能否使用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
相关产品推荐
相关产品推荐

