config = get_addon_config('fastim'); if ($this->config['wss_switch']) { if (file_exists($this->config['ssl_cert_file']) && file_exists($this->config['ssl_key_file'])) { $this->sockType = SWOOLE_SOCK_TCP | SWOOLE_SSL; } else { throw new Exception('SSL certificate file does not exist!'); } } $this->swoole = new WebSocketServer('0.0.0.0', $this->config['websocket_port'], $this->mode, $this->sockType); } /** * Worker 进程启动 * @param $server * @param $worker_id */ public function onWorkerStart($server, $worker_id) { $this->lastMtime = time(); if (0 == $worker_id && $this->monitor) { $this->monitor($server); } // print_r(get_included_files());// 查看不支持热更新的文件列表 // 保持mysql链接可用性 $server->tick(27000, function () { Db::execute("SELECT 1"); }); } /** * 链接握手成功 * @param $server * @param $frame */ public function onOpen($ws, $request) { $ws->push($request->fd, json_encode([ 'event' => 'open' ])); } /** * 收到数据帧 * @param $server * @param $frame */ public function onMessage($server, $frame) { $data = json_decode($frame->data, true); // 安全检查过滤 array_walk_recursive($data, ['addons\fastim\library\Common', 'checkVariable']); if (!is_array($data) || !isset($data['c']) || !isset($data['a'])) { $server->push($frame->fd, json_encode([ 'event' => 'show_msg', 'data' => '错误的请求!', 'close' => true ])); $server->close($frame->fd); return; } // 载入文件类似:根目录/addons/fastim/library/controller/index.php $filename = __DIR__ . '/../controller/' . $data['c'] . '.php'; if (file_exists($filename)) { require_once $filename; // 检查要访问的类是否存在 if (!class_exists($data['c'], false)) { $server->push($frame->fd, json_encode([ 'event' => 'show_msg', 'data' => '访问的控制器不存在!', 'close' => true ])); $server->close($frame->fd); return; } } else { $server->push($frame->fd, json_encode([ 'event' => 'show_msg', 'data' => '错误的请求!', 'close' => true ])); $server->close($frame->fd); return; } $o = new $data['c']([$server, $frame, $this->swooleCommon]); // 新建对象 if (!method_exists($o, $data['a'])) { $server->push($frame->fd, json_encode([ 'event' => 'show_msg', 'data' => '访问的方法不存在!' ])); return; } if ($o->authCheck($data['a'])) { $data['data'] = $data['data'] ?? []; call_user_func_array([$o, $data['a']], [$data['data']]); //调用对象$o($c)里的方法$a } } /** * 链接关闭 */ public function onClose($server, $fd, $reactorId) { // 解除fd绑定并修改用户状态 $uid = $this->swooleCommon->getUidByFd($fd); if (!$this->swooleCommon->unbindUid($fd, $uid)) { /** * 用户断开1分钟后才设置为离线状态 * Timer::after 不同于sleep,不会阻塞 */ Timer::after(60000, function () use ($uid) { if (!$this->swooleCommon->getFdByUid($uid)) { Db::name('fastim_user')->where('id', $uid)->update([ 'status' => 0 ]); $this->swooleCommon->radioStatusMessage($uid, 0); } }); } } public function option(array $option) { if (!empty($option)) { $this->swoole->set($this->checkOptions($option)); } // 注册回调 foreach ($this->event as $event) { if (method_exists($this, 'on' . $event)) { $this->swoole->on($event, [$this, 'on' . $event]); } } // 实例化swooleCommon类 $this->swooleCommon = new \addons\fastim\library\swoole\Common($option['max_connections'], $this->swoole); } protected function checkOptions(array $options) { if (class_exists(Helper::class)) { $constOptions = Helper::GLOBAL_OPTIONS + Helper::SERVER_OPTIONS + Helper::PORT_OPTIONS + Helper::HELPER_OPTIONS; foreach ($options as $k => $v) { if (!array_key_exists(strtolower($k), $constOptions)) { unset($options[$k]); } } } return $options; } public function setMonitor($interval = 2, $path = []) { $this->monitor['interval'] = $interval; $this->monitor['path'] = (array)$path; } /** * 文件监控 * * @param $server */ public function monitor($server) { if ($this->monitor['path']) { $server->tick($this->monitor['interval'], function () use ($server) { foreach ($this->monitor['path'] as $path) { $dir = new \RecursiveDirectoryIterator($path); $iterator = new \RecursiveIteratorIterator($dir); foreach ($iterator as $file) { if (pathinfo($file, PATHINFO_EXTENSION) != 'php') { continue; } if ($this->lastMtime < $file->getMTime()) { $this->lastMtime = $file->getMTime(); echo '[update]' . $file . " reload...\n"; $server->reload(); return; } } } }); } } /** * 魔术方法 有不存在的操作的时候执行 * @access public * @param string $method 方法名 * @param array $args 参数 * @return mixed */ public function __call($method, $args) { call_user_func_array([$this->swoole, $method], $args); } }