PHPackages                             workbunny/webman-push-server - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. workbunny/webman-push-server

ActiveLibrary

workbunny/webman-push-server
============================

Webman plugin workbunny/webman-push-server

3.2.1(6mo ago)6962117MITPHPPHP &gt;=8.0CI passing

Since Nov 30Pushed 6mo ago2 watchersCompare

[ Source](https://github.com/workbunny/webman-push-server)[ Packagist](https://packagist.org/packages/workbunny/webman-push-server)[ RSS](/packages/workbunny-webman-push-server/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (11)Versions (73)Used By (0)

[![workbunny](https://camo.githubusercontent.com/e2b1164338390ab45783434659e3e419e0c3b50fbe140c697ba1f82f59015ad6/68747470733a2f2f6368617a366368657a2e636e2f696d616765732f776f726b62756e6e792d6c6f676f2e706e67)](https://camo.githubusercontent.com/e2b1164338390ab45783434659e3e419e0c3b50fbe140c697ba1f82f59015ad6/68747470733a2f2f6368617a366368657a2e636e2f696d616765732f776f726b62756e6e792d6c6f676f2e706e67)

**workbunny/webman-push-server**

**🐇 Webman plugin for push server implementation. 🐇**

 [ ![Build Status](https://github.com/workbunny/webman-push-server/actions/workflows/CI.yml/badge.svg) ](https://github.com/workbunny/webman-push-server/actions?query=branch%3Amain) [ ![Latest Stable Version](https://camo.githubusercontent.com/f7c52585b5c8fed2e2b547f33ef70ad80d25a22a934a2eb4a5d3e7edaeadda88/68747470733a2f2f62616467656e2e6e65742f7061636b61676973742f762f776f726b62756e6e792f7765626d616e2d707573682d7365727665722f6c6174657374) ](https://github.com/workbunny/webman-push-server/releases) [ ![PHP Version Require](https://camo.githubusercontent.com/8057cea673f17a7b7edf045c71efd905280d0e42d32e2e71d43efe512c281738/68747470733a2f2f62616467656e2e6e65742f7061636b61676973742f7068702f776f726b62756e6e792f7765626d616e2d707573682d736572766572) ](https://github.com/workbunny/webman-push-server/blob/main/composer.json) [ ![GitHub license](https://camo.githubusercontent.com/e848f186f17ec4546712ac99127f3f2a54467c0e03b002835d1ffcd76ddc4f84/68747470733a2f2f62616467656e2e6e65742f7061636b61676973742f6c6963656e73652f776f726b62756e6e792f7765626d616e2d707573682d736572766572) ](https://github.com/workbunny/webman-push-server/blob/main/LICENSE)

说明
==

[](#说明)

- **3.0：全新架构 【推荐】**
- **2.0：旧版架构 LTS版本 | [点击跳转2.0文档](https://github.com/workbunny/webman-push-server/blob/2.x/README.md)**
- **1.0：旧版架构，不再维护，请使用2.0 / fork自行维护 | [点击跳转1.0文档](https://github.com/workbunny/webman-push-server/blob/1.x/README.md)**

简介
==

[](#简介)

- 全新重构的分布式推送服务，更高的性能，更简单的使用，更简单的部署，更简单的代码！
- 完整且高效的即时通讯服务，支持聊天、在线推送、数字大屏等双向通讯长连接业务场景；
- 高保真复刻的[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等)客户端地址下载地址： [https://pusher.com/docs/channels/channels\_libraries/libraries/](https://pusher.com/docs/channels/channels_libraries/libraries/)
- 本项目承接实现了诸多商业项目的即时通讯服务，最高日活连接达到20万+，最久的商业化项目已稳定运行3年+，性能与稳定性兼顾；
- 3.0与2.0相比，具备更低的广播延迟（上下界减少8%），具备更高的承载能力（QPS提升12%），具备更多样的部署方案和更多样的拓展开发能力；
- 如遇问题，欢迎 **[issue](https://github.com/workbunny/webman-push-server/issues) &amp; PR**；

架构
--

[](#架构)

```
                                   ┌─────────────┐     2 | 3
     S: Storage              ┌───> | Push-server | ─── ─ · ─
     C: Channel              |     └─────────────┘     1 | 4 ··· n
     R: Registrar            |       Hash | register     ↑
                             |            |          PUB | SUB
    ┌────────────────────┐ ──┘      ┌───────────┐  | S / C / R |
    └────────────────────┘ ──┐      └───────────┘  | API-server | ─── ─ · ─
                                    └────────────┘     1 | 4 ··· n

```

- Push-server: 推送服务，基于`websocket`通讯协议的推送服务器
- API-server: API服务，基于`http`通讯协议提供简单的`API`管理接口，如：订阅、取消订阅、广播、获取在线人数等
- Storage: 储存器，用于保存数据信息；默认使用`Redis`作为储存器；提供`StorageInterface`拓展
- Channel: 通道，用于保存订阅信息；默认使用`Redis`作为通道；提供`ChannelInterface`拓展
- Registrar: 服务注册器，用于服务注册与发现；默认使用`Redis`作为服务注册器；提供`RegistrarInterface`拓展

> version&gt;=3.2.0 支持`S/C/R`部分的拓展能力

约定
--

[](#约定)

### 配置说明

[](#配置说明)

配置信息及对应功能在代码注释中均有解释，详见对应代码注释；

```
|-- config
    |-- plugin
        |-- webman-push-server
            |-- app.php         # 主配置信息
            |-- bootstrap.php   # 自动加载
            |-- command.php     # 支持命令
            |-- log.php         # 日志配置
            |-- middlewares.php # 基础中间件
            |-- process.php     # 启动进程
            |-- redis.php       # redis配置
            |-- route.php       # APIs路由信息
            |-- registrar.php   # 分布式服务注册器配置
            |-- storage.php     # 储存器配置
            |-- channel.php     # 订阅通道配置

```

### 频道说明

[](#频道说明)

#### push-server支持以下三种频道类型：

[](#push-server支持以下三种频道类型)

- 公共频道（public）：**客户端仅可监听公共频道，不可向公共频道推送消息；**
- 私有频道（private）：客户端可向私有频道推送/监听，一般用于端对端的通讯，服务端仅做转发；**该频道可以用于私聊场景；**
- 状态频道（presence）：与私有频道保持一致，区别在于状态频道还保存有客户端的信息，任何用户的上下线都会收到该频道的广播通知，如user\_id、user\_info； **状态频道最多支持100个客户端（客户端限制，实际上可以放开）；**

### 事件说明

[](#事件说明)

#### 1. 默认 event 遵守以下的约定规范：

[](#1-默认-event-遵守以下的约定规范)

- **client-** 前缀的事件：拥有 **client-** 前缀的事件是客户端发起的事件，客户端在推送消息时一定会带有该前缀；
- **pusher:** 前缀的事件：拥有 **pusher:** 前缀的事件一般用于服务端消息、公共消息，比如在公共频道由服务端推送的消息、客户端发起的订阅公共消息；
- **pusher\_internal:** 前缀的事件：拥有 **pusher\_internal:** 前缀的事件是服务端的回执通知，一般是由客户端发起订阅、取消订阅等操作时，由服务端回执的事件信息带有该前缀的事件；

#### 2. event支持自定义注册

[](#2-event支持自定义注册)

使用
==

[](#使用)

服务端
---

[](#服务端)

### 1. 环境依赖

[](#1-环境依赖)

- **php &gt;=8.0**
- **webman &gt;= 1.0**
- **redis &gt;= 5.0**

### 2. 安装使用

[](#2-安装使用)

- 使用composer安装

```
composer require workbunny/webman-push-server

```

- webman框架自动加载配置
- 在config/plugin/workbunny/webman-push-server/中配置对应文件
- webman启动

### 3. 服务说明

[](#3-服务说明)

#### push-server服务

[](#push-server服务)

- push-server服务用于监听websocket消息，是实现即时通讯功能的主要服务
- push-server服务支持多进程，通讯方式及基础数据储存方式为redis
- config/plugin/workbunny/webman-push-server/process.php中可调节启动进程数，默认为cpu count
- config/plugin/workbunny/webman-push-server/app.php中可配置心跳等参数
- config/plugin/workbunny/webman-push-server/redis.php中可配置redis连接信息
- config/plugin/workbunny/webman-push-server/middlewares.php中可配置push-server消息中间件，可用于消息的拦截、过滤、路由等

#### api-server服务

[](#api-server服务)

- api-server服务用于监听http/https消息，对外提供REST风格的open-apis，API服务提供REST风格的http-APIs，接口内容与 [pusher-channel-api](https://pusher.com/docs/channels/library_auth_reference/rest-api/) 基本保持一致
- config/plugin/workbunny/webman-push-server/process.php中可调节启动进程数，默认为cpu count
- config/plugin/workbunny/webman-push-server/app.php中可配置流量统计间隔等参数
- config/plugin/workbunny/webman-push-server/route.php中为基础open-apis的实现
- config/plugin/workbunny/webman-push-server/middlewares.php中可配置api-server消息中间件，可用于消息的拦截、过滤、路由等

##### open-apis列表：

[](#open-apis列表)

methodurl描述POST/apps/\[app\_id\]/events[对应的pusher文档地址](https://pusher.com/docs/channels/library_auth_reference/rest-api/#post-event-trigger-an-event)POST/apps/\[app\_id\]/batch\_events[对应的pusher文档地址](https://pusher.com/docs/channels/library_auth_reference/rest-api/#post-batch-events-trigger-multiple-events)GET/apps/\[app\_id\]/channels[对应的pusher文档地址](https://pusher.com/docs/channels/library_auth_reference/rest-api/#get-channels-fetch-info-for-multiple-channels)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)POST/apps/\[app\_id\]/users/\[user\_id\]/terminate\_connections[对应的pusher文档地址](https://pusher.com/docs/channels/library_auth_reference/rest-api/#post-terminate-user-connections)GET/apps/\[app\_id\]/channels/\[channel\_name\]/users[对应的pusher文档地址](https://pusher.com/docs/channels/library_auth_reference/rest-api/#get-users)客户端
---

[](#客户端)

### javascript客户端

[](#javascript客户端)

#### 1. 安装

[](#1-安装)

- 引入

```

```

- 创建连接

**TIps：每 new 一个 Push 会创建一个连接。**

```
// 建立连接
var connection = new Push({
    url: 'ws://127.0.0.1:8001', // websocket地址
    app_key: '', // 在config/plugin/workbunny/webman-push-server/app.php里配置
});
```

#### 2.客户端订阅公共频道

[](#2客户端订阅公共频道)

**TIps：频道和事件可以是任意符合约定前缀的字符串，不需要服务端预先配置。**

```
// 建立连接
var connection = new Push({
    url: 'ws://127.0.0.1:8001', // websocket地址
    app_key: '', // 在config/plugin/workbunny/webman-push-server/app.php里配置
});

// 监听 public-test 公共频道
var user_channel = connection.subscribe('public-test');

// 当 public-test 频道有message事件的消息回调
user_channel.on('message', function(data) {
    // data里是消息内容
    console.log(data);
});
// 取消监听 public-test 频道
connection.unsubscribe('public-test')
// 取消所有频道的监听
connection.unsubscribeAll()
```

#### 3.客户端订阅私有/状态频道

[](#3客户端订阅私有状态频道)

**Tips：您需要先实现用于鉴权的接口服务**

- 私有频道

**Tips：样例鉴权接口详见 config/plugin/workbunny/webman-push-server/route.php**

```
// 订阅发生前，浏览器会发起一个ajax鉴权请求(ajax地址为new Push时auth参数配置的地址)，开发者可以在这里判断，当前用户是否有权限监听这个频道。这样就保证了订阅的安全性。
var connection = new Push({
    url: 'ws://127.0.0.1:8001', // websocket地址
    app_key: '',
    auth: 'http://127.0.0.1:8002/subscribe/auth' // 该接口是样例接口，请根据源码自行实现业务
});
// 监听 private-test 私有频道
var user_channel = connection.subscribe('private-test');
// 当 private-test 频道有message事件的消息回调
user_channel.on('message', function(data) {
    // data里是消息内容
    console.log(data);
});
// 取消监听 private-test 频道
connection.unsubscribe('private-test')
// 取消所有频道的监听
connection.unsubscribeAll()
```

- 状态频道

**Tips：样例鉴权接口详见 config/plugin/workbunny/webman-push-server/route.php**

- 方法一

```
// 方法一

// 订阅发生前，浏览器会发起一个ajax鉴权请求(ajax地址为new Push时auth参数配置的地址)，开发者可以在这里判断，当前用户是否有权限监听这个频道。这样就保证了订阅的安全性。
var connection = new Push({
    url: 'ws://127.0.0.1:8001', // websocket地址
    app_key: '',
    auth: 'http://127.0.0.1:8002/subscribe/auth' // 该接口是样例接口，请根据源码自行实现业务
});
```

- 方法二

```
// 方法二

// 先通过接口查询获得用户信息，组装成如下
var channel_data = {
    user_id: '100',
    user_info: "{\'name\':\'John\',\'sex\':\'man\'}"
}
// 订阅发生前，浏览器会发起一个ajax鉴权请求(ajax地址为new Push时auth参数配置的地址)，开发者可以在这里判断，当前用户是否有权限监听这个频道。这样就保证了订阅的安全性。
var connection = new Push({
    url: 'ws://127.0.0.1:8001', // websocket地址
    app_key: '',
    auth: 'http://127.0.0.1:8002/subscribe/auth', // 该接口是样例接口，请根据源码自行实现业务
    channel_data: channel_data
});

// 监听 presence-test 状态频道
var user_channel = connection.subscribe('presence-test');
// 当 presence-test 频道有message事件的消息回调
user_channel.on('message', function(data) {
    // data里是消息内容
    console.log(data);
});
// 取消监听 presence-test 频道
connection.unsubscribe('presence-test')
// 取消所有频道的监听
connection.unsubscribeAll()
```

#### 4.客户端推送

[](#4客户端推送)

##### Tips：

[](#tips)

- **客户端间推送仅支持私有频道(private-)/状态频道（presence-），并且客户端只能触发以 client- 开头的事件。**客户端触发事件推送的例子
- **以下代码给所有订阅了 private-user-1 的客户端推送 client-message 事件的数据，而当前客户端不会收到自己的推送消息**

```
// 以上省略

// 私有频道
var user_channel = connection.subscribe('private-user-1');
user_channel.on('client-message', function (data) {
//
});
user_channel.trigger('client-message', {form_uid:2, content:"hello"});

// 状态频道
var user_channel = connection.subscribe('presence-user-1');
user_channel.on('client-message', function (data) {
//
});
user_channel.trigger('client-message', {form_uid:2, content:"hello"});
```

#### 5. wss代理(SSL)

[](#5-wss代理ssl)

- https下无法使用ws连接，需要使用wss连接。这种情况可以使用nginx代理wss，配置类似如下：

```
server {
# .... 这里省略了其它配置 ...

    location /app
    {
        proxy_pass http://127.0.0.1:3131;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header X-Real-IP $remote_addr;
    }
}

```

- 重启nginx后，使用以下方式连接服务端

```
var connection = new Push({
    url: 'wss://example.com',
    app_key: ''
});
```

##### Tips：

[](#tips-1)

**wss开头，不写端口，必须使用ssl证书对应的域名连接**

---

### websocket-php客户端

[](#websocket-php客户端)

#### 1. 创建连接

[](#1-创建连接)

```
use Workbunny\WebmanPushServer\WsClient;
use Workerman\Connection\AsyncTcpConnection;
use Workbunny\WebmanPushServer\EVENT_SUBSCRIBE;
use Workbunny\WebmanPushServer\EVENT_SUBSCRIPTION_SUCCEEDED;

// 创建连接
$client = WsClient::instance('127.0.0.1:8001', [
    'app_key'        => 'workbunny',
    'heartbeat'      => 60,
    'auth'           => 'http://127.0.0.1:8002/subscribe/auth',
    'channel_data'   => []  // channel_data
    'query'          => [], // query
    'context_option' => []
])
// 建立连接
$client->connect();
// 关闭连接
$client->disconnect();
```

#### 2. 订阅/退订

[](#2-订阅退订)

```
use Workbunny\WebmanPushServer\WsClient;
use Workerman\Connection\AsyncTcpConnection;

// 创建连接
$client = WsClient::instance('127.0.0.1:8001', [
    'app_key'        => 'workbunny',
    'heartbeat'      => 60,
    'auth'           => 'http://127.0.0.1:8002/subscribe/auth',
    'channel_data'   => []  // channel_data
    'query'          => [], // query
    'context_option' => []
])

// 订阅一个私有通道，订阅成功后会执行回调函数
$client->subscribe('private-test', function (AsyncTcpConnection $connection, array $data) {
    // 订阅成功后打印
    dump($data);
});
// 订阅一个私有通道，不注册订阅成功后的回调
$client->subscribe('private-test');

// 取消订阅一个私有通道
$client->unsubscribe('private-test', function (AsyncTcpConnection $connection, array $data) {
    // 取消订阅成功后打印
    dump($data);
});
// 取消订阅一个私有通道，不注册订阅成功后的回调
$client->unsubscribe('private-test');

// 取消全部订阅
$client->unsubscribeAll();
```

#### 3. 触发消息

[](#3-触发消息)

```
// 向 private-test 通道发送 client-test 事件消息
$client->trigger('private-test', 'client-test', [
    'message' => 'hello workbunny!'
]);

// 向 presence-test 通道发送 client-test 事件消息
$client->trigger('presence-test', 'client-test', [
    'message' => 'hello workbunny!'
]);

// 事件不带 client- 前缀会抛出RuntimeException
try {
    $client->trigger('presence-test', 'test', [
        'message' => 'hello workbunny!'
    ]);
} catch (RuntimeException $exception){
    dump($exception);
}
```

#### 4. 事件注册回调

[](#4-事件注册回调)

```
use Workerman\Connection\AsyncTcpConnection;

// 注册关注private-test通道的client-test事件
$client->eventOn('private-test', 'client-test', function(AsyncTcpConnection $connection, array $data) {
    // 打印事件数据
    dump($data);
});
// 取消关注private-test通道的client-test事件
$client->eventOff('private-test', 'client-test');

// 获取所有注册事件回调
$client->getEvents();
```

#### 5. 其他

[](#5-其他)

```
// 获取客户端id，当连接创建前该方法返回null
$client->getSocketId();

// 获取已订阅通道，订阅触发前该方法返回空数组
$client->getChannels();

// 发布消息
$client->publish();

// 更多详见 WsClient.php
```

---

### open-apis-php客户端

[](#open-apis-php客户端)

#### 1. 安装

[](#1-安装-1)

1. 或者使用\\Workbunny\\WebmanPushServer\\ApiClient **【建议使用】**

    ```
    composer require workbunny/webman-push-server

    ```
2. 使用pusher提供的api客户端 **【不建议使用，客户端请求没有使用keep-alive】**

    ```
    composer require pusher/pusher-php-server

    ```

#### 2. 推送

[](#2-推送)

```
use Workbunny\WebmanPushServer\ApiClient;

try {
    $pusher = new ApiClient(
        'APP_KEY',
        'APP_SECRET',
        'APP_ID',
        [
            'host'       =>"http://127.0.0.1:8001",
            'timeout'    => 60,
            'keep-alive' => true
        ]
    );
    $pusher->trigger(
        // 频道（channel）支持多个通道
        ["private-d"],
        // 事件
        "client-a",
        // 消息体
        [
            'message' => 'hello workbunny!'
        ],
        // query
        []
    );
} catch (GuzzleException|ApiErrorException|PusherException $e) {
    dump($e);
}
```

#### 3. 其他功能详见open-apis列表

[](#3-其他功能详见open-apis列表)

---

### 其他客户端

[](#其他客户端)

- 兼容pusher，其他语言(Java Swift .NET Objective-C Unity Flutter Android IOS AngularJS等)客户端地址下载地址： [https://pusher.com/docs/channels/channels\_libraries/libraries/](https://pusher.com/docs/channels/channels_libraries/libraries/)

---

---

进阶用法
----

[](#进阶用法)

### 1. push-server中间件服务

[](#1-push-server中间件服务)

在一些服务器监控场景下，我们需要获取全量的往来信息，包括客户端的消息和服务端的回执等

- 创建一个中间件服务类，use引入ChannelMethods
    - 客户端与服务端的任何通讯消息会触达`_subscribeResponse`方法，请在`_subscribeResponse`方法中实现对应业务逻辑，入日志等；
    - `_subscribeResponse`方法是经过业务处理后的方法，如果想要订阅原始数据，请实现`_subscribeRaw`方法

```
