├── .env.example
├── .gitignore
├── react
├── WebSocket
│ ├── WsUser.php
│ ├── Dispatcher.php
│ ├── MiddlewareInterface.php
│ ├── MessageRoute.php
│ └── Event.php
├── Annotations
│ ├── Command.php
│ ├── Service.php
│ ├── RequestMethod.php
│ ├── Middleware.php
│ ├── Middlewares.php
│ ├── AnnotationFactory.php
│ └── RequestMapping.php
├── Providers
│ ├── ServiceProviderInterface.php
│ ├── WebSocketServiceProvider.php
│ ├── RegisterServiceProvider.php
│ ├── BusinessServiceProvider.php
│ ├── GatewayServiceProvider.php
│ ├── ConfigServiceProvider.php
│ ├── HttpServiceProvider.php
│ ├── EnvServiceProvider.php
│ ├── ConsoleServiceProvider.php
│ ├── DispatcherServiceProvider.php
│ └── RouteServiceProvider.php
├── Helper
│ ├── Functions.php
│ ├── RouteHelper.php
│ └── DirectoryHelper.php
├── Factorys
│ ├── CreateWorkermenResponse.php
│ └── CreateWorkermenRequest.php
├── ReactApp.php
├── Http
│ ├── Server.php
│ └── ServerRequest.php
├── Middlewares
│ └── ResponseFactoryMiddleware.php
└── Protocols
│ └── BusinessWorker.php
├── config
├── ws.php
└── config.php
├── bin
├── define.php
├── server
└── bootstrap.php
├── app
├── WebSocket
│ ├── User.php
│ ├── Controllers
│ │ └── HelloWorldController.php
│ └── Events
│ │ └── WsEvent.php
├── App.php
├── Annotations
│ └── MessageMapping.php
├── Commands
│ ├── Http
│ │ ├── HttpCommand.php
│ │ ├── StopCommand.php
│ │ └── StartCommand.php
│ └── WebSocket
│ │ ├── WebSocketCommand.php
│ │ ├── StopCommand.php
│ │ ├── StartDebugCommand.php
│ │ └── StartCommand.php
├── Http
│ └── Controllers
│ │ ├── LoginController.php
│ │ └── HelloWorldController.php
├── Providers
│ └── EmailServiceProvider.php
└── Middlewares
│ ├── WhoopsMiddleware.php
│ ├── LoginMiddleware.php
│ └── CorsMiddleware.php
├── debug.php
├── README.md
└── composer.json
/.env.example:
--------------------------------------------------------------------------------
1 | HTTP_SOCKET="http://0.0.0.0:8080"
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .buildpath
2 | .settings/
3 | .project
4 | *.patch
5 | .idea/
6 | .git/
7 | runtime/
8 | vendor/
9 | temp/
10 | *.lock
11 | .phpintel/
12 | .env
13 | .DS_Store
14 |
--------------------------------------------------------------------------------
/react/WebSocket/WsUser.php:
--------------------------------------------------------------------------------
1 | [
11 | /**
12 | * 全局中间件
13 | */
14 | 'middleware' => [
15 |
16 | ],
17 |
18 |
19 |
20 | ],
21 | ];
--------------------------------------------------------------------------------
/bin/define.php:
--------------------------------------------------------------------------------
1 | run();
18 |
--------------------------------------------------------------------------------
/bin/bootstrap.php:
--------------------------------------------------------------------------------
1 | route = $values['route']??$values['value']??'';
24 | }
25 |
26 | public function getRoute()
27 | {
28 | return $this->route;
29 | }
30 | }
--------------------------------------------------------------------------------
/react/Annotations/Service.php:
--------------------------------------------------------------------------------
1 | name = $values["name"]??$values["value"];
25 | $this->sort = $values["sort"]??100;
26 | }
27 | }
--------------------------------------------------------------------------------
/react/Helper/Functions.php:
--------------------------------------------------------------------------------
1 | run();
--------------------------------------------------------------------------------
/react/Providers/WebSocketServiceProvider.php:
--------------------------------------------------------------------------------
1 | getQueryParams(),$request->getParsedBody()];
26 | }
27 | }
--------------------------------------------------------------------------------
/app/Providers/EmailServiceProvider.php:
--------------------------------------------------------------------------------
1 | handleUnconditionally(true);
24 | $run->pushHandler($PrettyPageHandler);
25 |
26 | parent::__construct($run, $system);
27 | }
28 | }
--------------------------------------------------------------------------------
/react/Factorys/CreateWorkermenResponse.php:
--------------------------------------------------------------------------------
1 | call = $call;
22 | }
23 |
24 | public function getClosure()
25 | {
26 | return $this->call;
27 | }
28 |
29 | public function addMiddleware(MiddlewareInterface $middleware)
30 | {
31 | $this->middlewares[] = $middleware;
32 | }
33 |
34 | public function getMiddleware()
35 | {
36 | return $this->middlewares;
37 | }
38 | }
--------------------------------------------------------------------------------
/app/Commands/Http/StopCommand.php:
--------------------------------------------------------------------------------
1 | setName('http:stop')
26 | ->setDescription('关闭http')
27 | ;
28 | }
29 |
30 | protected function execute(InputInterface $input, OutputInterface $output)
31 | {
32 | $this->setWorker('stop');
33 | }
34 | }
--------------------------------------------------------------------------------
/app/Commands/WebSocket/StopCommand.php:
--------------------------------------------------------------------------------
1 | setName('ws:stop')
27 | ->setDescription('关闭所有worker')
28 | ;
29 | }
30 |
31 | protected function execute(InputInterface $input, OutputInterface $output)
32 | {
33 | $this->setWorker("stop");
34 | }
35 | }
--------------------------------------------------------------------------------
/react/Annotations/Middleware.php:
--------------------------------------------------------------------------------
1 | class = $values['value'];
30 | }
31 | if (isset($values['class'])) {
32 | $this->class = $values['class'];
33 | }
34 | }
35 |
36 | /**
37 | * @return string
38 | */
39 | public function getClass(): string
40 | {
41 | return $this->class;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/Middlewares/LoginMiddleware.php:
--------------------------------------------------------------------------------
1 | handle($request);
30 | }
31 | }
--------------------------------------------------------------------------------
/react/WebSocket/MessageRoute.php:
--------------------------------------------------------------------------------
1 | call = $call;
21 | }
22 |
23 | public function getClosure()
24 | {
25 | return $this->call;
26 | }
27 |
28 | public function setRoute($route)
29 | {
30 | $this->route = $route;
31 | }
32 |
33 | public function getRoute()
34 | {
35 | return $this->route;
36 | }
37 |
38 | public function addMiddleware(MiddlewareInterface $middleware)
39 | {
40 | $this->middleware[] = $middleware;
41 | }
42 |
43 | public function getMiddleware()
44 | {
45 | return $this->middleware;
46 | }
47 | }
--------------------------------------------------------------------------------
/app/Commands/WebSocket/StartDebugCommand.php:
--------------------------------------------------------------------------------
1 | setName('ws:debug')
29 | ->setDescription('开启business服务')
30 | ;
31 | }
32 |
33 | protected function execute(InputInterface $input, OutputInterface $output)
34 | {
35 | App::getService("business")->listen();
36 |
37 | $this->setWorker("start");
38 | }
39 | }
--------------------------------------------------------------------------------
/react/Providers/RegisterServiceProvider.php:
--------------------------------------------------------------------------------
1 | withQueryParams($date['get']);
30 | $request = $request->withParsedBody($date['post']);
31 | $request = $request->withUploadedFiles($date['files']);
32 |
33 | return $request;
34 | }
35 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 这是对workermen封装、规范、友好化的项目,对所有功能组件化,不重复造轮子,所有组件全部使用已存在的、热门的composer包
2 | 。
3 |
4 |
5 |
6 |
7 |
8 |
9 | ## 主要特性
10 |
11 | - [ ] 注解加载,服务、路由、命令等等,自定义注解也友好
12 | - [ ] 严格遵循`psr`规范
13 | - [ ] 单一入口,控制台使用最入门的`symfony/console`
14 | - [ ] 异常捕捉,`whoops`使错误更漂亮的显示
15 | - [ ] 方便调试,可以使用`xdebug`调试程序
16 | - [ ] 内置定时任务解析器
17 | - [ ] 内置异步`task`
18 |
19 | ## 开发计划
20 |
21 | 因为开发资源有限,开发计划暂定如下:
22 |
23 | 1. 定时任务,更好的定时测试,提供界面改时间触发定时任务
24 | 2. 支持多种session启动,文件,redis等
25 | 3. 异步task封装
26 |
27 | git安装
28 | ~~~~
29 | git clone https://github.com/ctfang/react.git
30 | cd react
31 | composer install
32 | ~~~~
33 | 查看帮助命令
34 | ~~~~php
35 | php bin/server
36 | ~~~~
37 |
38 | 启动http服务,如果需要使用80端口,加上 sudo
39 | ~~~~php
40 | // 守护模式
41 | php bin/server http:start --domain
42 | // 非守护模式
43 | php bin/server http:start
44 | // 关闭
45 | php bin/server http:stop
46 | ~~~~
47 |
--------------------------------------------------------------------------------
/app/WebSocket/Events/WsEvent.php:
--------------------------------------------------------------------------------
1 | [
14 | 'socket' => env('HTTP_SOCKET', 'http://0.0.0.0:8080'),
15 | 'count' => env('HTTP_COUNT', 1),
16 | ],
17 |
18 | /**
19 | * 全局中间件
20 | */
21 | 'middleware' => [
22 | \App\Middlewares\WhoopsMiddleware::class,
23 | \App\Middlewares\CorsMiddleware::class
24 | ],
25 |
26 | 'register' => [
27 | // 'socket' => env('REGISTER_SOCKET', '0.0.0.0'),
28 | 'connect' => env('REGISTER_OTHER', '127.0.0.1'),
29 | 'port' => env('REGISTER_PORT', 8060),
30 | ],
31 |
32 | 'business' => [
33 | 'name' => env('BUSINESS_NAME', 'MyWsApp'),
34 | 'count' => env('BUSINESS_COUNT', 1),
35 | ],
36 |
37 | /**
38 | * WebSocket配置
39 | */
40 | 'gateway' => [
41 | 'socket' => env('GATEWAY_SOCKET', 'WebSocket://0.0.0.0:8070'),
42 | 'name' => env('GATEWAY_NAME', 'WebSocket'),
43 | 'lan_ip' => env('GATEWAY_LANIP', '0.0.0.0'),
44 | 'start_port' => env('GATEWAY_START_PORT', '4000'),
45 | 'count' => env('GATEWAY_COUNT', 1),
46 | ],
47 | ];
--------------------------------------------------------------------------------
/react/Providers/BusinessServiceProvider.php:
--------------------------------------------------------------------------------
1 | name = App::config('business.name', 'business');
50 | // bussinessWorker进程数量
51 | $worker->count = App::isLinux() ? App::config('business.count') : 1;
52 | // 服务注册地址
53 | $worker->registerAddress = App::config('register.connect').':'.App::config('register.port');
54 | $worker->eventHandler = WsEvent::class;
55 | }
56 | }
--------------------------------------------------------------------------------
/react/Annotations/Middlewares.php:
--------------------------------------------------------------------------------
1 | middlewares = $values['value'];
35 | }
36 | if (isset($values['middlewares'])) {
37 | $this->middlewares = $values['value'];
38 | }
39 | if (isset($values['group'])) {
40 | $this->group = $values['value'];
41 | }
42 | }
43 |
44 | /**
45 | * @return array
46 | */
47 | public function getMiddlewares(): array
48 | {
49 | return $this->middlewares;
50 | }
51 |
52 | /**
53 | * @param array $middlewares
54 | * @return Middlewares
55 | */
56 | public function setMiddlewares($middlewares)
57 | {
58 | $this->middlewares = $middlewares;
59 | return $this;
60 | }
61 |
62 | /**
63 | * @return string
64 | */
65 | public function getGroup(): string
66 | {
67 | return $this->group;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/Commands/Http/StartCommand.php:
--------------------------------------------------------------------------------
1 | setName('http:start')
33 | ->addOption(
34 | "domain",
35 | null,
36 | InputOption::VALUE_OPTIONAL,
37 | "是否守护进程运行",
38 | 0
39 | )
40 | ->setDescription('开启http服务')
41 | ;
42 | }
43 |
44 | protected function execute(InputInterface $input, OutputInterface $output)
45 | {
46 | $domain = $input->getOption("domain");
47 |
48 | if( $domain || $domain===null ){
49 | $output->writeln("守护进程启动");
50 |
51 | Worker::$daemonize = true;
52 | }
53 |
54 | /** @var HttpServiceProvider $http */
55 | $http = App::getService("http");
56 |
57 | $http->listen();
58 |
59 | $this->setWorker('start');
60 | }
61 | }
--------------------------------------------------------------------------------
/react/Providers/GatewayServiceProvider.php:
--------------------------------------------------------------------------------
1 | name = App::config('gateway.name');
50 | // gateway进程数
51 | $gateway->count = App::config('gateway.count', 1);
52 | // 本机ip,分布式部署时使用内网ip
53 | $gateway->lanIp = App::config('gateway.lan_ip');
54 | // 内部通讯起始端口,假如$gateway->count=4,起始端口为4000
55 | // 则一般会使用4000 4001 4002 4003 4个端口作为内部通讯端口
56 | $gateway->startPort = App::config('gateway.start_port');
57 | // 服务注册地址
58 | $gateway->registerAddress = App::config('register.connect').':'.App::config('register.port');
59 | }
60 | }
--------------------------------------------------------------------------------
/app/Middlewares/CorsMiddleware.php:
--------------------------------------------------------------------------------
1 | getMethod()==RequestMethod::OPTIONS ){
36 | $response = Factory::createResponse();
37 | $body = $response->getBody();
38 | $body->write('');
39 | $response = $response->withBody($body);
40 | $response = $response->withAddedHeader("Access-Control-Allow-Headers","content-type");
41 | }else{
42 | $response = $handler->handle($request);
43 | }
44 | $response = $response->withAddedHeader('Access-Control-Allow-Origin', "*");
45 | return $response;
46 | }
47 | }
--------------------------------------------------------------------------------
/react/Providers/ConfigServiceProvider.php:
--------------------------------------------------------------------------------
1 | path = realpath(__ROOT_PATH__ . '/config');
31 | $this->default = realpath($this->path . '/' . $this->default);
32 | parent::__construct($data);
33 | }
34 |
35 | /**
36 | * 加载过程触发
37 | *
38 | * @return void
39 | */
40 | public function boot()
41 | {
42 | foreach (glob($this->path . '/*.php') as $start_file) {
43 | if (realpath($start_file) == $this->default) {
44 | break;
45 | }
46 | $arr = include $start_file;
47 | if ($arr) {
48 | $this->merge($arr);
49 | }
50 | }
51 | }
52 |
53 | /**
54 | * 所有服务加载后,注册触发,
55 | *
56 | * @return void
57 | */
58 | public function register()
59 | {
60 |
61 | }
62 |
63 | /**
64 | * @return array|mixed
65 | */
66 | protected function getDefaults()
67 | {
68 | if (file_exists($this->default)) {
69 | return include $this->default;
70 | }
71 | return [];
72 | }
73 | }
--------------------------------------------------------------------------------
/react/Providers/HttpServiceProvider.php:
--------------------------------------------------------------------------------
1 | socket = App::config('http.socket', 'http://0.0.0.0:8080');
49 | $this->count = App::config('http.count');
50 | }
51 |
52 | public function listen()
53 | {
54 | $server = new Server(function (ServerRequestInterface $request) {
55 | /** @var DispatcherServiceProvider $dispatcher */
56 | $dispatcher = App::getService('dispatcher');
57 | return $dispatcher->dispatch($request);
58 | });
59 | $socket = new Worker($this->socket);
60 |
61 | if( App::isLinux() ){
62 | $socket->count = $this->count;
63 | }
64 |
65 | $server->listen($socket);
66 | }
67 | }
--------------------------------------------------------------------------------
/app/Http/Controllers/HelloWorldController.php:
--------------------------------------------------------------------------------
1 | time(), 'query' => $request->getQueryParams(), 'parsed' => $request->getParsedBody()];
28 | }
29 |
30 | /**
31 | * 错误显示
32 | * @RequestMapping("/error")CallableHandler
33 | */
34 | public function index()
35 | {
36 | throw new \Exception("错误界面显示");
37 | }
38 |
39 | /**
40 | * 谷歌镜像
41 | * @RequestMapping("/google")
42 | * @param ServerRequestInterface $request
43 | * @throws \Exception
44 | */
45 | public function google(ServerRequestInterface $request)
46 | {
47 | $google = "www.baidu.com";
48 |
49 | $conToGoogle = new AsyncTcpConnection("tcp://{$google}:443");
50 | $conToGoogle->transport = 'ssl';
51 | $conToGoogle->onConnect = function ($conToGoogle)use($google) {
52 | $conToGoogle->send("GET / HTTP/1.1\r\nHost: {$google}\r\nConnection: keep-alive\r\n\r\n");
53 | };
54 | $conToGoogle->onMessage = function ($conToGoogle, $http_buffer) use ($request) {
55 | $connection = $request->getAttribute('connection');
56 | $connection->send($http_buffer,true);
57 | };
58 | $conToGoogle->connect();
59 | }
60 | }
--------------------------------------------------------------------------------
/app/Commands/WebSocket/StartCommand.php:
--------------------------------------------------------------------------------
1 | setName('ws:start')
30 | ->addOption(
31 | "domain",
32 | null,
33 | InputOption::VALUE_OPTIONAL,
34 | "是否守护进程运行",
35 | 0
36 | )
37 | ->addOption(
38 | 'debug',
39 | null,
40 | InputOption::VALUE_OPTIONAL,
41 | '是否启用隔离调试',
42 | 0
43 | )
44 | ->setDescription('开启WebSocket服务')
45 | ;
46 | }
47 |
48 | protected function execute(InputInterface $input, OutputInterface $output)
49 | {
50 | $domain = $input->getOption("domain");
51 | $debug = $input->getOption("debug");
52 |
53 | if( $domain || $domain===null ){
54 | $output->writeln("守护进程启动");
55 |
56 | Worker::$daemonize = true;
57 | }
58 |
59 | App::getService("register")->listen();
60 | App::getService("gateway")->listen();
61 |
62 | if( $debug===null || $debug ){
63 | // 启用隔离
64 | $output->writeln("开启隔离;需要另外开启ws:debug处理");
65 | }else{
66 | App::getService("business")->listen();
67 | }
68 |
69 | $this->setWorker("debug");
70 | }
71 | }
--------------------------------------------------------------------------------
/react/ReactApp.php:
--------------------------------------------------------------------------------
1 | get($key,$default);
89 | }
90 | }
--------------------------------------------------------------------------------
/react/Providers/EnvServiceProvider.php:
--------------------------------------------------------------------------------
1 | load();
35 |
36 | if (isset($_ENV)) {
37 | foreach ($_ENV as $key => $value) {
38 | switch (strtolower($value)) {
39 | case 'true':
40 | case '(true)':
41 | $value = true;
42 | break;
43 | case 'false':
44 | case '(false)':
45 | $value = false;
46 | break;
47 | case 'empty':
48 | case '(empty)':
49 | $value = '';
50 | break;
51 | case 'null':
52 | case '(null)':
53 | $value = null;
54 | break;
55 | default:
56 | if( ($strLen = strlen($value)) > 1 && $value{0}==='"' && $value{$strLen}==='"' ){
57 | $value = substr($value,1,$strLen-1);
58 | }
59 | break;
60 | }
61 | $_ENV[$key] = $value;
62 | }
63 | }
64 | }
65 |
66 | /**
67 | * 所有服务加载后,注册触发,
68 | *
69 | * @return void
70 | */
71 | public function register()
72 | {
73 | // TODO: Implement register() method.
74 | }
75 | }
--------------------------------------------------------------------------------
/react/Http/Server.php:
--------------------------------------------------------------------------------
1 | requestHandler = $requestHandler;
34 | }
35 |
36 | /**
37 | * @param Worker $socket
38 | * @throws \Exception
39 | */
40 | public function listen(Worker $socket)
41 | {
42 | $socket->onMessage = function (TcpConnection $connection, $data) {
43 |
44 | $request = CreateWorkermenRequest::create($data);
45 |
46 | $request = $request->withAttribute('connection',$connection);
47 |
48 | /** @var ResponseInterface $response */
49 | $response = ($this->requestHandler)($request);
50 |
51 | $this->handleResponse($connection,$response);
52 | };
53 |
54 | $socket->listen();
55 | }
56 |
57 | /**
58 | * @param TcpConnection $connection
59 | * @param ResponseInterface $response
60 | */
61 | public function handleResponse(TcpConnection $connection, ResponseInterface $response)
62 | {
63 | $body = $response->getBody();
64 |
65 | $headers = $response->getHeaders();
66 |
67 | foreach ($headers as $key=>$value){
68 | Http::header($key.":".implode(";",$value));
69 | }
70 |
71 | $code = $response->getStatusCode();
72 |
73 | Http::header('Http-Code:',false,$code);
74 |
75 | if( $body->getSize() ){
76 | $connection->send($body);
77 | }else{
78 | $connection->send('');
79 | $connection->close();
80 | }
81 | }
82 | }
--------------------------------------------------------------------------------
/react/Providers/ConsoleServiceProvider.php:
--------------------------------------------------------------------------------
1 | setLoader($loader);
43 | $directory->setScanNamespace($this->namespaces);
44 | $reader = new AnnotationReader();
45 |
46 | foreach ($directory->scanClass() as $class) {
47 | if (class_exists($class)) {
48 |
49 | $reflectionClass = new \ReflectionClass($class);
50 | $classAnnotations = $reader->getClassAnnotations($reflectionClass);
51 | foreach ($classAnnotations AS $annotation) {
52 | if( $annotation instanceof \ReactApp\Annotations\Command){
53 | $this->commands[] = $class;
54 | }
55 | }
56 | }
57 | }
58 | }
59 |
60 | /**
61 | * 所有服务加载后,注册触发,
62 | *
63 | * @return void
64 | */
65 | public function register()
66 | {
67 | $application = new Application("workermen http and ws server","0.1.2");
68 |
69 | foreach ($this->commands as $command){
70 | $class = new $command();
71 | if( $class instanceof Command){
72 | $application->add(new $command());
73 | }
74 | }
75 |
76 | $this->application = $application;
77 | unset($this->commands);
78 | }
79 |
80 | public function run()
81 | {
82 | $this->application->run();
83 | }
84 | }
--------------------------------------------------------------------------------
/react/Middlewares/ResponseFactoryMiddleware.php:
--------------------------------------------------------------------------------
1 | getAttribute("request-handler"), [$request,$handler]);
42 |
43 | if ($return instanceof ResponseInterface) {
44 | $response = $return;
45 | $return = '';
46 | } elseif ( is_array($return) ){
47 | $response = Factory::createResponse();
48 | $response = $response->withAddedHeader("Content-Type",["application/json","charset=utf-8"]);
49 | $return = json_encode($return);
50 | }elseif (is_null($return) || is_scalar($return) || (is_object($return) && method_exists($return, '__toString'))) {
51 | $response = Factory::createResponse();
52 | } else {
53 | throw new \UnexpectedValueException(
54 | 'The value returned must be scalar or an object with __toString method'
55 | );
56 | }
57 |
58 | while (ob_get_level() >= $level) {
59 | $return = ob_get_clean().$return;
60 | }
61 |
62 | $body = $response->getBody();
63 |
64 | if ($return !== '' && $body->isWritable()) {
65 | $body->write($return);
66 | }
67 |
68 | return $response;
69 | } catch (\Exception $exception) {
70 | while (ob_get_level() >= $level) {
71 | ob_end_clean();
72 | }
73 |
74 | throw $exception;
75 | }
76 | }
77 | }
--------------------------------------------------------------------------------
/react/Annotations/AnnotationFactory.php:
--------------------------------------------------------------------------------
1 | setLoader($loader);
36 | $directory->setScanNamespace($namespaces);
37 |
38 | AnnotationRegistry::registerLoader(array($loader, "loadClass"));
39 |
40 | self::scanAnnotation($directory);
41 | }
42 |
43 | /**
44 | * 索引所有注解
45 | * @param DirectoryHelper $directory
46 | * @throws \Doctrine\Common\Annotations\AnnotationException
47 | * @throws \ReflectionException
48 | */
49 | public static function scanAnnotation(DirectoryHelper $directory)
50 | {
51 | $reader = new AnnotationReader();
52 | $serviceAnnotations = [];
53 | foreach ($directory->scanClass() as $class) {
54 | if (class_exists($class)) {
55 | $reflectionClass = new ReflectionClass($class);
56 | $classAnnotations = $reader->getClassAnnotations($reflectionClass);
57 |
58 | foreach ($classAnnotations AS $annotation) {
59 | if ($annotation instanceof Service) {
60 | if( isset($serviceAnnotations[$annotation->name]) ) continue;
61 | $annotation->className = $class;
62 | $serviceAnnotations[$annotation->name] = $annotation;
63 | }
64 | }
65 | }
66 | }
67 |
68 | foreach (App::$before as $i=>$name){
69 | $annotation = $serviceAnnotations[$name];
70 | $annotation->sort = 90000+$i;
71 | }
72 |
73 | foreach ($serviceAnnotations as $name=>$annotation){
74 | $serviceAnnotations[($annotation->sort+10000).$name] = $annotation;
75 | unset($serviceAnnotations[$name]);
76 | }
77 |
78 | ksort($serviceAnnotations);
79 |
80 | foreach ($serviceAnnotations as $annotation){
81 | $class = $annotation->className;
82 | $object = new $class();
83 | $object->boot();
84 | App::setService($annotation->name,$object);
85 | }
86 |
87 | foreach ($serviceAnnotations as $annotation){
88 | App::getService($annotation->name)->register();
89 | }
90 | unset($serviceAnnotations);
91 | }
92 | }
--------------------------------------------------------------------------------
/react/Annotations/RequestMapping.php:
--------------------------------------------------------------------------------
1 | route = $values['value'];
54 | }
55 |
56 | if (isset($values['route'])) {
57 | $this->route = $values['route'];
58 | }
59 |
60 | if (isset($values['method'])) {
61 | $method = $values['method'];
62 | $this->method = (array)$method;
63 | $this->method = array_change_key_case($this->method,CASE_UPPER);
64 | }
65 |
66 | if (isset($values['params'])) {
67 | $this->params = $values['params'];
68 | }
69 |
70 | if (isset($values['defaults'])) {
71 | $this->defaults = $values['defaults'];
72 | }
73 | }
74 |
75 | /**
76 | * 获取路由
77 | *
78 | * @return string
79 | */
80 | public function getRoute(): string
81 | {
82 | return $this->route;
83 | }
84 |
85 |
86 | /**
87 | * 获取路由
88 | *
89 | * @param string $route
90 | * @return string
91 | */
92 | public function setRoute(string $route): string
93 | {
94 | return $this->route = $route;
95 | }
96 |
97 | /**
98 | * 获取方法集合
99 | *
100 | * @return array
101 | */
102 | public function getMethod(): array
103 | {
104 | return $this->method;
105 | }
106 |
107 | /**
108 | * @return array
109 | */
110 | public function getParams(): array
111 | {
112 | return $this->params;
113 | }
114 |
115 | /**
116 | * @param array $params
117 | */
118 | public function setParams(array $params)
119 | {
120 | $this->params = $params;
121 | }
122 |
123 | /**
124 | * @return array
125 | */
126 | public function getDefaults(): array
127 | {
128 | return $this->defaults;
129 | }
130 |
131 | /**
132 | * @param array $defaults
133 | */
134 | public function setDefaults(array $defaults)
135 | {
136 | $this->defaults = $defaults;
137 | }
138 | }
--------------------------------------------------------------------------------
/react/Protocols/BusinessWorker.php:
--------------------------------------------------------------------------------
1 | _gatewayAddresses = array();
41 | foreach ($addresses as $addr) {
42 | $this->_gatewayAddresses[$addr] = $addr;
43 | }
44 | $this->checkGatewayConnections($addresses);
45 | break;
46 | default:
47 | echo "Receive bad event:$event from Register.\n";
48 | }
49 | }
50 |
51 |
52 | /**
53 | * 尝试连接 Gateway 内部通讯地址
54 | *
55 | * @param string $addr
56 | * @throws \Exception
57 | */
58 | public function tryToConnectGateway($addr)
59 | {
60 | if (!isset($this->gatewayConnections[$addr]) && !isset($this->_connectingGatewayAddresses[$addr]) && isset($this->_gatewayAddresses[$addr])) {
61 |
62 | $conAddr = str_replace('0.0.0.0','127.0.0.1',$addr);
63 |
64 | $gateway_connection = new AsyncTcpConnection("GatewayProtocol://$conAddr");
65 | $gateway_connection->remoteAddress = $addr;
66 | $gateway_connection->onConnect = array($this, 'onConnectGateway');
67 | $gateway_connection->onMessage = array($this, 'onGatewayMessage');
68 | $gateway_connection->onClose = array($this, 'onGatewayClose');
69 | $gateway_connection->onError = array($this, 'onGatewayError');
70 | $gateway_connection->maxSendBufferSize = $this->sendToGatewayBufferSize;
71 | if (TcpConnection::$defaultMaxSendBufferSize == $gateway_connection->maxSendBufferSize) {
72 | $gateway_connection->maxSendBufferSize = 50 * 1024 * 1024;
73 | }
74 | $gateway_data = GatewayProtocol::$empty;
75 | $gateway_data['cmd'] = GatewayProtocol::CMD_WORKER_CONNECT;
76 | $gateway_data['body'] = json_encode(array(
77 | 'worker_key' =>"{$this->name}:{$this->id}",
78 | 'secret_key' => $this->secretKey,
79 | ));
80 | $gateway_connection->send($gateway_data);
81 | $gateway_connection->connect();
82 | $this->_connectingGatewayAddresses[$addr] = $addr;
83 | }
84 | unset($this->_waitingConnectGatewayAddresses[$addr]);
85 | }
86 | }
--------------------------------------------------------------------------------
/react/Http/ServerRequest.php:
--------------------------------------------------------------------------------
1 | serverParams = $serverParams;
48 | }
49 |
50 | public function getServerParams()
51 | {
52 | return $this->serverParams;
53 | }
54 |
55 | public function getCookieParams()
56 | {
57 | return $this->cookies;
58 | }
59 |
60 | public function withCookieParams(array $cookies)
61 | {
62 | $new = clone $this;
63 | $new->cookies = $cookies;
64 | return $new;
65 | }
66 |
67 | public function getQueryParams()
68 | {
69 | return $this->queryParams;
70 | }
71 |
72 | public function withQueryParams(array $query)
73 | {
74 | $new = clone $this;
75 | $new->queryParams = $query;
76 | return $new;
77 | }
78 |
79 | public function getUploadedFiles()
80 | {
81 | return $this->fileParams;
82 | }
83 |
84 | public function withUploadedFiles(array $uploadedFiles)
85 | {
86 | $new = clone $this;
87 | $new->fileParams = $uploadedFiles;
88 | return $new;
89 | }
90 |
91 | public function getParsedBody()
92 | {
93 | return $this->parsedBody;
94 | }
95 |
96 | public function withParsedBody($data)
97 | {
98 | $new = clone $this;
99 | $new->parsedBody = $data;
100 | return $new;
101 | }
102 |
103 | public function getAttributes()
104 | {
105 | return $this->attributes;
106 | }
107 |
108 | public function getAttribute($name, $default = null)
109 | {
110 | if (!array_key_exists($name, $this->attributes)) {
111 | return $default;
112 | }
113 | return $this->attributes[$name];
114 | }
115 |
116 | public function withAttribute($name, $value)
117 | {
118 | $new = clone $this;
119 | $new->attributes[$name] = $value;
120 | return $new;
121 | }
122 |
123 | public function withoutAttribute($name)
124 | {
125 | $new = clone $this;
126 | unset($new->attributes[$name]);
127 | return $new;
128 | }
129 | }
--------------------------------------------------------------------------------
/react/Providers/DispatcherServiceProvider.php:
--------------------------------------------------------------------------------
1 | responseFactory = new ResponseFactoryMiddleware();
55 | $this->responder = function ($request, $next) {
56 | return Factory::createResponse();
57 | };
58 | }
59 |
60 | /**
61 | * 所有服务加载后,注册触发,
62 | *
63 | * @return void
64 | */
65 | public function register()
66 | {
67 | foreach (App::config('middleware') as $middleware) {
68 | $this->defaultMiddleware[] = new $middleware();
69 | }
70 | /** @var RouteServiceProvider $router */
71 | $router = App::getService('route');
72 | $this->route = $router->getDispatcher();
73 | }
74 |
75 | /**
76 | * 调度处理
77 | *
78 | * @param ServerRequestInterface $request
79 | * @return ResponseInterface
80 | */
81 | public function dispatch(ServerRequestInterface $request): ResponseInterface
82 | {
83 | $route = $this->route->dispatch($request->getMethod(), $request->getUri()->getPath());
84 |
85 | if ($route[0] === Dispatcher::NOT_FOUND) {
86 | return Factory::createResponse(404);
87 | }
88 |
89 | foreach ($route[2] as $name => $value) {
90 | $request = $request->withAttribute($name, $value);
91 | }
92 |
93 | /** @var RouteHelper $routeHelper */
94 | $routeHelper = $route[1];
95 | $queue = $this->defaultMiddleware;
96 | $queue = array_merge($queue, $routeHelper->getMiddleware());
97 | $queue[] = $this->responseFactory;
98 | $queue[] = $this->responder;
99 | $relay = new Relay($queue);
100 | $request = $this->setHandler($request, $routeHelper->getClosure());
101 | return $relay->handle($request);
102 | }
103 |
104 | /**
105 | * Set the handler reference on the request.
106 | *
107 | * @param ServerRequestInterface $request
108 | * @param mixed $handler
109 | * @return ServerRequestInterface
110 | */
111 | protected function setHandler(ServerRequestInterface $request, $handler): ServerRequestInterface
112 | {
113 | return $request->withAttribute($this->attribute, $handler);
114 | }
115 | }
--------------------------------------------------------------------------------
/react/Helper/DirectoryHelper.php:
--------------------------------------------------------------------------------
1 | dirBindNameSpace[$directory] = $nameSpace;
36 | }
37 |
38 | /**
39 | * 设置搜索文件的扩展名
40 | *
41 | * @param $extensions
42 | */
43 | public function setExtensions($extensions)
44 | {
45 | $this->extensions = $extensions;
46 | }
47 |
48 | /**
49 | * 遍历目录下所有类
50 | *
51 | * @return \Generator
52 | */
53 | public function scanClass()
54 | {
55 | foreach ($this->dirBindNameSpace as $directory => $nameSpace) {
56 | foreach ($this->scanNameSpace($directory, $nameSpace) as $class) {
57 | yield $class;
58 | }
59 | }
60 | }
61 |
62 | /**
63 | * 遍历命名空间
64 | *
65 | * @param $directory
66 | * @param $nameSpace
67 | * @return \Generator
68 | */
69 | private function scanNameSpace($directory, $nameSpace)
70 | {
71 | if ($dh = opendir($directory)) {
72 | while (($file = readdir($dh)) !== false) {
73 | if (in_array($file, ['.', '..'])) {
74 | continue;
75 | } elseif (is_dir($directory . DIRECTORY_SEPARATOR . $file)) {
76 | foreach ($this->scanNameSpace($directory . DIRECTORY_SEPARATOR . $file, $nameSpace . $file . "\\") as $arrValue) {
77 | yield $arrValue;
78 | }
79 | } elseif (substr($file, -4) == $this->extensions) {
80 | yield $nameSpace . pathinfo($file, PATHINFO_FILENAME);
81 | }
82 | }
83 | closedir($dh);
84 | }
85 | }
86 |
87 | /**
88 | * 设置类加载器
89 | * @param ClassLoader $loader
90 | */
91 | public function setLoader(ClassLoader $loader)
92 | {
93 | $this->loader = $loader;
94 | }
95 |
96 | /**
97 | * @return ClassLoader
98 | */
99 | public function getLoader()
100 | {
101 | return $this->loader;
102 | }
103 |
104 | /**
105 | * @param $namespaces
106 | */
107 | public function setScanNamespace($namespaces)
108 | {
109 | foreach ($namespaces as $namespace){
110 | foreach ($this->findDirectoryWithNamespace($namespace) as $dir){
111 | $this->setScanDirectory($dir,$namespace);
112 | }
113 | }
114 | }
115 |
116 | private function findDirectoryWithNamespace(string $namespace)
117 | {
118 | $loader = $this->loader;
119 | $prePsr4 = $loader->getPrefixesPsr4();
120 |
121 | $arrNamespace = explode('\\',$namespace);
122 | $lastName = '';
123 | foreach ($arrNamespace as $key=>$name){
124 | unset($arrNamespace[$key]);
125 | if (!$name) break;
126 | $name = $lastName.$name."\\";
127 | if( isset($prePsr4[$name]) ){
128 | foreach ($prePsr4[$name] as $dir){
129 | yield realpath($dir.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR,$arrNamespace));
130 | }
131 | break;
132 | }
133 | $lastName = $name;
134 | }
135 | return '';
136 | }
137 | }
--------------------------------------------------------------------------------
/react/WebSocket/Event.php:
--------------------------------------------------------------------------------
1 | scanClass() as $class) {
42 | if (class_exists($class)) {
43 | $reflectionClass = new ReflectionClass($class);
44 | $classAnnotations = $reader->getClassAnnotations($reflectionClass);
45 |
46 | $queue = [];
47 | foreach ($classAnnotations AS $annotation) {
48 | if ($annotation instanceof Middleware) {
49 | $queue[] = $annotation->getClass();;
50 | } elseif ($annotation instanceof Middlewares) {
51 | /** @var Middleware $middleware */
52 | foreach ($annotation->getMiddlewares() as $middleware) {
53 | $queue[] = $middleware->getClass();
54 | }
55 | }
56 | }
57 |
58 | foreach ($reflectionClass->getMethods() as $reflectionMethod) {
59 | $methodAnnotations = $reader->getMethodAnnotations($reflectionMethod);
60 |
61 | foreach ($methodAnnotations AS $annotation) {
62 | $key = "{$class}/{$reflectionMethod->getName()}";
63 |
64 | if (!isset($routes[$key])) {
65 | $routeHelper = new MessageRoute();
66 | foreach ($queue as $mid) {
67 | $routeHelper->addMiddleware(self::getMiddleware($mid));
68 | }
69 | $routes[$key] = $routeHelper;
70 | } else {
71 | /** @var MessageRoute $routeHelper */
72 | $routeHelper = $routes[$key];
73 | }
74 |
75 | if ($annotation instanceof MessageMapping) {
76 | $routeHelper->setRoute($annotation->getRoute());
77 | $routeHelper->setClosure([new $class(), $reflectionMethod->getName()]);
78 | } elseif ($annotation instanceof Middleware) {
79 | $mid = $annotation->getClass();
80 | $routeHelper->addMiddleware(self::getMiddleware($mid));
81 | } elseif ($annotation instanceof Middlewares) {
82 | /** @var Middleware $middleware */
83 | foreach ($annotation->getMiddlewares() as $middleware) {
84 | $mid = $middleware->getClass();
85 | $routeHelper->addMiddleware(self::getMiddleware($mid));
86 | }
87 | }
88 |
89 | $routes[$key] = $routeHelper;
90 | }
91 | }
92 | }
93 | }
94 | self::$middleware = null;
95 | return $routes;
96 | }
97 |
98 | private static function getMiddleware($mid)
99 | {
100 | if (!isset(self::$middleware[$mid])) {
101 | self::$middleware[$mid] = new $mid();
102 | }
103 | return self::$middleware[$mid];
104 | }
105 |
106 |
107 | /**
108 | * 获取目录操作
109 | *
110 | * @param array $namespaces 需要搜索的命名空间
111 | * @return DirectoryHelper
112 | */
113 | protected static function getDirectoryHelper(array $namespaces)
114 | {
115 | $loader = App::getLoader();
116 | $directory = new DirectoryHelper();
117 | $directory->setLoader($loader);
118 | $directory->setScanNamespace($namespaces);
119 | return $directory;
120 | }
121 | }
--------------------------------------------------------------------------------
/react/Providers/RouteServiceProvider.php:
--------------------------------------------------------------------------------
1 | dispatcher = \FastRoute\simpleDispatcher(function (\FastRoute\RouteCollector $route) {
46 | foreach ($this->scanRoute() as $arr) {
47 | /** @var RequestMapping $requestMapping */
48 | $requestMapping = $arr[0];
49 | /** @var RouteHelper $routeHelper */
50 | $routeHelper = $arr[1];
51 | $route->addRoute($requestMapping->getMethod(), $requestMapping->getRoute(), $routeHelper);
52 | }
53 | });
54 | }
55 |
56 | /**
57 | * 所有服务加载后,注册触发,
58 | *
59 | * @return void
60 | */
61 | public function register()
62 | {
63 |
64 | }
65 |
66 | /**
67 | * @return mixed
68 | */
69 | public function getDispatcher()
70 | {
71 | return $this->dispatcher;
72 | }
73 |
74 | private function scanRoute()
75 | {
76 | $loader = App::getLoader();
77 | $directory = new DirectoryHelper();
78 | $directory->setLoader($loader);
79 | $directory->setScanNamespace($this->namespaces);
80 | $reader = new AnnotationReader();
81 | foreach ($directory->scanClass() as $class) {
82 | if (class_exists($class)) {
83 | $reflectionClass = new ReflectionClass($class);
84 | $classAnnotations = $reader->getClassAnnotations($reflectionClass);
85 |
86 | $prefix = "";
87 | $queue = [];
88 | foreach ($classAnnotations AS $annotation) {
89 | if ($annotation instanceof Middleware) {
90 | $queue[] = $annotation->getClass();;
91 | } elseif ($annotation instanceof Middlewares) {
92 | /** @var Middleware $middleware */
93 | foreach ($annotation->getMiddlewares() as $middleware) {
94 | $queue[] = $middleware->getClass();
95 | }
96 | }
97 | }
98 |
99 | foreach ($reflectionClass->getMethods() as $reflectionMethod) {
100 | $methodAnnotations = $reader->getMethodAnnotations($reflectionMethod);
101 |
102 | foreach ($methodAnnotations AS $annotation) {
103 | $key = "{$prefix}/{$class}/{$reflectionMethod->getName()}";
104 |
105 | if (!isset($this->routes[$key])) {
106 | $routeHelper = new RouteHelper();
107 | foreach ($queue as $mid) {
108 | $routeHelper->addMiddleware($this->getMiddleware($mid));
109 | }
110 | $this->routes[$key] = $routeHelper;
111 | } else {
112 | /** @var RouteHelper $routeHelper */
113 | $routeHelper = $this->routes[$key];
114 | }
115 |
116 | if ($annotation instanceof RequestMapping) {
117 | if (!$annotation->getRoute()) {
118 | $tem_1 = explode("\\", $class);
119 | $controllerName = end($tem_1);
120 | $tem_2 = explode('Controller', $controllerName);
121 | $className = reset($tem_2);
122 | $className = strtolower($className);
123 | $annotation->setRoute("{$prefix}/{$className}/{$reflectionMethod->getName()}");
124 | }
125 | $routeHelper->setClosure([new $class(), $reflectionMethod->getName()]);
126 | $this->requestMappingAnnotations[$key] = $annotation;
127 | } elseif ($annotation instanceof Middleware) {
128 | $mid = $annotation->getClass();
129 | $routeHelper->addMiddleware($this->getMiddleware($mid));
130 | } elseif ($annotation instanceof Middlewares) {
131 | /** @var Middleware $middleware */
132 | foreach ($annotation->getMiddlewares() as $middleware) {
133 | $mid = $middleware->getClass();
134 | $routeHelper->addMiddleware($this->getMiddleware($mid));
135 | }
136 | }
137 |
138 | $this->routes[$key] = $routeHelper;
139 | }
140 | }
141 | }
142 | }
143 |
144 | unset($this->middleware);
145 |
146 | foreach ($this->routes as $key => $routeHelper) {
147 | if (!isset($this->requestMappingAnnotations[$key])) break;
148 | yield [$this->requestMappingAnnotations[$key], $routeHelper];
149 | }
150 | }
151 |
152 | private function getMiddleware($mid)
153 | {
154 | if( !isset($this->middleware[$mid]) ){
155 | $this->middleware[$mid] = new $mid();
156 | }
157 | return $this->middleware[$mid];
158 | }
159 | }
--------------------------------------------------------------------------------