WebSocketService.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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. $data = Base::json2array($frame->data);
  95. $feedback = [
  96. 'status' => 1,
  97. 'message' => '',
  98. ];
  99. switch ($data['type']) {
  100. /**
  101. * 未读消息总数
  102. */
  103. case 'unread':
  104. $from = self::fd2name($frame->fd);
  105. if ($from) {
  106. $num = intval(DB::table('chat_dialog')->where('user1', $from)->sum('unread1'));
  107. $num+= intval(DB::table('chat_dialog')->where('user2', $from)->sum('unread2'));
  108. $feedback['message'] = $num;
  109. } else {
  110. $feedback['message'] = 0;
  111. }
  112. break;
  113. /**
  114. * 已读消息
  115. */
  116. case 'read':
  117. $to = self::name2fd($data['target']);
  118. if ($to) {
  119. $dialog = Chat::openDialog(self::fd2name($frame->fd), $data['target']);
  120. if (!Base::isError($dialog)) {
  121. $dialog = $dialog['data'];
  122. $upArray = [
  123. ($dialog['recField'] == 1 ? 'unread2' : 'unread1') => 0,
  124. ];
  125. DB::table('chat_dialog')->where('id', $dialog['id'])->update($upArray);
  126. }
  127. }
  128. break;
  129. /**
  130. * 发给用户
  131. */
  132. case 'user':
  133. $to = self::name2fd($data['target']);
  134. if ($to) {
  135. $res = Chat::saveMessage(self::fd2name($frame->fd), $data['target'], $data['content']);
  136. if (Base::isError($res)) {
  137. $feedback = [
  138. 'status' => 0,
  139. 'message' => $res['msg'],
  140. ];
  141. } else {
  142. $data['content']['id'] = $res['data']['id'];
  143. $server->push($to, Base::array2json($data));
  144. $feedback['message'] = $res['data']['id'];
  145. }
  146. } else {
  147. $feedback = [
  148. 'status' => 0,
  149. 'message' => '账号不存在!',
  150. ];
  151. }
  152. break;
  153. /**
  154. * 发给整个团队
  155. */
  156. case 'team':
  157. foreach (self::getUsersAll() as $user) {
  158. $data['target'] = $user['username'];
  159. $server->push($user['wsid'], Base::array2json($data));
  160. }
  161. break;
  162. }
  163. if ($data['messageId']) {
  164. $server->push($frame->fd, Base::array2json([
  165. 'messageType' => 'feedback',
  166. 'messageId' => $data['messageId'],
  167. 'type' => 'user',
  168. 'sender' => null,
  169. 'target' => null,
  170. 'content' => $feedback,
  171. 'time' => Base::time()
  172. ]));
  173. }
  174. }
  175. /**
  176. * 关闭连接时触发
  177. * @param Server $server
  178. * @param $fd
  179. * @param $reactorId
  180. */
  181. public function onClose(Server $server, $fd, $reactorId)
  182. {
  183. self::forgetUser($fd);
  184. }
  185. /** ****************************************************************************** */
  186. /** ****************************************************************************** */
  187. /** ****************************************************************************** */
  188. /**
  189. * 缓存用户信息
  190. * @param $fd
  191. * @param $username
  192. */
  193. public static function saveUser($fd, $username)
  194. {
  195. DB::table('users')->where('wsid', $fd)->update(['wsid' => 0]);
  196. DB::table('users')->where('username', $username)->update(['wsid' => $fd]);
  197. }
  198. /**
  199. * 清除用户缓存
  200. * @param $fd
  201. */
  202. public static function forgetUser($fd)
  203. {
  204. DB::table('users')->where('wsid', $fd)->update(['wsid' => 0]);
  205. }
  206. /**
  207. * 获取当前用户
  208. * @return array|string
  209. */
  210. public static function getUsersAll()
  211. {
  212. return Base::DBC2A(DB::table('users')->select(['wsid', 'username'])->where('wsid', '>', 0)->get());
  213. }
  214. /**
  215. * @param $fd
  216. * @return mixed
  217. */
  218. public static function fd2name($fd)
  219. {
  220. return DB::table('users')->select(['username'])->where('wsid', $fd)->value('username');
  221. }
  222. /**
  223. * @param $username
  224. * @return mixed
  225. */
  226. public static function name2fd($username)
  227. {
  228. return DB::table('users')->select(['wsid'])->where('username', $username)->value('wsid');
  229. }
  230. }