/** * Called when the worker is ready to go. * @return void */ public function onReady() { $appInstance = $this; // a reference to this application instance for ExampleWebSocketRoute \PHPDaemon\Servers\WebSocket\Pool::getInstance()->addRoute('ExamplePubSub', function ($client) use($appInstance) { return new ExamplePubSubWebSocketRoute($client, $appInstance); }); $this->sql = \PHPDaemon\Clients\MySQL\Pool::getInstance(); $this->pubsub = new \PHPDaemon\PubSub\PubSub(); $this->pubsub->addEvent('usersNum', \PHPDaemon\PubSub\PubSubEvent::init()->onActivation(function ($pubsub) use($appInstance) { \PHPDaemon\Core\Daemon::log('onActivation'); if (isset($pubsub->event)) { \PHPDaemon\Core\Timer::setTimeout($pubsub->event, 0); return; } $pubsub->event = setTimeout(function ($timer) use($pubsub, $appInstance) { $appInstance->sql->getConnection(function ($sql) use($pubsub) { if (!$sql->connected) { return; } $sql->query('SELECT COUNT(*) `num` FROM `dle_users`', function ($sql, $success) use($pubsub) { $pubsub->pub(sizeof($sql->resultRows) ? $sql->resultRows[0]['num'] : 'null'); }); }); $timer->timeout(5000000.0); // 5 seconds }, 0); })->onDeactivation(function ($pubsub) { if (isset($pubsub->event)) { \PHPDaemon\Core\Timer::cancelTimeout($pubsub->event); } })); }
protected function prepareAsync() { EventLoop::init(); Daemon::initSettings(); FileSystem::init(); FileSystem::initEvent(); }
/** * Called when socket is bound * @return boolean Success */ protected function onBound() { touch($this->path); chmod($this->path, 0770); if ($this->group === null && !empty($this->uri['pass'])) { $this->group = $this->uri['pass']; } if ($this->group === null && isset(Daemon::$config->group->value)) { $this->group = Daemon::$config->group->value; } if ($this->group !== null) { if (!@chgrp($this->path, $this->group)) { unlink($this->path); Daemon::log('Couldn\'t change group of the socket \'' . $this->path . '\' to \'' . $this->group . '\'.'); return false; } } if ($this->user === null && !empty($this->uri['user'])) { $this->user = $this->uri['user']; } if ($this->user === null && isset(Daemon::$config->user->value)) { $this->user = Daemon::$config->user->value; } if ($this->user !== null) { if (!@chown($this->path, $this->user)) { unlink($this->path); Daemon::log('Couldn\'t change owner of the socket \'' . $this->path . '\' to \'' . $this->user . '\'.'); return false; } } return true; }
public function run() { $this->proxy = $this->orm->appInstance->proxy; $this->params = $this['args'][0]; try { $this->orm->appInstance->httpclient->post('https://account.fineproxy.org/proxy/download/http_auth/txt/', ['log' => $this->params['username'], 'pass' => $this->params['password'], 'logsub' => 'Войти'], function ($conn) { $proxies = []; foreach (explode("\n", $conn->body) as $addr) { $addr = trim($addr); if (!preg_match('~^\\d+\\.\\d+\\.\\d+\\.\\d+:\\d+$~', $addr)) { continue; } $proxies[] = ['type' => 'http', 'addr' => $addr, 'auth' => ['username' => $this->params['username'], 'password' => $this->params['password']]]; } $source = 'Fineproxy-' . $this->params['username']; $itime = time(); $j = (new ComplexJob(function ($j) use($source, $itime) { $this->sendResult(true); $this->proxy->removeProxyServer(['source' => $source, 'itime' => ['$lt' => $itime]]); Daemon::log('complete'); }))->maxConcurrency(5)->more(function () use(&$proxies, $source, $itime) { foreach ($proxies as $k => $proxy) { (yield 'proxy_' . $k => function ($jobname, $j) use($proxy, $itime) { $this->proxy->newProxyServer($proxy)->setOnInsertMode(false)->attr(['itime' => $itime])->save(function ($o) use($jobname, $j) { $j->setResult($jobname, $o->lastError()); }); }); } }); $j(); }); } catch (Exception $e) { $this->sendResult(false); } }
public function perform() { $hash = Request::getString($_REQUEST['x']); if (!strlen($hash) || base64_decode($hash, true) === false) { $this->req->setResult(['success' => false, 'error' => 'Wrong format of extTokenHash']); return; } $this->appInstance->externalAuthTokens->findByExtTokenHash($hash, function ($result) use($hash) { if ($result) { $this->req->setResult(['success' => false, 'error' => 'This token was already used.']); return; } $ip = $this->req->getIp(); $intToken = Crypt::hash(Daemon::uniqid() . "" . $ip . "" . Crypt::randomString()); $this->appInstance->externalAuthTokens->save(['extTokenHash' => $hash, 'intToken' => $intToken, 'ip' => $ip, 'useragent' => Request::getString($_SERVER['HTTP_USER_AGENT']), 'ctime' => microtime(true), 'status' => 'new'], function ($lastError) use($intToken) { if (!isset($lastError['n']) || $lastError['n'] === 0) { $this->req->setResult(['success' => false, 'errors' => ['code' => 'Sorry, internal error.']]); return; } $type = Request::getString($_REQUEST['type']); if ($type === 'email') { // send email.... } elseif ($type === 'redirect') { $this->req->redirectTo(HTTPClient::buildUrl(['/' . $this->req->locale . '/account/extauth', 'i' => $intToken]), false); } $this->req->setResult(['success' => true, 'intToken' => $intToken]); }); }); }
/** * Called when the request starts sleep * @return void */ public function onSleep() { Daemon::$context = null; $this->running = false; unset($_SESSION, $_GET, $_POST, $_COOKIE); Daemon::$process->setState(Daemon::WSTATE_IDLE); }
/** * @TODO DESCR * @return void */ public function onReady() { if ($this->user === null) { $this->connected = true; } if ($this->connected) { parent::onReady(); return; } $this->dbname = $this->path; $this->pool->getNonce(['dbname' => $this->dbname], function ($result) { if (isset($result['$err'])) { Daemon::log('MongoClient: getNonce() error with ' . $this->url . ': ' . $result['$err']); $this->finish(); } $this->pool->auth(['user' => $this->user, 'password' => $this->password, 'nonce' => $result['nonce'], 'dbname' => $this->dbname], function ($result) { if (!isset($result['ok']) || !$result['ok']) { Daemon::log('MongoClient: authentication error with ' . $this->url . ': ' . $result['errmsg']); $this->finish(); return; } $this->connected = true; $this->onReady(); }, $this); }, $this); }
/** * Bind given socket * @param string $uri Address to bind * @return boolean Success */ public function bindSocket($uri) { $u = \PHPDaemon\Config\Object::parseCfgUri($uri); $scheme = $u['scheme']; if ($scheme === 'unix') { $socket = new \PHPDaemon\BoundSocket\UNIX($u); } elseif ($scheme === 'udp') { $socket = new \PHPDaemon\BoundSocket\UDP($u); if (isset($this->config->port->value)) { $socket->setDefaultPort($this->config->port->value); } } elseif ($scheme === 'tcp') { $socket = new \PHPDaemon\BoundSocket\TCP($u); if (isset($this->config->port->value)) { $socket->setDefaultPort($this->config->port->value); } } else { Daemon::log(get_class($this) . ': enable to bind \'' . $uri . '\': scheme \'' . $scheme . '\' is not supported'); return false; } $socket->attachTo($this); if ($socket->bindSocket()) { if ($this->enabled) { $socket->enable(); } return true; } return false; }
public function init() { if ($this->config->enable->value) { Daemon::log(__CLASS__ . ' up.'); $this->db = \PHPDaemon\Clients\Mongo\Pool::getInstance(); $this->tags = array(); $this->minMsgInterval = 1; } }
/** * @param string $name * @return bool */ public function __get($name) { $class = '\\WakePHP\\Components\\' . $name; if (!class_exists($class)) { Daemon::log(get_class($this) . ': undefined class: ' . $class); return false; } return $this->{$name} = new $class($this->req); }
public function setPassword($value) { if (($r = static::checkPasswordFormat($value)) !== true) { throw new \Exception($r); } $this->setProperty('salt', $salt = $this->appInstance->config->cryptsalt->value . Crypt::hash(Daemon::uniqid() . "" . $this['email'])); $this->setProperty('password', Crypt::hash($value, $salt . $this->appInstance->config->cryptsaltextra->value)); return $this; }
public function getObject($type, $cond = null, $objOrCb = null) { $class = ClassFinder::find($type, $this->name, $this->ns); if (!class_exists($class)) { Daemon::log(get_class($this) . ': undefined class: ' . $class); return false; } return new $class($cond, $objOrCb, $this); }
/** * Called when timer is triggered * @return void */ public function eventCall() { try { //Daemon::log('cb - '.Debug::zdump($this->cb)); call_user_func($this->cb, $this); } catch (\Exception $e) { Daemon::uncaughtExceptionHandler($e); } }
/** * Called when new frame received. * @param string Frame's contents. * @param integer Frame's type. * @return void */ public function onFrame($data, $type) { if ($data === 'ping') { $this->client->sendFrame('pong', 'STRING', function ($client) { // optional. called when the frame is transmitted to the client \PHPDaemon\Core\Daemon::log('ExampleWebSocket: \'pong\' received by client.'); }); } }
/** * Called when the worker is ready to go * * @return void */ public function onReady() { // Adding listener // ComplexJob - STATE_WAITING $job = new \PHPDaemon\Core\ComplexJob(function ($job) { // ComplexJob - STATE_DONE /*array ( 'bar' => array ( 'job' => 'bar', 'success' => false, 'line' => 63, ), 'foo' => array ( 'job' => 'foo', 'success' => true, 'line' => 84, 'arg' => array ( 'param' => 'value', ), ), 'baz' => array ( 'job' => 'baz', 'success' => false, 'line' => 94, ), )*/ \PHPDaemon\Core\Daemon::log($job->results); }); // Adding listener // ComplexJob - STATE_WAITING $job->addListener(function ($job) { // ComplexJob - STATE_DONE }); // Adding async job foo $job('foo', $this->foo(['param' => 'value'])); // Adding with 1 sec delay \PHPDaemon\Core\Timer::add(function ($event) use($job) { // Adding async job bar $job('bar', function ($jobname, $job) { \PHPDaemon\Core\Timer::add(function ($event) use($jobname, $job) { // Job done $job->setResult($jobname, ['job' => 'bar', 'success' => false, 'line' => __LINE__]); $event->finish(); }, 1000.0 * 50); }); // Adding async job baz. Equal $job('baz', $this->baz()); $job->addJob('baz', $this->baz()); // Run jobs. All listeners will be called when the jobs done // ComplexJob - STATE_RUNNING $job(); $event->finish(); }, 1000000.0 * 1); }
/** * Called when the worker is ready to go. * @return void */ public function onReady() { $_ws = \PHPDaemon\Servers\WebSocket\Pool::getInstance(); $_ws->addRoute('/sockjs', function ($client) { Daemon::log('call route at WebSocket Server'); //Daemon::log($client); return new \SockJsAppRoute($client, $this); }); $this->log('onReady at SockJsApp'); }
/** * Adds a route if it doesn't exist already. * @param string $path Route name. * @param callable $cb Route's callback. * @callback $cb ( ) * @return boolean Success. */ public function addRoute($path, $cb) { $routeName = ltrim($path, '/'); if (isset($this->routes[$routeName])) { Daemon::log(__METHOD__ . ': Route \'' . $path . '\' is already defined.'); return false; } $this->routes[$routeName] = $cb; return true; }
/** * Returns a proxy callback function with logging for debugging purposes * @param callable $cb Callback * @param mixed $name Data * @return callable */ public static function proxy($cb, $name = null) { static $i = 0; $n = ++$i; Daemon::log('Debug::proxy #' . $n . ': SPAWNED (' . json_encode($name) . ')'); return function () use($cb, $name, $n) { Daemon::log('Debug::proxy #' . $n . ': CALLED (' . json_encode($name) . ')'); call_user_func_array($cb, func_get_args()); }; }
public function onHandshake() { $this->defineLocalMethods(['serverTest' => function () { $this->callRemote('clientTest', 'foobar', function () { Daemon::log('callback called'); }); }]); $this->onFrame('{"method":"methods","arguments":[{"clientTest":{}}],"callbacks":{"1":[0,"clientTest"]},"links":[]} ', 'STRING'); parent::onHandshake(); }
/** * Called when new frame received. * @param string Frame's contents. * @param integer Frame's type. * @return void */ public function onFrame($data, $type) { D($data); Daemon::log('SockJsAppRoute'); Daemon::log($data); if ($data === 'ping') { $this->client->sendFrame('pong'); } else { $this->client->sendFrame($data); } }
public function redirect() { if (!$this->checkReferer($this->appInstance->config->domain->value)) { $this->req->setResult(['error' => 'Wrong referer']); return; } $code = Request::getString($_GET['code']); if ($code === '') { Daemon::log('Authentication failed'); $this->req->status(401); $this->req->setResult(['error' => 'Authenticaion failed']); return; } $this->appInstance->httpclient->get(['https://graph.facebook.com/oauth/access_token', 'client_id' => $this->cmp->config->facebook_app_key->value, 'redirect_uri' => $this->req->getBaseUrl() . $_SERVER['REQUEST_URI'], 'client_secret' => $this->cmp->config->facebook_app_secret->value, 'code' => $code], function ($conn, $success) { if (!$success) { $this->req->status(400); $this->req->setResult(['error' => 'request declined']); return; } parse_str($conn->body, $response); if (!isset($response['access_token'])) { $json_response = json_decode($conn->body, true); $err_message = 'no access_token'; if (isset($json_response['error']['message'])) { $err_message = $json_response['error']['message']; } $this->req->status(403); $this->req->setResult(['error' => $err_message]); return; } $this->appInstance->httpclient->get(['https://graph.facebook.com/me', 'fields' => 'id,name,email', 'format' => 'json', 'access_token' => $response['access_token']], function ($conn, $success) { $response = json_decode($conn->body, true); $id = Request::getString($response['id']); if (!$success || !is_array($response) || empty($id)) { $this->req->redirectTo('/'); return; } $data = []; if (isset($response['name'])) { $data['username'] = Request::getString($response['name']); } if (isset($response['email'])) { $data['email'] = Request::getString($response['email']); } if (isset($_REQUEST['external_token'])) { $data['external_token'] = Request::getString($_REQUEST['external_token']); } $this->req->components->account->acceptUserAuthentication('facebook', $id, $data, function () { $this->finalRedirect(); }); }); }); }
/** * Bind the socket * @return null|boolean Success. */ public function bindSocket() { if ($this->erroneous) { return false; } $port = $this->getPort(); if (!is_int($port)) { Daemon::log(get_class($this) . ' (' . get_class($this->pool) . '): no port defined for \'' . $this->uri['uri'] . '\''); return; } if ($port < 1024 && Daemon::$config->user->value !== 'root') { $this->listenerMode = false; } if ($this->listenerMode) { $this->setFd($this->host . ':' . $port); return true; } $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if (!$sock) { $errno = socket_last_error(); Daemon::$process->log(get_class($this->pool) . ': Couldn\'t create TCP-socket (' . $errno . ' - ' . socket_strerror($errno) . ').'); return false; } if ($this->reuse) { if (!socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1)) { $errno = socket_last_error(); Daemon::$process->log(get_class($this->pool) . ': Couldn\'t set option REUSEADDR to socket (' . $errno . ' - ' . socket_strerror($errno) . ').'); return false; } if (defined('SO_REUSEPORT') && !@socket_set_option($sock, SOL_SOCKET, SO_REUSEPORT, 1)) { $errno = socket_last_error(); Daemon::$process->log(get_class($this->pool) . ': Couldn\'t set option REUSEPORT to socket (' . $errno . ' - ' . socket_strerror($errno) . ').'); return false; } } if (!@socket_bind($sock, $this->host, $port)) { $errno = socket_last_error(); Daemon::$process->log(get_class($this->pool) . ': Couldn\'t bind TCP-socket \'' . $this->host . ':' . $port . '\' (' . $errno . ' - ' . socket_strerror($errno) . ').'); return false; } socket_getsockname($sock, $this->host, $this->port); socket_set_nonblock($sock); if (!$this->listenerMode) { if (!socket_listen($sock, SOMAXCONN)) { $errno = socket_last_error(); Daemon::$process->log(get_class($this->pool) . ': Couldn\'t listen TCP-socket \'' . $this->host . ':' . $port . '\' (' . $errno . ' - ' . socket_strerror($errno) . ')'); return false; } } $this->setFd($sock); return true; }
/** * Initialize FS driver * @return void */ public static function init() { if (!Daemon::$config->eioenabled->value) { self::$supported = false; return; } if (!(self::$supported = Daemon::loadModuleIfAbsent('eio', self::$eioVer))) { Daemon::log('FS: missing pecl-eio >= ' . self::$eioVer . '. Filesystem I/O performance compromised. Consider installing pecl-eio. `pecl install http://pecl.php.net/get/eio`'); return; } self::$fdCache = new CappedStorageHits(self::$fdCacheSize); eio_init(); }
/** * Called when file $path is changed * @param string $path Path * @return void */ public function onFileChanged($path) { if (!Daemon::lintFile($path)) { Daemon::log(__METHOD__ . ': Detected parse error in ' . $path); return; } foreach ($this->files[$path] as $cb) { if (is_callable($cb) || is_array($cb)) { $cb($path); } elseif (!Daemon::$process->IPCManager->importFile($cb, $path)) { $this->rmWatch($path, $cb); } } }
protected function getAuthorizationHeader($url, $oauth_params = []) { $params = ['oauth_consumer_key' => $this->cmp->config->twitter_app_key->value, 'oauth_nonce' => Daemon::uniqid(), 'oauth_signature_method' => 'HMAC-SHA1', 'oauth_timestamp' => time(), 'oauth_version' => '1.0']; if (!empty($oauth_params)) { $params = array_merge($params, $oauth_params); } $params['oauth_signature'] = OAuth::getSignature('POST', $url, $params, $this->cmp->config->twitter_app_secret->value); $header_params = []; foreach ($params as $param => $value) { $header_params[] = rawurlencode($param) . '="' . rawurlencode($value) . '"'; } $header = 'OAuth ' . implode(', ', $header_params); return $header; }
/** * Get real frame type identificator * @param $type * @return integer */ public function getFrameType($type) { if (is_int($type)) { return $type; } if ($type === null) { $type = 'STRING'; } $frametype = @constant($a = get_class($this) . '::' . $type); if ($frametype === null) { Daemon::log(__METHOD__ . ' : Undefined frametype "' . $type . '"'); } return $frametype; }
public function connect() { $this->asteriskclient->getConnection($this->config->url->value, function ($conn) { $this->asteriskconn = $conn; if ($conn->connected) { $conn->bind('disconnect', function ($conn) { \PHPDaemon\Core\Daemon::log('Connection lost... Reconnect in ' . $this->config->reconnect->value . ' sec'); $this->connect(); }); } else { \PHPDaemon\Core\Daemon::log(get_class($this) . ': couldn\'t connect to ' . $this->config->url->value); } }); }
/** * Called when request iterated. * @return integer Status. */ public function run() { $stime = microtime(true); $this->header('Content-Type: text/html; charset=utf-8'); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>Server status.</title> </head> <body> <br/>Uptime: <b><?php echo DateTime::diffAsText(Daemon::$startTime, time()); ?> </b> <br/><br/><b>State of workers:</b><?php $stat = Daemon::getStateOfWorkers(); ?> <br/>Idle: <?php echo $stat['idle']; ?> <br/>Busy: <?php echo $stat['busy']; ?> <br/>Total alive: <?php echo $stat['alive']; ?> <br/>Shutdown: <?php echo $stat['shutdown']; ?> <br/>Pre-init: <?php echo $stat['preinit']; ?> <br/>Wait-init: <?php echo $stat['waitinit']; ?> <br/>Init: <?php echo $stat['init']; ?> <br/> <br/>Request took: <?php printf('%f', round(microtime(true) - $stime, 6)); ?> </body> </html> <?php }
/** * Returns string of pseudo random characters * @param integer $len Length of desired string * @param string $chars String of allowed characters * @param callable $cb Callback * @param integer $pri Priority of EIO operation * @param boolean $hang If true, we shall use /dev/random instead of /dev/urandom and it may cause a delay * @return string */ public static function randomString($len = null, $chars = null, $cb = null, $pri = 0, $hang = false) { if ($len === null) { $len = 64; } if ($chars === null) { $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.'; } if ($cb === null) { Daemon::log('[CODE WARN] \\PHPDaemon\\Utils\\Crypt::randomString: non-callback way is not secure.' . ' Please rewrite your code with callback function in third argument' . PHP_EOL . Debug::backtrace()); $r = ''; $m = strlen($chars) - 1; for ($i = 0; $i < $len; ++$i) { $r .= $chars[mt_rand(0, $m)]; } return $r; } $charsLen = strlen($chars); $mask = static::getMinimalBitMask($charsLen - 1); $iterLimit = max($len, $len * 64); static::randomInts(2 * $len, function ($ints) use($cb, $chars, $charsLen, $len, $mask, &$iterLimit) { if ($ints === false) { call_user_func($cb, false); return; } $r = ''; for ($i = 0, $s = sizeof($ints); $i < $s; ++$i) { // This is wasteful, but RNGs are fast and doing otherwise adds complexity and bias $c = $ints[$i] & $mask; // Only use the random number if it is in range, otherwise try another (next iteration) if ($c < $charsLen) { $r .= static::stringIdx($chars, $c); } // Guarantee termination if (--$iterLimit <= 0) { return false; } } $d = $len - strlen($r); if ($d > 0) { static::randomString($d, $chars, function ($r2) use($r, $cb) { call_user_func($cb, $r . $r2); }); return; } call_user_func($cb, $r); }, $pri, $hang); }
/** * Constructor * @param string $path Path * @param integer $segsize Segment size * @param string $name Name * @param boolean $create Create */ public function __construct($path, $segsize, $name, $create = false) { $this->path = $path; $this->segsize = $segsize; $this->name = $name; if ($create && !touch($this->path)) { Daemon::log('Couldn\'t touch IPC file \'' . $this->path . '\'.'); exit(0); } if (!is_file($this->path) || ($this->key = ftok($this->path, 't')) === false) { Daemon::log('Couldn\'t ftok() IPC file \'' . $this->path . '\'.'); exit(0); } if (!$this->open(0, $create) && $create) { Daemon::log('Couldn\'t open IPC-' . $this->name . ' shared memory segment (key=' . $this->key . ', segsize=' . $this->segsize . ', uid=' . posix_getuid() . ', path = ' . $this->path . ').'); exit(0); } }