You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否使用PAMI与react-php连接多台FreePBX服务器?

问题:能否用PAMI结合React-PHP实现多台FreePBX服务器的连接?

我正在使用PAMI结合react-php和Ratchet连接Asterisk AMI,目前拥有3台FreePBX服务器,希望在一个仪表板中连接所有服务器并接收它们的全部事件。以下是我用PHP/Laravel编写的连接Asterisk AMI的代码:

Artisan::command('asterisk:go', function () {
$loop = React\EventLoop\Factory::create();
$websockethandler = new \App\WebsocketHandler();
$app = new Ratchet\App(
'localhost',
6001,
'0.0.0.0',
$loop
);
$app->route(
'/websocket',
$websockethandler,
['*']
);
$user               = AsteriskServer::where('user_id', auth()->user()->id)->get();
foreach($user as $key => $us){
try {

            $ami = new \React\Stream\DuplexResourceStream(
                stream_socket_client("tcp://$us->pbx:5038"),
                $loop
            );
    } catch (\Exception $e) {
        die($e->getMessage());
    }
    $asteriskmanager[$key] = new App\AsteriskManager($ami);
    $asteriskmanager[$key]->login(
        $us->ami_username,
        $us->ami_password
    );
    $callcenter = new Callcenter($websockethandler, $asteriskmanager[$key]);
    $websockethandler->on('websocket.hello', [$callcenter, 'websocketHello']);
    $websockethandler->on('websocket.avail', [$callcenter, 'websocketSetAgentAvail']);
    $websockethandler->on('websocket.pause', [$callcenter, 'websocketSetAgentPause']);
    
    $asteriskmanager[$key]->on('agent.loggedin', [$callcenter, 'agentLoggedIn']);
    $asteriskmanager[$key]->on('agent.events', [$callcenter, 'agentEvents']);
    $asteriskmanager[$key]->on('agent.paused', [$callcenter, 'agentPaused']);
    $asteriskmanager[$key]->on('agent.avail', [$callcenter, 'agentAvail']);

}

    $app->run();

})->purpose('Display an inspiring quote');

回答

当然可以,你的代码核心思路已经正确——通过循环遍历多台FreePBX服务器,为每台服务器创建独立的AMI连接实例,并绑定对应的事件处理逻辑,完全支持同时连接多台服务器并接收各自的事件。

不过可以针对现有代码做几点优化,提升稳定性和实用性:

  • 避免单台连接失败导致进程终止:原代码中使用die()会在某台服务器连接失败时直接终止整个服务,改成记录错误日志并跳过故障服务器,保证其他正常服务器能正常连接。
  • 标记事件来源服务器:在Callcenter实例中传入服务器ID或标识,这样事件回调中能区分事件来自哪台FreePBX,方便前端仪表板展示对应服务器的状态。
  • 添加连接断开重连逻辑:监听AMI连接的close事件,当连接意外断开时自动尝试重连,避免服务中断。
  • 优化WebSocket事件绑定:无需为每台服务器重复绑定相同的WebSocket事件,可在前端发送消息时携带目标服务器ID,后端根据ID找到对应连接执行操作。

下面是优化后的代码示例:

Artisan::command('asterisk:go', function () {
    $loop = React\EventLoop\Factory::create();
    $websockethandler = new \App\WebsocketHandler();
    $app = new Ratchet\App(
        'localhost',
        6001,
        '0.0.0.0',
        $loop
    );
    $app->route(
        '/websocket',
        $websockethandler,
        ['*']
    );
    $servers = AsteriskServer::where('user_id', auth()->user()->id)->get();
    
    foreach($servers as $key => $server){
        try {
            $socket = stream_socket_client("tcp://{$server->pbx}:5038");
            if (!$socket) {
                throw new \Exception("无法连接到服务器 {$server->pbx}");
            }
            $ami = new \React\Stream\DuplexResourceStream($socket, $loop);
        } catch (\Exception $e) {
            \Log::error("连接服务器失败: {$e->getMessage()}");
            continue; // 跳过故障服务器,继续连接其他服务器
        }
        
        $asteriskmanager[$key] = new App\AsteriskManager($ami);
        $asteriskmanager[$key]->login(
            $server->ami_username,
            $server->ami_password
        );
        
        // 传入服务器ID,方便事件回调区分来源
        $callcenter = new Callcenter($websockethandler, $asteriskmanager[$key], $server->id);
        
        $websockethandler->on('websocket.hello', [$callcenter, 'websocketHello']);
        $websockethandler->on('websocket.avail', [$callcenter, 'websocketSetAgentAvail']);
        $websockethandler->on('websocket.pause', [$callcenter, 'websocketSetAgentPause']);
        
        $asteriskmanager[$key]->on('agent.loggedin', [$callcenter, 'agentLoggedIn']);
        $asteriskmanager[$key]->on('agent.events', [$callcenter, 'agentEvents']);
        $asteriskmanager[$key]->on('agent.paused', [$callcenter, 'agentPaused']);
        $asteriskmanager[$key]->on('agent.avail', [$callcenter, 'agentAvail']);
        
        // 添加连接断开监听,5秒后尝试重连
        $ami->on('close', function() use ($loop, $server, $websockethandler, &$asteriskmanager, $key) {
            \Log::warning("服务器 {$server->pbx} 的AMI连接已断开,将在5秒后尝试重连");
            $loop->addTimer(5, function() use ($loop, $server, $websockethandler, &$asteriskmanager, $key) {
                try {
                    $socket = stream_socket_client("tcp://{$server->pbx}:5038");
                    $ami = new \React\Stream\DuplexResourceStream($socket, $loop);
                    $asteriskmanager[$key] = new App\AsteriskManager($ami);
                    $asteriskmanager[$key]->login($server->ami_username, $server->ami_password);
                    
                    $callcenter = new Callcenter($websockethandler, $asteriskmanager[$key], $server->id);
                    // 重新绑定事件
                    $asteriskmanager[$key]->on('agent.loggedin', [$callcenter, 'agentLoggedIn']);
                    $asteriskmanager[$key]->on('agent.events', [$callcenter, 'agentEvents']);
                    $asteriskmanager[$key]->on('agent.paused', [$callcenter, 'agentPaused']);
                    $asteriskmanager[$key]->on('agent.avail', [$callcenter, 'agentAvail']);
                    
                    \Log::info("服务器 {$server->pbx} 的AMI连接已重连成功");
                } catch (\Exception $e) {
                    \Log::error("重连服务器 {$server->pbx} 失败: {$e->getMessage()}");
                }
            });
        });
    }

    $app->run();
})->purpose('启动Asterisk AMI多服务器连接与WebSocket服务');

内容的提问来源于stack exchange,提问作者abdullah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 09:54:56