Socket.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <?php
  2. namespace App\Console\Commands;
  3. use App\Services\ChatMessageService;
  4. use App\Services\Common\MemberService;
  5. use App\Services\RedisService;
  6. use Illuminate\Console\Command;
  7. class Socket extends Command
  8. {
  9. public $ws;
  10. /**
  11. * The name and signature of the console command.
  12. *
  13. * @var string
  14. */
  15. protected $signature = 'swoole:socketIm {op?}';
  16. /**
  17. * The console command description.
  18. *
  19. * @var string
  20. */
  21. protected $description = 'websocket ';
  22. /**
  23. * Create a new command instance.
  24. *
  25. * @return void
  26. */
  27. public function __construct()
  28. {
  29. parent::__construct();
  30. }
  31. /**
  32. * Execute the console command.
  33. *
  34. * @return mixed
  35. */
  36. public function handle()
  37. {
  38. $op = $this->argument('op');
  39. $op = $op ? $op : 'start';
  40. if ($op == 'start') {
  41. echo "socket start ...\n";
  42. $this->start();
  43. } else if ($op == 'stop') {
  44. echo "socket stop ...\n";
  45. $this->stop();
  46. }
  47. }
  48. /**
  49. * 运行
  50. */
  51. public function start()
  52. {
  53. try {
  54. //创建websocket服务器对象,监听0.0.0.0:7104端口
  55. $this->ws = new \swoole_websocket_server("0.0.0.0", env('SOCKET_PORT', '6520'));
  56. // $this->ws->set();
  57. //监听WebSocket连接打开事件
  58. $this->ws->on('open', [$this, 'open']);
  59. //监听WebSocket消息事件
  60. $this->ws->on('message', [$this, 'message']);
  61. //监听WebSocket主动推送消息事件
  62. $this->ws->on('request', [$this, 'request']);
  63. //监听WebSocket连接关闭事件
  64. $this->ws->on('close', [$this, 'close']);
  65. $this->ws->start();
  66. } catch (\Exception $exception){
  67. RedisService::set("caches:sockets:error", $exception->getMessage(), 600);
  68. }
  69. }
  70. /**
  71. * 建立连接
  72. * @param $ws
  73. * @param $request
  74. */
  75. public function open($ws, $request)
  76. {
  77. echo "连接成功:" . $request->fd . "\n";
  78. $this->ws->push($request->fd, json_encode(['message' => '连接成功'], 256));
  79. }
  80. /**
  81. * 接收消息
  82. * @param $ws
  83. * @param $frame
  84. */
  85. public function message($ws, $frame)
  86. {
  87. try {
  88. if ($frame->data == 'ping') {
  89. $this->ws->push($frame->fd, 'pong');
  90. return false;
  91. }
  92. // 消息处理
  93. $data = $frame->data ? json_decode($frame->data, true) : [];
  94. $op = isset($data['op']) ? $data['op'] : '';
  95. $userId = isset($data['from_uid']) ? intval($data['from_uid']) : 0;
  96. $chatKey = isset($data['chat_key']) ? trim($data['chat_key']) : '';
  97. $toUid = isset($data['to_uid']) ? intval($data['to_uid']) : 0;
  98. if ($userId && $frame->fd) {
  99. $chatKey = $chatKey ? $chatKey : getChatKey($userId, $toUid);
  100. RedisService::set("chats:bind:{$userId}", ['fd' => $frame->fd, 'user_id' => $userId, 'chat_key' => $chatKey], 86400);
  101. }
  102. if ($data) {
  103. switch ($op) {
  104. case 'chat': // 默认聊天
  105. $toUid = isset($data['to_uid']) ? intval($data['to_uid']) : 0;
  106. $fromUid = isset($data['from_uid']) ? intval($data['from_uid']) : 0;
  107. $messageType = isset($data['message_type']) ? $data['message_type'] : 1;
  108. if ($toUid <= 0 || $fromUid <= 0) {
  109. return false;
  110. }
  111. if (!ChatMessageService::make()->saveData($data)) {
  112. $data = ['message' => lang(ChatMessageService::make()->getError())];
  113. $this->ws->push($frame->fd, json_encode($data, 256));
  114. return false;
  115. }
  116. $toInfo = MemberService::make()->getInfo($toUid);
  117. $fromInfo = MemberService::make()->getInfo($fromUid);
  118. $message = isset($data['message']) ? $data['message'] : '';
  119. $chatKey = getChatKey($fromUid, $toUid);
  120. $data = [
  121. 'type' => isset($data['type']) ? $data['type'] : 1,
  122. 'message_type' => $messageType,
  123. 'from_uid' => $fromUid,
  124. 'from_username' => isset($fromInfo['username']) ? $fromInfo['username'] : '客服',
  125. 'from_username_text' => isset($fromInfo['username']) ? format_account($fromInfo['username']) : '客服',
  126. 'to_uid' => isset($data['to_uid']) ? $data['to_uid'] : 0,
  127. 'to_username' => isset($toInfo['username']) ? $toInfo['username'] : '客服',
  128. 'to_username_text' => isset($toInfo['username']) ? format_account($toInfo['username']) : '客服',
  129. 'chat_key' => $chatKey,
  130. 'message' => $message,
  131. 'message_url' => $messageType == 2 && $message ? get_image_url($message) : '',
  132. 'create_time' => time(),
  133. 'time_text' => format_time(time() - 1),
  134. 'is_read' => 1,
  135. 'status' => 1,
  136. ];
  137. $this->ws->push($frame->fd, json_encode($data, 256));
  138. $toBindData = RedisService::get("chats:bind:{$toUid}");
  139. $toFd = isset($toBindData['fd']) ? $toBindData['fd'] : 0;
  140. $toChatKey = isset($toBindData['chat_key']) ? $toBindData['chat_key'] : '';
  141. if ($toBindData && $toFd && $toChatKey == $chatKey) {
  142. $this->ws->push($toFd, json_encode($data, 256));
  143. }
  144. break;
  145. default:
  146. $this->ws->push($frame->fd, json_encode(['message' => $frame->data], 256));
  147. break;
  148. }
  149. } else {
  150. $this->ws->push($frame->fd, json_encode(['message' => 'no data'], 256));
  151. }
  152. } catch (\Exception $exception) {
  153. $this->ws->push($frame->fd, json_encode(['message' => $exception->getMessage()], 256));
  154. }
  155. }
  156. /**
  157. * 接收请求
  158. * @param $request
  159. * @param $response
  160. */
  161. public function request($request, $response)
  162. {
  163. }
  164. /**
  165. * 关闭连接
  166. * @param $ws
  167. * @param $fd
  168. */
  169. public function close($ws, $fd = '')
  170. {
  171. // var_dump($ws);
  172. echo '连接关闭:' . $fd . "\n";
  173. $this->ws->close($fd);
  174. }
  175. /**
  176. * 停止运行
  177. */
  178. public function stop()
  179. {
  180. if($this->ws){
  181. $this->ws->close();
  182. }
  183. }
  184. }