{"action":"created","comment":{"url":"https://api.github.com/repos/svaarala/duktape/pulls/comments/53548666","id":53548666,"diff_hunk":"@@ -1773,6 +1811,161 @@ target endianness and interpret the bytecode based on that.\n .. note:: This command is somewhat incomplete at the moment and may be modified\n    once the best way to do this in the debugger UI has been figured out.\n \n+AppRequest request (0x22)\n+-------------------------\n+\n+Format::\n+\n+    REQ <int: 0x22> [<tval>*] EOM\n+    REP [<tval>*] EOM\n+\n+Example::\n+\n+    REQ 34 \"GameInfo\" \"GetTitle\" EOM\n+    REP \"Spectacles: Bruce's Story\" EOM\n+\n+This is a custom request message whose meaning and semantics depend on the\n+application.\n+\n+AppRequest messages are used for direct communication between the debug client\n+and debug target over the Duktape debug protocol.  Both the meaning of a custom\n+message and the dvalues it contains are entirely up to the implementation and\n+depending on the needs of the application, need not be supported at all.\n+\n+See \"Custom requests and notifications\" below for more details.\n+\n+Custom requests and notifications\n+=================================\n+\n+Starting in Duktape 1.5.x, Duktape supports direct communication between the\n+debug client and debug target over the same transport by using the special\n+AppRequest and AppNotify messages.  These messages have no meaning to Duktape,\n+which merely serves to marshal them back and forth through a defined API.\n+\n+AppNotify messages may be sent by pushing the contents of the message to the\n+stack and calling `duk_debugger_notify()` passing the number of values pushed.\n+Each value pushed will be sent as a dvalue in the message.  So if you push two\n+strings, \"foo\" and \"bar\", the client will see ``NFY 7 \"foo\" \"bar\" EOM``.\n+\n+AppRequest is used to make requests to the target which are not directly\n+related to Ecmascript execution and may be implementation-dependant.  For\n+example, an AppRequest might be used to:\n+\n+* Change the frame rate of a game engine\n+\n+* Reset/reboot an embedded target device while debugging\n+\n+* Perform or trigger software or script updates\n+\n+A target that wishes to support AppRequest should attach the debugger using the\n+``duk_debugger_attach_custom()`` API and provide a request callback.  When an\n+AppRequest is received, the request callback is invoked with the contents of\n+the message on the value stack, and may push its own values to be sent in\n+reply.\n+\n+This is a do-nothing request callback::\n+\n+    duk_idx_t duk_cb_debug_request(void* udata, duk_context* ctx, duk_idx_t nvalues) {\n+        /* nop */\n+        return 0;\n+    }\n+\n+The above callback simply responds with ``REP EOM`` (an empty reply) to all\n+requests.  This is admittedly not very useful and a real implementation should\n+process the values it receives on the stack, push its own values to send in\n+reply, and return a non-negative integer indicating how many values it pushed.\n+\n+Here is a slightly more useful implementation::\n+\n+    duk_idx_t duk_cb_debug_request(void* udata, duk_context* ctx, duk_idx_t nvalues) {\n+        /* Must use negative stack indices to access dvalues */\n+        const char* cmdname = duk_get_string(ctx, -nvalues + 0);\n+        \n+        if (strcmp(cmdname, \"VersionInfo\") == 0) {\n+            /* Return a positive integer to send a REP containing values pushed\n+             * to the stack. The return value indicates how many dvalues you\n+             * are including in the response.\n+             */\n+            \n+            duk_push_string(ctx, \"My Awesome Program\");\n+            duk_push_int(ctx, 81200);  /* ver. 8.12.0 */\n+            \n+            return 2;  /* 2 dvalues */\n+        } else {\n+            /* Return -1 to send an ERR reply. The value on top of the stack\n+             * will be string coerced and used for the error text.\n+             */\n+            \n+            duk_push_string(ctx, \"unrecognized AppRequest command name\");\n+            return -1;\n+        }\n+    }\n+\n+If no request callback is provided at attach, AppRequest will be treated as an\n+unsupported command, eliciting an ERR reply from Duktape saying so.  Such a\n+target is still free to send AppNotify messages, however.\n+\n+As a precaution, the target should try to avoid sending structured values such\n+as JS objects in notify messages as their heap pointers may become stale by the\n+time the client receives them.  This is especially true for notifications sent\n+while the target is running.  It's better to stick to primitives which have\n+unique dvalue representations, i.e. numbers, strings and buffers.  If a\n+structured value does need to be sent, it can simply be, e.g. JSON/JX encoded\n+and sent as a string instead.\n+\n+Important notes on the request callback\n+---------------------------------------\n+\n+The request callback is provided with a ``duk_context`` pointer with which it\n+can access the value stack and is assumed to be trusted.  Specifically, there\n+are certain things it **MUST NOT** do.  Specifically:\n+\n+* It MUST NOT attempt to access or pop any values from the top of the stack\n+  beyond the ``nvalues`` it is given.\n+\n+* It MUST NOT assume any specific value for ``duk_get_top()`` and similar\n+  primitives.  In practice this means using negative stack indices to access\n+  values.\n+\n+* It MUST NOT throw errors.  It is very easy to accidentally throw an error\n+  when working with value stack values directly, so caution must be exercised\n+  here.","path":"doc/debugger.rst","position":203,"original_position":203,"commit_id":"313e8a1d3ce8808d6918f6390ba47625cf7a2496","original_commit_id":"313e8a1d3ce8808d6918f6390ba47625cf7a2496","user":{"login":"svaarala","id":6377415,"avatar_url":"https://avatars.githubusercontent.com/u/6377415?v=3","gravatar_id":"","url":"https://api.github.com/users/svaarala","html_url":"https://github.com/svaarala","followers_url":"https://api.github.com/users/svaarala/followers","following_url":"https://api.github.com/users/svaarala/following{/other_user}","gists_url":"https://api.github.com/users/svaarala/gists{/gist_id}","starred_url":"https://api.github.com/users/svaarala/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/svaarala/subscriptions","organizations_url":"https://api.github.com/users/svaarala/orgs","repos_url":"https://api.github.com/users/svaarala/repos","events_url":"https://api.github.com/users/svaarala/events{/privacy}","received_events_url":"https://api.github.com/users/svaarala/received_events","type":"User","site_admin":false},"body":"Maybe add:\r\n\r\n* ... must be exercised here. (Allowing callback errors will be added in future work.)\r\n\r\nor something similar. It's an obvious issue to fix.","created_at":"2016-02-20T10:52:38Z","updated_at":"2016-02-20T10:52:38Z","html_url":"https://github.com/svaarala/duktape/pull/596#discussion_r53548666","pull_request_url":"https://api.github.com/repos/svaarala/duktape/pulls/596","_links":{"self":{"href":"https://api.github.com/repos/svaarala/duktape/pulls/comments/53548666"},"html":{"href":"https://github.com/svaarala/duktape/pull/596#discussion_r53548666"},"pull_request":{"href":"https://api.github.com/repos/svaarala/duktape/pulls/596"}}},"pull_request":{"url":"https://api.github.com/repos/svaarala/duktape/pulls/596","id":59702943,"html_url":"https://github.com/svaarala/duktape/pull/596","diff_url":"https://github.com/svaarala/duktape/pull/596.diff","patch_url":"https://github.com/svaarala/duktape/pull/596.patch","issue_url":"https://api.github.com/repos/svaarala/duktape/issues/596","number":596,"state":"open","locked":false,"title":"Implement application-defined debugger command support","user":{"login":"fatcerberus","id":4097841,"avatar_url":"https://avatars.githubusercontent.com/u/4097841?v=3","gravatar_id":"","url":"https://api.github.com/users/fatcerberus","html_url":"https://github.com/fatcerberus","followers_url":"https://api.github.com/users/fatcerberus/followers","following_url":"https://api.github.com/users/fatcerberus/following{/other_user}","gists_url":"https://api.github.com/users/fatcerberus/gists{/gist_id}","starred_url":"https://api.github.com/users/fatcerberus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fatcerberus/subscriptions","organizations_url":"https://api.github.com/users/fatcerberus/orgs","repos_url":"https://api.github.com/users/fatcerberus/repos","events_url":"https://api.github.com/users/fatcerberus/events{/privacy}","received_events_url":"https://api.github.com/users/fatcerberus/received_events","type":"User","site_admin":false},"body":"This adds application-defined message support to the debug protocol. When Duktape receives a request message beginning `REQ 0xff`, it pushes all the remaining dvalues in the message to the valstack and calls `heap->dbg_appcustom_cb`.  The callback can push it own values to the stack, and these are sent back to the client as a REP.\r\n\r\nIt is also possible for the target to send application-specific notifys to the client by calling `duk_debugger_notify()`.\r\n\r\nThis currently represents a breaking API change because it adds an additional callback argument to duk_debugger_attach().  If possible, it would be better to implement this in a way that didn't break the existing API guarantees.\r\n\r\nThis branch is just a prototype right now for the purpose of having something concrete to discuss.  It still needs documentation, and is somewhat messy.  However, initial testing indicates the functionality itself is working as designed.","created_at":"2016-02-17T20:22:38Z","updated_at":"2016-02-20T10:52:38Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f8788adddc0fed6e11817d2aea1257eb1b839ef4","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/svaarala/duktape/pulls/596/commits","review_comments_url":"https://api.github.com/repos/svaarala/duktape/pulls/596/comments","review_comment_url":"https://api.github.com/repos/svaarala/duktape/pulls/comments{/number}","comments_url":"https://api.github.com/repos/svaarala/duktape/issues/596/comments","statuses_url":"https://api.github.com/repos/svaarala/duktape/statuses/313e8a1d3ce8808d6918f6390ba47625cf7a2496","head":{"label":"fatcerberus:debugger-custom-commands","ref":"debugger-custom-commands","sha":"313e8a1d3ce8808d6918f6390ba47625cf7a2496","user":{"login":"fatcerberus","id":4097841,"avatar_url":"https://avatars.githubusercontent.com/u/4097841?v=3","gravatar_id":"","url":"https://api.github.com/users/fatcerberus","html_url":"https://github.com/fatcerberus","followers_url":"https://api.github.com/users/fatcerberus/followers","following_url":"https://api.github.com/users/fatcerberus/following{/other_user}","gists_url":"https://api.github.com/users/fatcerberus/gists{/gist_id}","starred_url":"https://api.github.com/users/fatcerberus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fatcerberus/subscriptions","organizations_url":"https://api.github.com/users/fatcerberus/orgs","repos_url":"https://api.github.com/users/fatcerberus/repos","events_url":"https://api.github.com/users/fatcerberus/events{/privacy}","received_events_url":"https://api.github.com/users/fatcerberus/received_events","type":"User","site_admin":false},"repo":{"id":35036428,"name":"duktape","full_name":"fatcerberus/duktape","owner":{"login":"fatcerberus","id":4097841,"avatar_url":"https://avatars.githubusercontent.com/u/4097841?v=3","gravatar_id":"","url":"https://api.github.com/users/fatcerberus","html_url":"https://github.com/fatcerberus","followers_url":"https://api.github.com/users/fatcerberus/followers","following_url":"https://api.github.com/users/fatcerberus/following{/other_user}","gists_url":"https://api.github.com/users/fatcerberus/gists{/gist_id}","starred_url":"https://api.github.com/users/fatcerberus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fatcerberus/subscriptions","organizations_url":"https://api.github.com/users/fatcerberus/orgs","repos_url":"https://api.github.com/users/fatcerberus/repos","events_url":"https://api.github.com/users/fatcerberus/events{/privacy}","received_events_url":"https://api.github.com/users/fatcerberus/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/fatcerberus/duktape","description":"Duktape - embeddable Javascript engine with a focus on portability and compact footprint","fork":true,"url":"https://api.github.com/repos/fatcerberus/duktape","forks_url":"https://api.github.com/repos/fatcerberus/duktape/forks","keys_url":"https://api.github.com/repos/fatcerberus/duktape/keys{/key_id}","collaborators_url":"https://api.github.com/repos/fatcerberus/duktape/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/fatcerberus/duktape/teams","hooks_url":"https://api.github.com/repos/fatcerberus/duktape/hooks","issue_events_url":"https://api.github.com/repos/fatcerberus/duktape/issues/events{/number}","events_url":"https://api.github.com/repos/fatcerberus/duktape/events","assignees_url":"https://api.github.com/repos/fatcerberus/duktape/assignees{/user}","branches_url":"https://api.github.com/repos/fatcerberus/duktape/branches{/branch}","tags_url":"https://api.github.com/repos/fatcerberus/duktape/tags","blobs_url":"https://api.github.com/repos/fatcerberus/duktape/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/fatcerberus/duktape/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/fatcerberus/duktape/git/refs{/sha}","trees_url":"https://api.github.com/repos/fatcerberus/duktape/git/trees{/sha}","statuses_url":"https://api.github.com/repos/fatcerberus/duktape/statuses/{sha}","languages_url":"https://api.github.com/repos/fatcerberus/duktape/languages","stargazers_url":"https://api.github.com/repos/fatcerberus/duktape/stargazers","contributors_url":"https://api.github.com/repos/fatcerberus/duktape/contributors","subscribers_url":"https://api.github.com/repos/fatcerberus/duktape/subscribers","subscription_url":"https://api.github.com/repos/fatcerberus/duktape/subscription","commits_url":"https://api.github.com/repos/fatcerberus/duktape/commits{/sha}","git_commits_url":"https://api.github.com/repos/fatcerberus/duktape/git/commits{/sha}","comments_url":"https://api.github.com/repos/fatcerberus/duktape/comments{/number}","issue_comment_url":"https://api.github.com/repos/fatcerberus/duktape/issues/comments{/number}","contents_url":"https://api.github.com/repos/fatcerberus/duktape/contents/{+path}","compare_url":"https://api.github.com/repos/fatcerberus/duktape/compare/{base}...{head}","merges_url":"https://api.github.com/repos/fatcerberus/duktape/merges","archive_url":"https://api.github.com/repos/fatcerberus/duktape/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/fatcerberus/duktape/downloads","issues_url":"https://api.github.com/repos/fatcerberus/duktape/issues{/number}","pulls_url":"https://api.github.com/repos/fatcerberus/duktape/pulls{/number}","milestones_url":"https://api.github.com/repos/fatcerberus/duktape/milestones{/number}","notifications_url":"https://api.github.com/repos/fatcerberus/duktape/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/fatcerberus/duktape/labels{/name}","releases_url":"https://api.github.com/repos/fatcerberus/duktape/releases{/id}","deployments_url":"https://api.github.com/repos/fatcerberus/duktape/deployments","created_at":"2015-05-04T13:30:42Z","updated_at":"2016-01-11T04:56:49Z","pushed_at":"2016-02-20T06:08:50Z","git_url":"git://github.com/fatcerberus/duktape.git","ssh_url":"git@github.com:fatcerberus/duktape.git","clone_url":"https://github.com/fatcerberus/duktape.git","svn_url":"https://github.com/fatcerberus/duktape","homepage":null,"size":59181,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"svaarala:master","ref":"master","sha":"be2051fd251fad0101eca357320b2803f5cb135e","user":{"login":"svaarala","id":6377415,"avatar_url":"https://avatars.githubusercontent.com/u/6377415?v=3","gravatar_id":"","url":"https://api.github.com/users/svaarala","html_url":"https://github.com/svaarala","followers_url":"https://api.github.com/users/svaarala/followers","following_url":"https://api.github.com/users/svaarala/following{/other_user}","gists_url":"https://api.github.com/users/svaarala/gists{/gist_id}","starred_url":"https://api.github.com/users/svaarala/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/svaarala/subscriptions","organizations_url":"https://api.github.com/users/svaarala/orgs","repos_url":"https://api.github.com/users/svaarala/repos","events_url":"https://api.github.com/users/svaarala/events{/privacy}","received_events_url":"https://api.github.com/users/svaarala/received_events","type":"User","site_admin":false},"repo":{"id":15852088,"name":"duktape","full_name":"svaarala/duktape","owner":{"login":"svaarala","id":6377415,"avatar_url":"https://avatars.githubusercontent.com/u/6377415?v=3","gravatar_id":"","url":"https://api.github.com/users/svaarala","html_url":"https://github.com/svaarala","followers_url":"https://api.github.com/users/svaarala/followers","following_url":"https://api.github.com/users/svaarala/following{/other_user}","gists_url":"https://api.github.com/users/svaarala/gists{/gist_id}","starred_url":"https://api.github.com/users/svaarala/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/svaarala/subscriptions","organizations_url":"https://api.github.com/users/svaarala/orgs","repos_url":"https://api.github.com/users/svaarala/repos","events_url":"https://api.github.com/users/svaarala/events{/privacy}","received_events_url":"https://api.github.com/users/svaarala/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/svaarala/duktape","description":"Duktape - embeddable Javascript engine with a focus on portability and compact footprint","fork":false,"url":"https://api.github.com/repos/svaarala/duktape","forks_url":"https://api.github.com/repos/svaarala/duktape/forks","keys_url":"https://api.github.com/repos/svaarala/duktape/keys{/key_id}","collaborators_url":"https://api.github.com/repos/svaarala/duktape/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/svaarala/duktape/teams","hooks_url":"https://api.github.com/repos/svaarala/duktape/hooks","issue_events_url":"https://api.github.com/repos/svaarala/duktape/issues/events{/number}","events_url":"https://api.github.com/repos/svaarala/duktape/events","assignees_url":"https://api.github.com/repos/svaarala/duktape/assignees{/user}","branches_url":"https://api.github.com/repos/svaarala/duktape/branches{/branch}","tags_url":"https://api.github.com/repos/svaarala/duktape/tags","blobs_url":"https://api.github.com/repos/svaarala/duktape/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/svaarala/duktape/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/svaarala/duktape/git/refs{/sha}","trees_url":"https://api.github.com/repos/svaarala/duktape/git/trees{/sha}","statuses_url":"https://api.github.com/repos/svaarala/duktape/statuses/{sha}","languages_url":"https://api.github.com/repos/svaarala/duktape/languages","stargazers_url":"https://api.github.com/repos/svaarala/duktape/stargazers","contributors_url":"https://api.github.com/repos/svaarala/duktape/contributors","subscribers_url":"https://api.github.com/repos/svaarala/duktape/subscribers","subscription_url":"https://api.github.com/repos/svaarala/duktape/subscription","commits_url":"https://api.github.com/repos/svaarala/duktape/commits{/sha}","git_commits_url":"https://api.github.com/repos/svaarala/duktape/git/commits{/sha}","comments_url":"https://api.github.com/repos/svaarala/duktape/comments{/number}","issue_comment_url":"https://api.github.com/repos/svaarala/duktape/issues/comments{/number}","contents_url":"https://api.github.com/repos/svaarala/duktape/contents/{+path}","compare_url":"https://api.github.com/repos/svaarala/duktape/compare/{base}...{head}","merges_url":"https://api.github.com/repos/svaarala/duktape/merges","archive_url":"https://api.github.com/repos/svaarala/duktape/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/svaarala/duktape/downloads","issues_url":"https://api.github.com/repos/svaarala/duktape/issues{/number}","pulls_url":"https://api.github.com/repos/svaarala/duktape/pulls{/number}","milestones_url":"https://api.github.com/repos/svaarala/duktape/milestones{/number}","notifications_url":"https://api.github.com/repos/svaarala/duktape/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/svaarala/duktape/labels{/name}","releases_url":"https://api.github.com/repos/svaarala/duktape/releases{/id}","deployments_url":"https://api.github.com/repos/svaarala/duktape/deployments","created_at":"2014-01-12T22:16:14Z","updated_at":"2016-02-19T12:38:40Z","pushed_at":"2016-02-20T06:08:50Z","git_url":"git://github.com/svaarala/duktape.git","ssh_url":"git@github.com:svaarala/duktape.git","clone_url":"https://github.com/svaarala/duktape.git","svn_url":"https://github.com/svaarala/duktape","homepage":null,"size":70806,"stargazers_count":2033,"watchers_count":2033,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":188,"mirror_url":null,"open_issues_count":178,"forks":188,"open_issues":178,"watchers":2033,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/svaarala/duktape/pulls/596"},"html":{"href":"https://github.com/svaarala/duktape/pull/596"},"issue":{"href":"https://api.github.com/repos/svaarala/duktape/issues/596"},"comments":{"href":"https://api.github.com/repos/svaarala/duktape/issues/596/comments"},"review_comments":{"href":"https://api.github.com/repos/svaarala/duktape/pulls/596/comments"},"review_comment":{"href":"https://api.github.com/repos/svaarala/duktape/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/svaarala/duktape/pulls/596/commits"},"statuses":{"href":"https://api.github.com/repos/svaarala/duktape/statuses/313e8a1d3ce8808d6918f6390ba47625cf7a2496"}}}}