WebSocketService.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. <?php
  2. namespace App\Services;
  3. use App\Module\Base;
  4. use App\Module\Chat;
  5. use Cache;
  6. use DB;
  7. use Hhxsv5\LaravelS\Swoole\WebSocketHandlerInterface;
  8. use Swoole\Http\Request;
  9. use Swoole\WebSocket\Frame;
  10. use Swoole\WebSocket\Server;
  11. /**
  12. * @see https://wiki.swoole.com/#/start/start_ws_server
  13. */
  14. class WebSocketService implements WebSocketHandlerInterface
  15. {
  16. /**
  17. * 声明没有参数的构造函数
  18. * WebSocketService constructor.
  19. */
  20. public function __construct()
  21. {
  22. }
  23. /**
  24. * 连接建立时触发
  25. * @param Server $server
  26. * @param Request $request
  27. */
  28. public function onOpen(Server $server, Request $request)
  29. {
  30. $to = $request->fd;
  31. if (!isset($request->get['token'])) {
  32. $server->push($to, Base::array2json([
  33. 'messageType' => 'error',
  34. 'type' => 'user',
  35. 'sender' => null,
  36. 'target' => null,
  37. 'content' => [
  38. 'error' => '参数错误'
  39. ],
  40. 'time' => Base::time()
  41. ]));
  42. $server->close($to);
  43. self::forgetUser($to);
  44. return;
  45. }
  46. //
  47. $token = $request->get['token'];
  48. $cacheKey = "ws-token:" . md5($token);
  49. $username = Cache::remember($cacheKey, now()->addSeconds(1), function () use ($token) {
  50. list($id, $username, $encrypt, $timestamp) = explode("@", base64_decode($token) . "@@@@");
  51. if (intval($id) > 0 && intval($timestamp) + 2592000 > Base::time()) {
  52. if (DB::table('users')->where(['id' => $id, 'username' => $username, 'encrypt' => $encrypt])->exists()) {
  53. return $username;
  54. }
  55. }
  56. return null;
  57. });
  58. if (empty($username)) {
  59. Cache::forget($cacheKey);
  60. $server->push($to, Base::array2json([
  61. 'messageType' => 'error',
  62. 'type' => 'user',
  63. 'sender' => null,
  64. 'target' => null,
  65. 'content' => [
  66. 'error' => '会员不存在',
  67. ],
  68. 'time' => Base::time()
  69. ]));
  70. $server->close($to);
  71. self::forgetUser($to);
  72. return;
  73. }
  74. //
  75. self::saveUser($to, $username);
  76. $server->push($to, Base::array2json([
  77. 'messageType' => 'open',
  78. 'type' => 'user',
  79. 'sender' => null,
  80. 'target' => null,
  81. 'content' => [
  82. 'swid' => $to,
  83. ],
  84. 'time' => Base::time()
  85. ]));
  86. }
  87. /**
  88. * 收到消息时触发
  89. * @param Server $server
  90. * @param Frame $frame
  91. */
  92. public function onMessage(Server $server, Frame $frame)
  93. {
  94. global $_A;
  95. $_A = [
  96. '__static_langdata' => [],
  97. ];
  98. //
  99. $data = Base::json2array($frame->data);
  100. $feedback = [
  101. 'status' => 1,
  102. 'message' => '',
  103. ];
  104. switch ($data['type']) {
  105. /**
  106. * 未读消息总数
  107. */
  108. case 'unread':
  109. $from = self::fd2name($frame->fd);
  110. if ($from) {
  111. $num = intval(DB::table('chat_dialog')->where('user1', $from)->sum('unread1'));
  112. $num+= intval(DB::table('chat_dialog')->where('user2', $from)->sum('unread2'));
  113. $feedback['message'] = $num;
  114. } else {
  115. $feedback['message'] = 0;
  116. }
  117. break;
  118. /**
  119. * 已读消息
  120. */
  121. case 'read':
  122. $to = self::name2fd($data['target']);
  123. if ($to) {
  124. $dialog = Chat::openDialog(self::fd2name($frame->fd), $data['target']);
  125. if (!Base::isError($dialog)) {
  126. $dialog = $dialog['data'];
  127. $upArray = [];
  128. if ($dialog['user1'] == $dialog['user2']) {
  129. $upArray['unread1'] = 0;
  130. $upArray['unread2'] = 0;
  131. } else {
  132. $upArray[($dialog['recField'] == 1 ? 'unread2' : 'unread1')] = 0;
  133. }
  134. DB::table('chat_dialog')->where('id', $dialog['id'])->update($upArray);
  135. }
  136. }
  137. break;
  138. /**
  139. * 发给用户
  140. */
  141. case 'user':
  142. $to = self::name2fd($data['target']);
  143. $res = Chat::saveMessage(self::fd2name($frame->fd), $data['target'], $data['content']);
  144. if (Base::isError($res)) {
  145. $feedback = [
  146. 'status' => 0,
  147. 'message' => $res['msg'],
  148. ];
  149. } else {
  150. $data['content']['id'] = $res['data']['id'];
  151. $feedback['message'] = $res['data']['id'];
  152. if ($to) {
  153. $server->push($to, Base::array2json($data));
  154. }
  155. }
  156. break;
  157. /**
  158. * 发给整个团队
  159. */
  160. case 'team':
  161. foreach (self::getUsersAll() as $user) {
  162. $data['target'] = $user['username'];
  163. $server->push($user['wsid'], Base::array2json($data));
  164. }
  165. break;
  166. }
  167. if ($data['messageId']) {
  168. $server->push($frame->fd, Base::array2json([
  169. 'messageType' => 'feedback',
  170. 'messageId' => $data['messageId'],
  171. 'type' => 'user',
  172. 'sender' => null,
  173. 'target' => null,
  174. 'content' => $feedback,
  175. 'time' => Base::time()
  176. ]));
  177. }
  178. }
  179. /**
  180. * 关闭连接时触发
  181. * @param Server $server
  182. * @param $fd
  183. * @param $reactorId
  184. */
  185. public function onClose(Server $server, $fd, $reactorId)
  186. {
  187. self::forgetUser($fd);
  188. }
  189. /** ****************************************************************************** */
  190. /** ****************************************************************************** */
  191. /** ****************************************************************************** */
  192. /**
  193. * 缓存用户信息
  194. * @param $fd
  195. * @param $username
  196. */
  197. public static function saveUser($fd, $username)
  198. {
  199. DB::table('users')->where('wsid', $fd)->update(['wsid' => 0]);
  200. DB::table('users')->where('username', $username)->update(['wsid' => $fd]);
  201. }
  202. /**
  203. * 清除用户缓存
  204. * @param $fd
  205. */
  206. public static function forgetUser($fd)
  207. {
  208. DB::table('users')->where('wsid', $fd)->update(['wsid' => 0]);
  209. }
  210. /**
  211. * 获取当前用户
  212. * @return array|string
  213. */
  214. public static function getUsersAll()
  215. {
  216. return Base::DBC2A(DB::table('users')->select(['wsid', 'username'])->where('wsid', '>', 0)->get());
  217. }
  218. /**
  219. * @param $fd
  220. * @return mixed
  221. */
  222. public static function fd2name($fd)
  223. {
  224. return DB::table('users')->select(['username'])->where('wsid', $fd)->value('username');
  225. }
  226. /**
  227. * @param $username
  228. * @return mixed
  229. */
  230. public static function name2fd($username)
  231. {
  232. return DB::table('users')->select(['wsid'])->where('username', $username)->value('wsid');
  233. }
  234. }