WebSocketService.php 7.4 KB

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