Socket.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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. $fds = RedisService::get('chats:fds');
  79. if($fds){
  80. $fds[] = $request->fd;
  81. }else{
  82. $fds = [$request->fd];
  83. }
  84. RedisService::set('chats:fds',$fds, 86400);
  85. $this->ws->push($request->fd, json_encode(['message' => '连接成功:'.$request->fd], 256));
  86. }
  87. /**
  88. * 接收消息
  89. * @param $ws
  90. * @param $frame
  91. */
  92. public function message($ws, $frame)
  93. {
  94. try {
  95. if ($frame->data == 'ping') {
  96. $this->ws->push($frame->fd, 'pong');
  97. return false;
  98. }
  99. // 消息处理
  100. $data = $frame->data ? json_decode($frame->data, true) : [];
  101. $op = isset($data['op']) ? $data['op'] : '';
  102. $userId = isset($data['from_uid']) ? trim($data['from_uid']) : 0;
  103. $chatKey = isset($data['chat_key']) ? trim($data['chat_key']) : '';
  104. $toUid = isset($data['to_uid']) ? intval($data['to_uid']) : 0;
  105. if ($userId && $frame->fd) {
  106. $chatKey = $chatKey ? $chatKey : getChatKey($userId, $toUid);
  107. RedisService::set("chats:bind:{$userId}", ['fd' => $frame->fd, 'user_id' => $userId, 'chat_key' => $chatKey], 86400);
  108. }
  109. if ($data) {
  110. switch ($op) {
  111. case 'chat': // 默认聊天
  112. $toUid = isset($data['to_uid']) ? intval($data['to_uid']) : 0;
  113. $fromUid = isset($data['from_uid']) ? intval($data['from_uid']) : 0;
  114. $messageType = isset($data['message_type']) ? $data['message_type'] : 1;
  115. if ($toUid <= 0 || $fromUid <= 0) {
  116. return false;
  117. }
  118. if (!ChatMessageService::make()->saveData($data)) {
  119. $data = ['message' => lang(ChatMessageService::make()->getError())];
  120. $this->ws->push($frame->fd, json_encode($data, 256));
  121. return false;
  122. }
  123. $toInfo = MemberService::make()->getInfo($toUid);
  124. $fromInfo = MemberService::make()->getInfo($fromUid);
  125. $message = isset($data['message']) ? $data['message'] : '';
  126. $chatKey = getChatKey($fromUid, $toUid);
  127. $data = [
  128. 'type' => isset($data['type']) ? $data['type'] : 1,
  129. 'message_type' => $messageType,
  130. 'from_uid' => $fromUid,
  131. 'from_username' => isset($fromInfo['username']) ? $fromInfo['username'] : '客服',
  132. 'from_username_text' => isset($fromInfo['username']) ? format_account($fromInfo['username']) : '客服',
  133. 'to_uid' => isset($data['to_uid']) ? $data['to_uid'] : 0,
  134. 'to_username' => isset($toInfo['username']) ? $toInfo['username'] : '客服',
  135. 'to_username_text' => isset($toInfo['username']) ? format_account($toInfo['username']) : '客服',
  136. 'chat_key' => $chatKey,
  137. 'message' => $message,
  138. 'message_url' => $messageType == 2 && $message ? get_image_url($message) : '',
  139. 'create_time' => time(),
  140. 'time_text' => format_time(time() - 1),
  141. 'is_read' => 1,
  142. 'status' => 1,
  143. ];
  144. $this->ws->push($frame->fd, json_encode($data, 256));
  145. $toBindData = RedisService::get("chats:bind:{$toUid}");
  146. $toFd = isset($toBindData['fd']) ? $toBindData['fd'] : 0;
  147. $toChatKey = isset($toBindData['chat_key']) ? $toBindData['chat_key'] : '';
  148. if ($toBindData && $toFd && $toChatKey == $chatKey) {
  149. $this->ws->push($toFd, json_encode($data, 256));
  150. }
  151. break;
  152. case 'order':
  153. $toBindData = RedisService::get("chats:bind:od_{$toUid}");
  154. $toFd = isset($toBindData['fd']) ? $toBindData['fd'] : 0;
  155. if($toFd){
  156. $this->sendMsg($toFd, $frame->data);
  157. }
  158. $data['fd'] = $frame->fd;
  159. $data['to_fd'] = $toFd;
  160. $this->ws->push($frame->fd, json_encode($data, 256));
  161. break;
  162. default:
  163. $this->ws->push($frame->fd, json_encode(['message' => $frame->data], 256));
  164. break;
  165. }
  166. } else {
  167. $this->ws->push($frame->fd, json_encode(['message' => 'no data'], 256));
  168. }
  169. } catch (\Exception $exception) {
  170. $this->ws->push($frame->fd, json_encode(['message' => $exception->getMessage()], 256));
  171. }
  172. }
  173. /**
  174. * 接收请求
  175. * @param $request
  176. * @param $response
  177. */
  178. public function request($request, $response)
  179. {
  180. }
  181. /**
  182. * 发送消息
  183. * @param $fd
  184. * @param $data
  185. * @return false
  186. */
  187. public function sendMsg($fd, $data)
  188. {
  189. try {
  190. $this->ws->push($fd, $data);
  191. } catch (\Exception $exception){
  192. return false;
  193. }
  194. }
  195. /**
  196. * 关闭连接
  197. * @param $ws
  198. * @param $fd
  199. */
  200. public function close($ws, $fd = '')
  201. {
  202. // var_dump($ws);
  203. echo '连接关闭:' . $fd . "\n";
  204. $this->ws->close($fd);
  205. }
  206. /**
  207. * 停止运行
  208. */
  209. public function stop()
  210. {
  211. if($this->ws){
  212. $this->ws->close();
  213. }
  214. }
  215. }