{"id":19829681,"url":"https://github.com/workbunny/webman-push-server","last_synced_at":"2025-05-01T14:33:47.386Z","repository":{"id":63422836,"uuid":"567178890","full_name":"workbunny/webman-push-server","owner":"workbunny","description":"🚀🐇 Webman plugin for push server implementation.","archived":false,"fork":false,"pushed_at":"2024-04-22T11:00:50.000Z","size":293,"stargazers_count":42,"open_issues_count":1,"forks_count":5,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-04-22T12:24:51.166Z","etag":null,"topics":["push-server","pusher-channel","webman","workbunny"],"latest_commit_sha":null,"homepage":"https://www.workerman.net/plugin/102","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/workbunny.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2022-11-17T08:37:51.000Z","updated_at":"2024-07-09T12:00:18.970Z","dependencies_parsed_at":"2024-01-12T15:29:16.328Z","dependency_job_id":"96ab083a-81ed-484e-b0f3-c4b75d03380f","html_url":"https://github.com/workbunny/webman-push-server","commit_stats":{"total_commits":78,"total_committers":3,"mean_commits":26.0,"dds":0.08974358974358976,"last_synced_commit":"58a65ea6801a973b2188da7a840c5da1000f85c2"},"previous_names":[],"tags_count":48,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workbunny%2Fwebman-push-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workbunny%2Fwebman-push-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workbunny%2Fwebman-push-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workbunny%2Fwebman-push-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/workbunny","download_url":"https://codeload.github.com/workbunny/webman-push-server/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224262759,"owners_count":17282421,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["push-server","pusher-channel","webman","workbunny"],"created_at":"2024-11-12T11:19:33.967Z","updated_at":"2024-11-12T11:19:34.518Z","avatar_url":"https://github.com/workbunny.png","language":"PHP","readme":"\u003cp align=\"center\"\u003e\u003cimg width=\"260px\" src=\"https://chaz6chez.cn/images/workbunny-logo.png\" alt=\"workbunny\"\u003e\u003c/p\u003e\n\n**\u003cp align=\"center\"\u003eworkbunny/webman-push-server\u003c/p\u003e**\n\n**\u003cp align=\"center\"\u003e🐇  Webman plugin for push server implementation. 🐇\u003c/p\u003e**\n\n\u003cdiv align=\"center\"\u003e\n    \u003ca href=\"https://github.com/workbunny/webman-push-server/actions?query=branch%3Amain\"\u003e\n        \u003cimg src=\"https://github.com/workbunny/webman-push-server/actions/workflows/CI.yml/badge.svg\" alt=\"Build Status\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/workbunny/webman-push-server/releases\"\u003e\n        \u003cimg alt=\"Latest Stable Version\" src=\"https://badgen.net/packagist/v/workbunny/webman-push-server/latest\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/workbunny/webman-push-server/blob/main/composer.json\"\u003e\n        \u003cimg alt=\"PHP Version Require\" src=\"https://badgen.net/packagist/php/workbunny/webman-push-server\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/workbunny/webman-push-server/blob/main/LICENSE\"\u003e\n        \u003cimg alt=\"GitHub license\" src=\"https://badgen.net/packagist/license/workbunny/webman-push-server\"\u003e\n    \u003c/a\u003e\n\u003c/div\u003e\n\n# 说明\n\n- **3.0：全新架构**\n- **2.0：旧版架构，长期技术支持版本（LTS），[点击跳转2.0文档](https://github.com/workbunny/webman-push-server/blob/2.x/README.md)**\n- **1.0：旧版架构，不再维护，请使用2.0 / fork自行维护，[点击跳转1.0文档](https://github.com/workbunny/webman-push-server/blob/1.x/README.md)**\n\n# 简介\n\n- 全新重构的分布式推送服务，更简单的使用，更简单的部署，更简单的代码！\n- 完整且高效的即时通讯服务，支持聊天、在线推送、数字大屏等双向通讯长连接业务场景；\n- 高保真复刻的[Pusher-Channel](https://support.pusher.com/hc/en-us/categories/4411973917585-Channels)，可以利用现有的[Pusher-Channel](https://support.pusher.com/hc/en-us/categories/4411973917585-Channels)客户端，其他语言(Java Swift .NET Objective-C Unity Flutter Android IOS AngularJS等)客户端地址下载地址：\n  https://pusher.com/docs/channels/channels_libraries/libraries/\n- 本项目1.0/2.0版本承接实现了诸多商业项目的即时通讯服务，最高日活连接达到20万+，最久的商业化项目已稳定运行3年，性能与稳定性兼顾；\n- 如遇问题，欢迎 **[issue](https://github.com/workbunny/webman-push-server/issues) \u0026 PR**；\n\n## 架构\n\n- 摒弃了api-service服务需要挂载在Push-server的设计，独立化api-server，性能更好\n- 使用redis Publish/Subscribe 代替workerman/channel作为分布式广播\n- 使用redis Publish/Subscribe 代替HookServer队列作为事件监听中间件\n- 简化Push-server的代码内容\n- 简化了Api逻辑\n\n```\n                                   ┌─────────────┐     2 | 3\n                             ┌───\u003e | Push-server | ─── ─ · ─\n                             |     └─────────────┘     1 | 4 ··· n\n                             |       Hash | register     ↑\n                             |            |          PUB | SUB\n    ┌────────────────────┐ ──┘     ┌──────────────┐ \u003c────┘                     \n    | webman-push-server | ──────\u003e | Redis-server | \n    └────────────────────┘ ──┐     └──────────────┘ \u003c────┐     \n                             |            |          PUB | SUB\n                             |       Hash | register     ↓\n                             |      ┌────────────┐     2 | 3\n                             └────\u003e | API-server | ─── ─ · ─\n                                    └────────────┘     1 | 4 ··· n\n                                     \n```\n\n## 约定\n\n### 配置说明\n\n配置信息及对应功能在代码注释中均有解释，详见对应代码注释；\n\n```\n|-- config\n    |-- plugin\n        |-- webman-push-server\n            |-- app.php         # 主配置信息\n            |-- bootstrap.php   # 自动加载\n            |-- command.php     # 支持命令\n            |-- log.php         # 日志配置\n            |-- middlewares.php # 基础中间件\n            |-- process.php     # 启动进程\n            |-- redis.php       # redis配置\n            |-- route.php       # APIs路由信息\n            |-- registrar.php   # 分布式服务注册器配置\n```\n\n### 频道说明\n\n#### push-server支持以下三种频道类型：\n\n- 公共频道（public）：**客户端仅可监听公共频道，不可向公共频道推送消息；**\n- 私有频道（private）：客户端可向私有频道推送/监听，一般用于端对端的通讯，服务端仅做转发；**该频道可以用于私聊场景；**\n- 状态频道（presence）：与私有频道保持一致，区别在于状态频道还保存有客户端的信息，任何用户的上下线都会收到该频道的广播通知，如user_id、user_info；\n**状态频道最多支持100个客户端（客户端限制，实际上可以放开）；**\n\n### 事件说明\n\n#### 1. 默认 event 遵守以下的约定规范：\n\n- **client-** 前缀的事件：拥有 **client-** 前缀的事件是客户端发起的事件，客户端在推送消息时一定会带有该前缀；\n- **pusher:** 前缀的事件：拥有 **pusher:** 前缀的事件一般用于服务端消息、公共消息，比如在公共频道由服务端推送的消息、客户端发起的订阅公共消息；\n- **pusher_internal:** 前缀的事件：拥有 **pusher_internal:** 前缀的事件是服务端的回执通知，一般是由客户端发起订阅、取消订阅等操作时，由服务端回执的事件信息带有该前缀的事件；\n\n#### 2. event支持自定义注册\n\n# 使用\n\n## 服务端\n\n### 1. 环境依赖\n\n- **php \u003e=8.0**\n- **webman \u003e= 1.0**\n- **redis \u003e= 5.0**\n\n### 2. 安装使用\n\n- 使用composer安装\n\n```\ncomposer require workbunny/webman-push-server\n```\n\n- webman框架自动加载配置\n- 在config/plugin/workbunny/webman-push-server/中配置对应文件\n- webman启动\n\n### 3. 服务说明\n\n#### push-server服务\n\n- push-server服务用于监听websocket消息，是实现即时通讯功能的主要服务\n- push-server服务支持多进程，通讯方式及基础数据储存方式为redis\n- config/plugin/workbunny/webman-push-server/process.php中可调节启动进程数，默认为cpu count\n- config/plugin/workbunny/webman-push-server/app.php中可配置心跳等参数\n- config/plugin/workbunny/webman-push-server/redis.php中可配置redis连接信息\n- config/plugin/workbunny/webman-push-server/middlewares.php中可配置push-server消息中间件，可用于消息的拦截、过滤、路由等\n\n#### api-server服务\n\n- api-server服务用于监听http/https消息，对外提供REST风格的open-apis，API服务提供REST风格的http-APIs，接口内容与 [pusher-channel-api](https://pusher.com/docs/channels/library_auth_reference/rest-api/) 基本保持一致\n- config/plugin/workbunny/webman-push-server/process.php中可调节启动进程数，默认为cpu count\n- config/plugin/workbunny/webman-push-server/app.php中可配置流量统计间隔等参数\n- config/plugin/workbunny/webman-push-server/route.php中为基础open-apis的实现\n- config/plugin/workbunny/webman-push-server/middlewares.php中可配置api-server消息中间件，可用于消息的拦截、过滤、路由等\n\n##### open-apis列表：\n\n| method | url                                                  | 描述                                                                                                                               |\n|:-------|:-----------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------|\n| POST   | /apps/[app_id]/events                                | [对应的pusher文档地址](https://pusher.com/docs/channels/library_auth_reference/rest-api/#post-event-trigger-an-event)                   |\n| POST   | /apps/[app_id]/batch_events                          | [对应的pusher文档地址](https://pusher.com/docs/channels/library_auth_reference/rest-api/#post-batch-events-trigger-multiple-events)     |\n| GET    | /apps/[app_id]/channels                              | [对应的pusher文档地址](https://pusher.com/docs/channels/library_auth_reference/rest-api/#get-channels-fetch-info-for-multiple-channels) |\n| GET    | /apps/[app_id]/channels/[channel_name]               | [对应的pusher文档地址](https://pusher.com/docs/channels/library_auth_reference/rest-api/#get-channel-fetch-info-for-one-channel)        |\n| POST   | /apps/[app_id]/users/[user_id]/terminate_connections | [对应的pusher文档地址](https://pusher.com/docs/channels/library_auth_reference/rest-api/#post-terminate-user-connections)               |\n| GET    | /apps/[app_id]/channels/[channel_name]/users         | [对应的pusher文档地址](https://pusher.com/docs/channels/library_auth_reference/rest-api/#get-users)                                     |\n\n## 客户端\n\n### javascript客户端\n\n#### 1. 安装\n\n- 引入\n\n```javascript\n\u003cscript src=\"/plugin/workbunny/webman-push-server/push.js\"\u003e \u003c/script\u003e\n```\n\n- 创建连接\n\n**TIps：每 new 一个 Push 会创建一个连接。**\n\n```javascript\n// 建立连接\nvar connection = new Push({\n    url: 'ws://127.0.0.1:8001', // websocket地址\n    app_key: '\u003capp_key\u003e', // 在config/plugin/workbunny/webman-push-server/app.php里配置\n});\n```\n\n#### 2.客户端订阅公共频道\n\n**TIps：频道和事件可以是任意符合约定前缀的字符串，不需要服务端预先配置。**\n\n```javascript\n// 建立连接\nvar connection = new Push({\n    url: 'ws://127.0.0.1:8001', // websocket地址\n    app_key: '\u003capp_key\u003e', // 在config/plugin/workbunny/webman-push-server/app.php里配置\n});\n\n// 监听 public-test 公共频道\nvar user_channel = connection.subscribe('public-test');\n\n// 当 public-test 频道有message事件的消息回调\nuser_channel.on('message', function(data) {\n    // data里是消息内容\n    console.log(data);\n});\n// 取消监听 public-test 频道\nconnection.unsubscribe('public-test')\n// 取消所有频道的监听\nconnection.unsubscribeAll()\n```\n\n#### 3.客户端订阅私有/状态频道\n\n**Tips：您需要先实现用于鉴权的接口服务**\n\n- 私有频道\n\n**Tips：样例鉴权接口详见 config/plugin/workbunny/webman-push-server/route.php**\n\n```javascript\n// 订阅发生前，浏览器会发起一个ajax鉴权请求(ajax地址为new Push时auth参数配置的地址)，开发者可以在这里判断，当前用户是否有权限监听这个频道。这样就保证了订阅的安全性。\nvar connection = new Push({\n    url: 'ws://127.0.0.1:8001', // websocket地址\n    app_key: '\u003capp_key\u003e',\n    auth: 'http://127.0.0.1:8002/subscribe/auth' // 该接口是样例接口，请根据源码自行实现业务\n});\n// 监听 private-test 私有频道\nvar user_channel = connection.subscribe('private-test');\n// 当 private-test 频道有message事件的消息回调\nuser_channel.on('message', function(data) {\n    // data里是消息内容\n    console.log(data);\n});\n// 取消监听 private-test 频道\nconnection.unsubscribe('private-test')\n// 取消所有频道的监听\nconnection.unsubscribeAll()\n```\n\n- 状态频道\n  \n**Tips：样例鉴权接口详见 config/plugin/workbunny/webman-push-server/route.php**\n\n- 方法一\n\n```javascript\n// 方法一\n\n// 订阅发生前，浏览器会发起一个ajax鉴权请求(ajax地址为new Push时auth参数配置的地址)，开发者可以在这里判断，当前用户是否有权限监听这个频道。这样就保证了订阅的安全性。\nvar connection = new Push({\n    url: 'ws://127.0.0.1:8001', // websocket地址\n    app_key: '\u003capp_key\u003e',\n    auth: 'http://127.0.0.1:8002/subscribe/auth' // 该接口是样例接口，请根据源码自行实现业务\n});\n```\n\n- 方法二\n\n```javascript\n// 方法二\n\n// 先通过接口查询获得用户信息，组装成如下\nvar channel_data = {\n    user_id: '100',\n    user_info: \"{\\'name\\':\\'John\\',\\'sex\\':\\'man\\'}\"\n}\n// 订阅发生前，浏览器会发起一个ajax鉴权请求(ajax地址为new Push时auth参数配置的地址)，开发者可以在这里判断，当前用户是否有权限监听这个频道。这样就保证了订阅的安全性。\nvar connection = new Push({\n    url: 'ws://127.0.0.1:8001', // websocket地址\n    app_key: '\u003capp_key\u003e',\n    auth: 'http://127.0.0.1:8002/subscribe/auth', // 该接口是样例接口，请根据源码自行实现业务\n    channel_data: channel_data\n});\n\n// 监听 presence-test 状态频道\nvar user_channel = connection.subscribe('presence-test');\n// 当 presence-test 频道有message事件的消息回调\nuser_channel.on('message', function(data) {\n    // data里是消息内容\n    console.log(data);\n});\n// 取消监听 presence-test 频道\nconnection.unsubscribe('presence-test')\n// 取消所有频道的监听\nconnection.unsubscribeAll()\n```\n\n#### 4.客户端推送\n\n##### Tips：\n\n- **客户端间推送仅支持私有频道(private-)/状态频道（presence-），并且客户端只能触发以 client- 开头的事件。**\n客户端触发事件推送的例子\n- **以下代码给所有订阅了 private-user-1 的客户端推送 client-message 事件的数据，而当前客户端不会收到自己的推送消息**\n\n```javascript\n// 以上省略\n\n// 私有频道\nvar user_channel = connection.subscribe('private-user-1');\nuser_channel.on('client-message', function (data) {\n//\n});\nuser_channel.trigger('client-message', {form_uid:2, content:\"hello\"});\n\n// 状态频道\nvar user_channel = connection.subscribe('presence-user-1');\nuser_channel.on('client-message', function (data) {\n//\n});\nuser_channel.trigger('client-message', {form_uid:2, content:\"hello\"});\n```\n\n#### 5. wss代理(SSL)\n\n- https下无法使用ws连接，需要使用wss连接。这种情况可以使用nginx代理wss，配置类似如下：\n\n```\nserver {\n# .... 这里省略了其它配置 ...\n\n    location /app\n    {\n        proxy_pass http://127.0.0.1:3131;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"Upgrade\";\n        proxy_set_header X-Real-IP $remote_addr;\n    }\n}\n```\n\n- 重启nginx后，使用以下方式连接服务端\n\n```javascript\nvar connection = new Push({\n    url: 'wss://example.com',\n    app_key: '\u003capp_key\u003e'\n});\n```\n\n##### Tips：\n**wss开头，不写端口，必须使用ssl证书对应的域名连接**\n\n---\n\n### websocket-php客户端\n\n#### 1. 创建连接\n\n```php\nuse Workbunny\\WebmanPushServer\\WsClient;\nuse Workerman\\Connection\\AsyncTcpConnection;\nuse Workbunny\\WebmanPushServer\\EVENT_SUBSCRIBE;\nuse Workbunny\\WebmanPushServer\\EVENT_SUBSCRIPTION_SUCCEEDED;\n\n// 创建连接\n$client = WsClient::instance('127.0.0.1:8001', [\n    'app_key'        =\u003e 'workbunny',\n    'heartbeat'      =\u003e 60,\n    'auth'           =\u003e 'http://127.0.0.1:8002/subscribe/auth',\n    'channel_data'   =\u003e []  // channel_data\n    'query'          =\u003e [], // query\n    'context_option' =\u003e []\n])\n// 建立连接\n$client-\u003econnect();\n// 关闭连接\n$client-\u003edisconnect();\n```\n\n#### 2. 订阅/退订\n\n```php\nuse Workbunny\\WebmanPushServer\\WsClient;\nuse Workerman\\Connection\\AsyncTcpConnection;\n\n// 创建连接\n$client = WsClient::instance('127.0.0.1:8001', [\n    'app_key'        =\u003e 'workbunny',\n    'heartbeat'      =\u003e 60,\n    'auth'           =\u003e 'http://127.0.0.1:8002/subscribe/auth',\n    'channel_data'   =\u003e []  // channel_data\n    'query'          =\u003e [], // query\n    'context_option' =\u003e []\n])\n\n// 订阅一个私有通道，订阅成功后会执行回调函数\n$client-\u003esubscribe('private-test', function (AsyncTcpConnection $connection, array $data) {\n    // 订阅成功后打印\n    dump($data);\n});\n// 订阅一个私有通道，不注册订阅成功后的回调\n$client-\u003esubscribe('private-test');\n\n// 取消订阅一个私有通道\n$client-\u003eunsubscribe('private-test', function (AsyncTcpConnection $connection, array $data) {\n    // 取消订阅成功后打印\n    dump($data);\n});\n// 取消订阅一个私有通道，不注册订阅成功后的回调\n$client-\u003eunsubscribe('private-test');\n\n// 取消全部订阅\n$client-\u003eunsubscribeAll();\n```\n\n#### 3. 触发消息\n\n```php\n// 向 private-test 通道发送 client-test 事件消息\n$client-\u003etrigger('private-test', 'client-test', [\n    'message' =\u003e 'hello workbunny!'\n]);\n\n// 向 presence-test 通道发送 client-test 事件消息\n$client-\u003etrigger('presence-test', 'client-test', [\n    'message' =\u003e 'hello workbunny!'\n]);\n\n// 事件不带 client- 前缀会抛出RuntimeException\ntry {\n    $client-\u003etrigger('presence-test', 'test', [\n        'message' =\u003e 'hello workbunny!'\n    ]);\n} catch (RuntimeException $exception){\n    dump($exception);\n}\n```\n\n#### 4. 事件注册回调\n\n```php\nuse Workerman\\Connection\\AsyncTcpConnection;\n\n// 注册关注private-test通道的client-test事件\n$client-\u003eeventOn('private-test', 'client-test', function(AsyncTcpConnection $connection, array $data) {\n    // 打印事件数据\n    dump($data);\n});\n// 取消关注private-test通道的client-test事件\n$client-\u003eeventOff('private-test', 'client-test');\n\n// 获取所有注册事件回调\n$client-\u003egetEvents();\n```\n\n#### 5. 其他\n\n```php\n\n// 获取客户端id，当连接创建前该方法返回null\n$client-\u003egetSocketId();\n\n// 获取已订阅通道，订阅触发前该方法返回空数组\n$client-\u003egetChannels();\n\n// 发布消息\n$client-\u003epublish();\n\n// 更多详见 WsClient.php\n```\n\n---\n\n### open-apis-php客户端\n\n#### 1. 安装\n\n1. 或者使用\\Workbunny\\WebmanPushServer\\ApiClient **【建议使用】**\n\n    ```\n    composer require workbunny/webman-push-server\n    ```\n\n2. 使用pusher提供的api客户端 **【不建议使用，客户端请求没有使用keep-alive】**\n\n    ```\n    composer require pusher/pusher-php-server\n    ```\n\n#### 2. 推送\n\n```php\nuse Workbunny\\WebmanPushServer\\ApiClient;\n\ntry {\n    $pusher = new ApiClient(\n        'APP_KEY', \n        'APP_SECRET',\n        'APP_ID',\n        [\n            'host'       =\u003e\"http://127.0.0.1:8001\",\n            'timeout'    =\u003e 60,\n            'keep-alive' =\u003e true\n        ]\n    );\n    $pusher-\u003etrigger(\n        // 频道（channel）支持多个通道\n        [\"private-d\"], \n        // 事件\n        \"client-a\", \n        // 消息体\n        [\n            'message' =\u003e 'hello workbunny!'\n        ],\n        // query\n        []\n    );\n} catch (GuzzleException|ApiErrorException|PusherException $e) {\n    dump($e);\n}\n```\n\n#### 3. 其他功能详见open-apis列表\n\n---\n\n\n### 其他客户端\n\n- 兼容pusher，其他语言(Java Swift .NET Objective-C Unity Flutter Android IOS AngularJS等)客户端地址下载地址：\nhttps://pusher.com/docs/channels/channels_libraries/libraries/\n\n---\n\n---\n\n## 进阶用法\n\n### 1. push-server中间件服务\n\n在一些服务器监控场景下，我们需要获取全量的往来信息，包括客户端的消息和服务端的回执等\n\n- 创建一个中间件服务类，use引入ChannelMethods\n\n```php\n\u003c?php declare(strict_types=1);\n\nnamespace YourNamespace;\n\nuse Workbunny\\WebmanPushServer\\Traits\\ChannelMethods;\n\nclass PushServerMiddleware\n{\n    use ChannelMethods;\n\n    /** @inheritDoc */\n    public static function _subscribeResponse(string $type, array $data): void\n    {\n        // TODO\n    }\n}\n```\n\n- 客户端与服务端的任何通讯消息会触达_subscribeResponse方法，请在_subscribeResponse方法中实现对应业务逻辑，入日志等；\n\n- 在项目config/process.php或config/plugin/workbunny/webman-push-server/process.php中添加配置\n\n```php\n    // push-server-middleware\n    'push-server-middleware' =\u003e [\n        'handler'     =\u003e YourNamespace\\PushServerMiddleware::class,\n        'count'       =\u003e 1,\n    ],\n```\n\n- 启动webman即可\n\n#### Tips：\n\n- 中间件切记保持单进程运行，本质上是与push-server进程组监听同一个内部通讯通道\n- _subscribeResponse方法中请勿执行耗时操作，否则将影响性能，建议异步执行，如投送到队列进行消费\n- _subscribeResponse中type为client时为客户端消息，type为server时为服务端回执消息，其他则详见[AbstractPublishType.php](src/PublishTypes/AbstractPublishType.php)\n- 该中间件更适合作为监控服务或者日志服务，如果作为拦截器等服务，可能存在调用链路较长的问题\n- 样例查看，[PushServerMiddleware.php](tests/Examples/PushServerMiddleware.php)\n\n### 2. push-server onMessage中间件\n\n我们在使用过程中可能需要为push-server的onMessage做一些安全性考虑或者数据过滤和拦截的功能，那么消息中间件非常适合该场景\n\n- 以拦截非websocket协议消息距离\n- 在config/plugin/workbunny/webman-push-server/middlewares.php中添加中间件回调函数\n\n```php\n    // push server root middlewares\n    'push-server' =\u003e [\n        // 以拦截非websocket消息举例\n        function (Closure $next, TcpConnection $connection, $data): void\n        {\n            // 拦截非websocket服务消息\n            if (!$connection-\u003eprotocol instanceof \\Workerman\\Protocols\\Websocket) {\n                $connection-\u003eclose('Not Websocket');\n                return;\n            }\n            $next($connection, $data);\n        }\n    ],\n```\n\n- 启动webman即可\n\n#### Tips：\n\n- push-server onMessage中间件由于传递了connection对象，所以我们可以使用PushServer类中针对connection操作的所有方法，无需使用open-apis等进行回执\n- onMessage中间件可以使用例子中的Closure匿名函数方式，也可以使用任意callable函数，也可以使用类方法，只需要满足实例的入参和出参即可\n\n### 3. 自定义事件响应\n\n我们在使用过程中，可能需要自定义事件响应客户端的消息，那么我们可以创建一个自定义响应类\n\n- 创建自定义响应类\n\n```php\n\u003c?php declare(strict_types=1);\n\nnamespace Tests\\Examples;\n\nuse Workbunny\\WebmanPushServer\\Events\\AbstractEvent;\nuse Workerman\\Connection\\TcpConnection;\n\nclass OtherEvent extends AbstractEvent\n{\n    /**\n     * @inheritDoc\n     */\n    public function response(TcpConnection $connection, array $request): void\n    {\n        // todo\n    }\n}\n```\n\n- 在服务启动前注册该相应类，注册方法可以放在webman的bootstrap中\n\n```php\n\\Workbunny\\WebmanPushServer\\Events\\AbstractEvent::register('other', \\Tests\\Examples\\OtherEvent::class);\n```\n\n- 启动webman即可\n- 当合法客户端发送event=other时，将会触发该事件响应\n\n#### Tips：\n\n- response传递了connection对象及request对象，所以我们可以使用PushServer类中针对connection操作的所有方法，无需使用open-apis等进行回执\n- 样例查看，[OtherEvent.php](tests/Examples/OtherEvent.php)\n\n### 4. 自定义内部广播事件\n\n内部广播默认存在client事件和server事件，push-server默认只会响应该两种事件，如果我们需要对其他额外的内部事件进行处理时可使用该方案\n\n- 创建自定义内部广播事件\n\n```php\n\u003c?php declare(strict_types=1);\n\nnamespace Tests\\Examples;\n\nuse Workbunny\\WebmanPushServer\\PublishTypes\\AbstractPublishType;\n\nclass OtherType extends AbstractPublishType\n{\n\n    /** @inheritDoc */\n    public static function response(array $data): void\n    {\n        static::verify($data, [\n            ['appKey', 'is_string', true],\n            ['channel', 'is_string', true],\n            ['event', 'is_string', true],\n            ['socketId', 'is_string', false]\n        ]);\n        // todo\n    }\n}\n```\n\n- 在服务启动前注册该相应类，注册方法可以放在webman的bootstrap中\n\n```php\n\\Workbunny\\WebmanPushServer\\PublishTypes\\AbstractPublishType::register('other', \\Tests\\Examples\\OtherType::class);\n```\n\n- 启动webman即可\n- 当使用内部广播发送type=other时，将会触发该事件响应\n\n```php\n\\Workbunny\\WebmanPushServer\\PushServer::publish('other', [\n    'a' =\u003e 'a'\n])\n```\n\n#### Tips：\n- 样例查看，[OtherType.php](tests/Examples/OtherType.php)\n\n### 5. 高阶部署\n\n#### 分布式部署\n\n- 在不同的服务项目中引入该插件\n- 配置redis指向同一个redis服务\n- 启动所有服务项目即可\n\n#### push-server api-server分离部署\n\n- 在A服务项目中配置config/plugin/workbunny/webman-push-server/process.php中注释api-server进程配置\n- 在B服务项目中配置config/plugin/workbunny/webman-push-server/process.php中注释push-server进程配置\n- 分别启动A、B服务即可\n\n#### Tips：\n- 分布式部署与分离式部署可以相互结合，达到最小颗粒度的部署\n- redis配置中可以独立配置storage与channel，以达到最高性能\n\n### 6. 二次开发\n\n在一些场景下，我们可能需要对push-server进行二次开发，那么我们可以使用组合式拓展开发，以实现对push-server的拓展\n\n- 创建自定义push-server类\n- 以PushServer为样例，引入Traits并实现其方法；或者继承PushServer类进行方法重写\n- 修改process启动配置，将push-server替换为自定义push-server类\n- 启动webman即可","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fworkbunny%2Fwebman-push-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fworkbunny%2Fwebman-push-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fworkbunny%2Fwebman-push-server/lists"}