{"action":"created","comment":{"url":"https://api.github.com/repos/c9s/CLIFramework/pulls/comments/30468820","id":30468820,"diff_hunk":"@@ -0,0 +1,202 @@\n+<?php\n+namespace CLIFramework\\Extension;\n+\n+use CLIFramework\\ServiceContainer;\n+use CLIFramework\\Command;\n+use CLIFramework\\Logger;\n+use CLIFramework\\Exception\\ExtensionException;\n+use CLIFramework\\IO\\StreamWriter;\n+\n+class DaemonExtension extends ExtensionBase\n+{\n+    private $config;\n+    private $logger;\n+    private $isNoClose = false;\n+    private $isNoChangeDirectory = false;\n+    private $command;\n+\n+    public function __construct()\n+    {\n+        $container = ServiceContainer::getInstance();\n+        $this->config = $container['config'];\n+    }\n+\n+    public static function isAvailable()\n+    {\n+        return function_exists('pcntl_fork');\n+    }\n+\n+    public function bind(Command $command)\n+    {\n+        $this->command = $command;\n+        $this->bindOptions($command);\n+        $this->bindHooks($command);\n+    }\n+\n+    public function run()\n+    {\n+        if (!$this->isAvailable()) {\n+            throw new ExtensionException(\"pcntl_fork() is not supported.\");\n+        }\n+\n+        $this->prepareLogger();\n+        $logger = $this->getLogger();\n+        $logger->debug('call hook: run.before');\n+        $this->callHook('run.before');\n+        $logger->debug('call daemonize()');\n+        $this->daemonize();\n+        $logger->debug('call hook: run.after');\n+        $this->callHook('run.after');\n+        $logger->debug('isNoClose = ' . var_export($this->isNoClose, true));\n+        $logger->debug('isNoChangeDirectory = ' . var_export($this->isNoChangeDirectory, true));\n+        $logger->debug('PidFilePath = ' . $this->getPidFilePath());\n+    }\n+\n+    public function noClose()\n+    {\n+        $this->isNoClose = true;\n+    }\n+\n+    public function noChangeDirectory()\n+    {\n+        $this->isNoChangeDirectory = true;\n+    }\n+\n+    public function getPidFilePath()\n+    {\n+        if ($this->getCommandOptions() && $this->getCommandOptions()->{'pid-file'}) {\n+            return $this->getCommandOptions()->{'pid-file'};\n+        }\n+        $pid = getmypid();\n+        $pidFile = $this->command ? $this->command->getName() : $pid;\n+        return $this->config->getPidDirectory() . \"/$pidFile.pid\";\n+    }\n+\n+    private function bindHooks($command)\n+    {\n+        $extension = $this;\n+        $command->addHook('execute.before', function() use ($extension) {\n+            $extension->run();\n+        });\n+        $command->addHook('execute.after', function() use ($extension) {\n+            @unlink($extension->getPidFilePath());\n+        });\n+    }\n+\n+    private function bindOptions($command)\n+    {\n+        $options = $command->getOptionCollection();\n+        if (!$options) {\n+            return;\n+        }\n+        $options->add('pid-file?', 'The path of pid file.');","path":"src/CLIFramework/Extension/DaemonExtension.php","position":92,"original_position":92,"commit_id":"97d2927b74e9396968f7460d934ca2dba5c31eea","original_commit_id":"97d2927b74e9396968f7460d934ca2dba5c31eea","user":{"login":"shinnya","id":227787,"avatar_url":"https://avatars.githubusercontent.com/u/227787?v=3","gravatar_id":"","url":"https://api.github.com/users/shinnya","html_url":"https://github.com/shinnya","followers_url":"https://api.github.com/users/shinnya/followers","following_url":"https://api.github.com/users/shinnya/following{/other_user}","gists_url":"https://api.github.com/users/shinnya/gists{/gist_id}","starred_url":"https://api.github.com/users/shinnya/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shinnya/subscriptions","organizations_url":"https://api.github.com/users/shinnya/orgs","repos_url":"https://api.github.com/users/shinnya/repos","events_url":"https://api.github.com/users/shinnya/events{/privacy}","received_events_url":"https://api.github.com/users/shinnya/received_events","type":"User","site_admin":false},"body":"Oh, I got it. I haven't understood `CommandBase` perfectly yet :dizzy_face: ","created_at":"2015-05-17T09:22:02Z","updated_at":"2015-05-17T09:22:02Z","html_url":"https://github.com/c9s/CLIFramework/pull/68#discussion_r30468820","pull_request_url":"https://api.github.com/repos/c9s/CLIFramework/pulls/68","_links":{"self":{"href":"https://api.github.com/repos/c9s/CLIFramework/pulls/comments/30468820"},"html":{"href":"https://github.com/c9s/CLIFramework/pull/68#discussion_r30468820"},"pull_request":{"href":"https://api.github.com/repos/c9s/CLIFramework/pulls/68"}}},"pull_request":{"url":"https://api.github.com/repos/c9s/CLIFramework/pulls/68","id":35581612,"html_url":"https://github.com/c9s/CLIFramework/pull/68","diff_url":"https://github.com/c9s/CLIFramework/pull/68.diff","patch_url":"https://github.com/c9s/CLIFramework/pull/68.patch","issue_url":"https://api.github.com/repos/c9s/CLIFramework/issues/68","number":68,"state":"open","locked":false,"title":"Add a new feature of built-in daemon command.","user":{"login":"shinnya","id":227787,"avatar_url":"https://avatars.githubusercontent.com/u/227787?v=3","gravatar_id":"","url":"https://api.github.com/users/shinnya","html_url":"https://github.com/shinnya","followers_url":"https://api.github.com/users/shinnya/followers","following_url":"https://api.github.com/users/shinnya/following{/other_user}","gists_url":"https://api.github.com/users/shinnya/gists{/gist_id}","starred_url":"https://api.github.com/users/shinnya/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shinnya/subscriptions","organizations_url":"https://api.github.com/users/shinnya/orgs","repos_url":"https://api.github.com/users/shinnya/repos","events_url":"https://api.github.com/users/shinnya/events{/privacy}","received_events_url":"https://api.github.com/users/shinnya/received_events","type":"User","site_admin":false},"body":"Ref: https://github.com/c9s/CLIFramework/issues/33\r\n\r\nI've implemented a built-in daemon command. The new `Extension` and hook system are described at the above issue.\r\n\r\n## How to try\r\nCheck my branch out and execute the following shell commands:\r\n\r\n```bash\r\n$ php example/demo --log-path=/tmp/server.log server --pid-file=/tmp/sample.pid 127.0.0.1 12345\r\n$ echo 'Hello, world!' | netcat 127.0.0.1 12345\r\n$ tail /tmp/server.log\r\n```\r\n`php example/demo server` launches an echo server, so that's ok if you can see 'Hello, world!' in the log file.\r\n\r\n## execution steps for ServerCommand and DaemonExtension\r\n1. ServerCommand::init()\r\n2. ServerCommand::enableExtension(new DaemonExtension())\r\n3. ServerCommand::_init()\r\n4. ServerCommand::initExtensions()\r\n5. DaemonExtension::bind($command)\r\n6. ServerCommand::executeWrappers()\r\n7. ServerCommand::callHook('execute.before')\r\n8. DaemonExtension::callHook('run.before')\r\n9. DaemonExtension::run()\r\n10. DaemonExtension::daemonize()\r\n11. DaemonExtension::callHook('run.after')\r\n12. ServerCommand::execute()\r\n13. ServerCommand::callHook('execute.after')\r\n\r\n## ChangeLogs\r\n* add `CLIFramework\\Hook` namespace and support hook system.\r\n* `CommandBase` and `ExtensionBase` implement `Hookable` interface.\r\n* support global `--log-path` option and daemon command outputs logs to the path if `--log-path` is given.\r\n* call `Logger::setVerbose` and `Logger::setDebug` on preparing `Application` if verbose and debug are set in cliframework.ini\r\n* add `Command::hasApplication` in order to confirm whether we can get application or not.","created_at":"2015-05-17T04:27:43Z","updated_at":"2015-05-17T09:22:02Z","closed_at":null,"merged_at":null,"merge_commit_sha":"ce21a902698617551113f169c702604096e27049","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/c9s/CLIFramework/pulls/68/commits","review_comments_url":"https://api.github.com/repos/c9s/CLIFramework/pulls/68/comments","review_comment_url":"https://api.github.com/repos/c9s/CLIFramework/pulls/comments{/number}","comments_url":"https://api.github.com/repos/c9s/CLIFramework/issues/68/comments","statuses_url":"https://api.github.com/repos/c9s/CLIFramework/statuses/97d2927b74e9396968f7460d934ca2dba5c31eea","head":{"label":"shinnya:feature/daemon","ref":"feature/daemon","sha":"97d2927b74e9396968f7460d934ca2dba5c31eea","user":{"login":"shinnya","id":227787,"avatar_url":"https://avatars.githubusercontent.com/u/227787?v=3","gravatar_id":"","url":"https://api.github.com/users/shinnya","html_url":"https://github.com/shinnya","followers_url":"https://api.github.com/users/shinnya/followers","following_url":"https://api.github.com/users/shinnya/following{/other_user}","gists_url":"https://api.github.com/users/shinnya/gists{/gist_id}","starred_url":"https://api.github.com/users/shinnya/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shinnya/subscriptions","organizations_url":"https://api.github.com/users/shinnya/orgs","repos_url":"https://api.github.com/users/shinnya/repos","events_url":"https://api.github.com/users/shinnya/events{/privacy}","received_events_url":"https://api.github.com/users/shinnya/received_events","type":"User","site_admin":false},"repo":{"id":35146498,"name":"CLIFramework","full_name":"shinnya/CLIFramework","owner":{"login":"shinnya","id":227787,"avatar_url":"https://avatars.githubusercontent.com/u/227787?v=3","gravatar_id":"","url":"https://api.github.com/users/shinnya","html_url":"https://github.com/shinnya","followers_url":"https://api.github.com/users/shinnya/followers","following_url":"https://api.github.com/users/shinnya/following{/other_user}","gists_url":"https://api.github.com/users/shinnya/gists{/gist_id}","starred_url":"https://api.github.com/users/shinnya/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shinnya/subscriptions","organizations_url":"https://api.github.com/users/shinnya/orgs","repos_url":"https://api.github.com/users/shinnya/repos","events_url":"https://api.github.com/users/shinnya/events{/privacy}","received_events_url":"https://api.github.com/users/shinnya/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/shinnya/CLIFramework","description":"A powerful command line application framework for PHP. It's an extensible, flexible component, You can build your command-based application in seconds!","fork":true,"url":"https://api.github.com/repos/shinnya/CLIFramework","forks_url":"https://api.github.com/repos/shinnya/CLIFramework/forks","keys_url":"https://api.github.com/repos/shinnya/CLIFramework/keys{/key_id}","collaborators_url":"https://api.github.com/repos/shinnya/CLIFramework/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/shinnya/CLIFramework/teams","hooks_url":"https://api.github.com/repos/shinnya/CLIFramework/hooks","issue_events_url":"https://api.github.com/repos/shinnya/CLIFramework/issues/events{/number}","events_url":"https://api.github.com/repos/shinnya/CLIFramework/events","assignees_url":"https://api.github.com/repos/shinnya/CLIFramework/assignees{/user}","branches_url":"https://api.github.com/repos/shinnya/CLIFramework/branches{/branch}","tags_url":"https://api.github.com/repos/shinnya/CLIFramework/tags","blobs_url":"https://api.github.com/repos/shinnya/CLIFramework/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/shinnya/CLIFramework/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/shinnya/CLIFramework/git/refs{/sha}","trees_url":"https://api.github.com/repos/shinnya/CLIFramework/git/trees{/sha}","statuses_url":"https://api.github.com/repos/shinnya/CLIFramework/statuses/{sha}","languages_url":"https://api.github.com/repos/shinnya/CLIFramework/languages","stargazers_url":"https://api.github.com/repos/shinnya/CLIFramework/stargazers","contributors_url":"https://api.github.com/repos/shinnya/CLIFramework/contributors","subscribers_url":"https://api.github.com/repos/shinnya/CLIFramework/subscribers","subscription_url":"https://api.github.com/repos/shinnya/CLIFramework/subscription","commits_url":"https://api.github.com/repos/shinnya/CLIFramework/commits{/sha}","git_commits_url":"https://api.github.com/repos/shinnya/CLIFramework/git/commits{/sha}","comments_url":"https://api.github.com/repos/shinnya/CLIFramework/comments{/number}","issue_comment_url":"https://api.github.com/repos/shinnya/CLIFramework/issues/comments{/number}","contents_url":"https://api.github.com/repos/shinnya/CLIFramework/contents/{+path}","compare_url":"https://api.github.com/repos/shinnya/CLIFramework/compare/{base}...{head}","merges_url":"https://api.github.com/repos/shinnya/CLIFramework/merges","archive_url":"https://api.github.com/repos/shinnya/CLIFramework/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/shinnya/CLIFramework/downloads","issues_url":"https://api.github.com/repos/shinnya/CLIFramework/issues{/number}","pulls_url":"https://api.github.com/repos/shinnya/CLIFramework/pulls{/number}","milestones_url":"https://api.github.com/repos/shinnya/CLIFramework/milestones{/number}","notifications_url":"https://api.github.com/repos/shinnya/CLIFramework/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/shinnya/CLIFramework/labels{/name}","releases_url":"https://api.github.com/repos/shinnya/CLIFramework/releases{/id}","created_at":"2015-05-06T07:57:54Z","updated_at":"2015-05-07T20:19:31Z","pushed_at":"2015-05-17T05:14:40Z","git_url":"git://github.com/shinnya/CLIFramework.git","ssh_url":"git@github.com:shinnya/CLIFramework.git","clone_url":"https://github.com/shinnya/CLIFramework.git","svn_url":"https://github.com/shinnya/CLIFramework","homepage":"","size":766,"stargazers_count":0,"watchers_count":0,"language":"PHP","has_issues":false,"has_downloads":true,"has_wiki":true,"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":"c9s:master","ref":"master","sha":"afbc3d83313fcc911223627e56f0613ae2b10b57","user":{"login":"c9s","id":50894,"avatar_url":"https://avatars.githubusercontent.com/u/50894?v=3","gravatar_id":"","url":"https://api.github.com/users/c9s","html_url":"https://github.com/c9s","followers_url":"https://api.github.com/users/c9s/followers","following_url":"https://api.github.com/users/c9s/following{/other_user}","gists_url":"https://api.github.com/users/c9s/gists{/gist_id}","starred_url":"https://api.github.com/users/c9s/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/c9s/subscriptions","organizations_url":"https://api.github.com/users/c9s/orgs","repos_url":"https://api.github.com/users/c9s/repos","events_url":"https://api.github.com/users/c9s/events{/privacy}","received_events_url":"https://api.github.com/users/c9s/received_events","type":"User","site_admin":false},"repo":{"id":2962174,"name":"CLIFramework","full_name":"c9s/CLIFramework","owner":{"login":"c9s","id":50894,"avatar_url":"https://avatars.githubusercontent.com/u/50894?v=3","gravatar_id":"","url":"https://api.github.com/users/c9s","html_url":"https://github.com/c9s","followers_url":"https://api.github.com/users/c9s/followers","following_url":"https://api.github.com/users/c9s/following{/other_user}","gists_url":"https://api.github.com/users/c9s/gists{/gist_id}","starred_url":"https://api.github.com/users/c9s/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/c9s/subscriptions","organizations_url":"https://api.github.com/users/c9s/orgs","repos_url":"https://api.github.com/users/c9s/repos","events_url":"https://api.github.com/users/c9s/events{/privacy}","received_events_url":"https://api.github.com/users/c9s/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/c9s/CLIFramework","description":"A powerful command line application framework for PHP. It's an extensible, flexible component, You can build your command-based application in seconds!","fork":false,"url":"https://api.github.com/repos/c9s/CLIFramework","forks_url":"https://api.github.com/repos/c9s/CLIFramework/forks","keys_url":"https://api.github.com/repos/c9s/CLIFramework/keys{/key_id}","collaborators_url":"https://api.github.com/repos/c9s/CLIFramework/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/c9s/CLIFramework/teams","hooks_url":"https://api.github.com/repos/c9s/CLIFramework/hooks","issue_events_url":"https://api.github.com/repos/c9s/CLIFramework/issues/events{/number}","events_url":"https://api.github.com/repos/c9s/CLIFramework/events","assignees_url":"https://api.github.com/repos/c9s/CLIFramework/assignees{/user}","branches_url":"https://api.github.com/repos/c9s/CLIFramework/branches{/branch}","tags_url":"https://api.github.com/repos/c9s/CLIFramework/tags","blobs_url":"https://api.github.com/repos/c9s/CLIFramework/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/c9s/CLIFramework/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/c9s/CLIFramework/git/refs{/sha}","trees_url":"https://api.github.com/repos/c9s/CLIFramework/git/trees{/sha}","statuses_url":"https://api.github.com/repos/c9s/CLIFramework/statuses/{sha}","languages_url":"https://api.github.com/repos/c9s/CLIFramework/languages","stargazers_url":"https://api.github.com/repos/c9s/CLIFramework/stargazers","contributors_url":"https://api.github.com/repos/c9s/CLIFramework/contributors","subscribers_url":"https://api.github.com/repos/c9s/CLIFramework/subscribers","subscription_url":"https://api.github.com/repos/c9s/CLIFramework/subscription","commits_url":"https://api.github.com/repos/c9s/CLIFramework/commits{/sha}","git_commits_url":"https://api.github.com/repos/c9s/CLIFramework/git/commits{/sha}","comments_url":"https://api.github.com/repos/c9s/CLIFramework/comments{/number}","issue_comment_url":"https://api.github.com/repos/c9s/CLIFramework/issues/comments{/number}","contents_url":"https://api.github.com/repos/c9s/CLIFramework/contents/{+path}","compare_url":"https://api.github.com/repos/c9s/CLIFramework/compare/{base}...{head}","merges_url":"https://api.github.com/repos/c9s/CLIFramework/merges","archive_url":"https://api.github.com/repos/c9s/CLIFramework/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/c9s/CLIFramework/downloads","issues_url":"https://api.github.com/repos/c9s/CLIFramework/issues{/number}","pulls_url":"https://api.github.com/repos/c9s/CLIFramework/pulls{/number}","milestones_url":"https://api.github.com/repos/c9s/CLIFramework/milestones{/number}","notifications_url":"https://api.github.com/repos/c9s/CLIFramework/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/c9s/CLIFramework/labels{/name}","releases_url":"https://api.github.com/repos/c9s/CLIFramework/releases{/id}","created_at":"2011-12-12T05:38:25Z","updated_at":"2015-05-15T13:14:09Z","pushed_at":"2015-05-17T05:14:40Z","git_url":"git://github.com/c9s/CLIFramework.git","ssh_url":"git@github.com:c9s/CLIFramework.git","clone_url":"https://github.com/c9s/CLIFramework.git","svn_url":"https://github.com/c9s/CLIFramework","homepage":"","size":2062,"stargazers_count":142,"watchers_count":142,"language":"PHP","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":19,"mirror_url":null,"open_issues_count":26,"forks":19,"open_issues":26,"watchers":142,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/c9s/CLIFramework/pulls/68"},"html":{"href":"https://github.com/c9s/CLIFramework/pull/68"},"issue":{"href":"https://api.github.com/repos/c9s/CLIFramework/issues/68"},"comments":{"href":"https://api.github.com/repos/c9s/CLIFramework/issues/68/comments"},"review_comments":{"href":"https://api.github.com/repos/c9s/CLIFramework/pulls/68/comments"},"review_comment":{"href":"https://api.github.com/repos/c9s/CLIFramework/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/c9s/CLIFramework/pulls/68/commits"},"statuses":{"href":"https://api.github.com/repos/c9s/CLIFramework/statuses/97d2927b74e9396968f7460d934ca2dba5c31eea"}}}}