Socket.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. <?php
  2. namespace addons\shopro\library\chat\provider\getter;
  3. use addons\shopro\exception\ShoproException;
  4. use addons\shopro\library\chat\traits\Helper;
  5. use addons\shopro\library\chat\traits\Session;
  6. use addons\shopro\library\chat\traits\BindUId;
  7. use addons\shopro\library\chat\Getter;
  8. use PHPSocketIO\SocketIO;
  9. use PHPSocketIO\Socket as PhpSocket;
  10. use PHPSocketIO\Nsp;
  11. /**
  12. * 从 socket 连接中获取
  13. */
  14. class Socket
  15. {
  16. /**
  17. * session 存储助手
  18. */
  19. use Session;
  20. /**
  21. * BindUid 助手
  22. */
  23. use BindUId;
  24. /**
  25. * 助手方法
  26. */
  27. use Helper;
  28. /**
  29. * getter 实例
  30. *
  31. * @var Getter
  32. */
  33. protected $getter;
  34. /**
  35. * 当前 phpsocket.io 实例
  36. *
  37. * @var SocketIo
  38. */
  39. protected $io = null;
  40. /**
  41. * 当前socket 连接
  42. *
  43. * @var PhpSocket
  44. */
  45. protected $socket = null;
  46. /**
  47. * 当前 命名空间实例
  48. *
  49. * @var Nsp
  50. */
  51. protected $nsp = null;
  52. public function __construct(Getter $getter, PhpSocket $socket = null, SocketIo $io, Nsp $nsp)
  53. {
  54. $this->getter = $getter;
  55. $this->socket = $socket;
  56. $this->io = $io;
  57. $this->nsp = $nsp;
  58. }
  59. /**
  60. * 通过房间获取房间中所有连接的 clientIds
  61. *
  62. * @param string $room 房间名称
  63. * @return void
  64. */
  65. public function getClientIdsByRoom($room) {
  66. // 获取到的数组 键是 id 值是 boolean true
  67. $clientIds = $this->nsp->adapter->rooms[$room] ?? [];
  68. // 取出 clientIds
  69. $clientIds = array_keys($clientIds);
  70. return $clientIds;
  71. }
  72. /**
  73. * 根据房间获取所有房间中的 authUser
  74. *
  75. * @param string $room_id 房间号
  76. * @param string $is_unique 默认过滤重复的数据
  77. * @return array
  78. */
  79. public function getAuthsByAuth($auth, $is_unique = true)
  80. {
  81. // 要接入的客服所在的房间,默认 admin 房间,z这里的客服的状态都是 在线的,如果手动切换为离线,则会被移除该房间
  82. $room = $this->getRoomName('auth', ['auth' => $auth]);
  83. $sessions = $this->getSessionsByRoom($room, null, $is_unique);
  84. $authUsers = [];
  85. foreach ($sessions as $session) {
  86. if (isset($session['auth_user']) && $session['auth_user']) {
  87. $authUsers[$session['session_id']] = $session['auth_user'];
  88. }
  89. }
  90. return $authUsers;
  91. }
  92. /**
  93. * 通过id 获取指定客服,并且还必须在对应的客服房间中
  94. *
  95. * @param string $id 客服 id
  96. * @param string $room_id 客服房间号
  97. * @return array|null
  98. */
  99. public function getCustomerServiceById($room_id, $id)
  100. {
  101. // 要接入的客服所在的房间,默认 admin 房间
  102. $room = $this->getRoomName('customer_service_room', ['room_id' => $room_id]);
  103. // 房间中的所有客服的 clientids
  104. $roomClientIds = $this->getClientIdsByRoom($room);
  105. // 当前客服 uid 绑定的所有客户端 clientIds,手动后台离线的已经被解绑了,这里都是状态为在线的
  106. $currentClientIds = $this->getClientIdByUId($id, 'customer_service');
  107. if ($clientIds = array_intersect($currentClientIds, $roomClientIds)) {
  108. // 客服在线
  109. return $this->getSession(current($clientIds), 'customer_service');
  110. }
  111. return null;
  112. }
  113. /**
  114. * 通过 客服 id 判断客服是否在线,这里不管客服所在房间,一个客服只能属于一个房间
  115. *
  116. * @param string $id 客服 id
  117. * @return boolean
  118. */
  119. public function isOnLineCustomerServiceById($id)
  120. {
  121. return $this->isUIdOnline($id, 'customer_service');
  122. }
  123. /**
  124. * 根据房间获取所有房间中的客服
  125. *
  126. * @param string $room_id 客服房间号
  127. * @param string $is_unique 默认过滤重复的数据
  128. * @return array
  129. */
  130. public function getCustomerServicesByRoomId($room_id, $is_unique = true)
  131. {
  132. // 要接入的客服所在的房间,默认 admin 房间,z这里的客服的状态都是 在线的,如果手动切换为离线,则会被移除该房间
  133. $room = $this->getRoomName('customer_service_room', ['room_id' => $room_id]);
  134. $customerServices = $this->getSessionsByRoom($room, 'customer_service', $is_unique);
  135. return $customerServices;
  136. }
  137. /**
  138. * 获取指定 session_id 在对应房间的所有客户端的服务客服的信息
  139. *
  140. * @param [type] $room_id
  141. * @param [type] $session_id
  142. * @return void
  143. */
  144. public function getCustomerServiceBySessionId($room_id, $session_id)
  145. {
  146. $sessions = $this->getSessionsById($session_id, 'customer');
  147. $customerService = null;
  148. foreach ($sessions as $session) {
  149. if (isset($session['room_id']) && $session['room_id'] == $room_id
  150. && isset($session['customer_service']) && $session['customer_service']) {
  151. $currentCustomerService = $session['customer_service'];
  152. if ($this->isOnLineCustomerServiceById($currentCustomerService['id'])) {
  153. // 如果客服在线
  154. $customerService = $currentCustomerService;
  155. break;
  156. }
  157. }
  158. }
  159. return $customerService;
  160. }
  161. /**
  162. * 判断当前房间中是否有客服在线
  163. *
  164. * @param string $room_id 客服房间号
  165. * @return boolean
  166. */
  167. public function hasCustomerServiceByRoomId($room_id)
  168. {
  169. // 获取房间中所有客服的 session,只要有,就说明有客服在线,手动切换状态的会被移除 在线客服房间
  170. $allCustomerServices = $this->getCustomerServicesByRoomId($room_id, false);
  171. if ($allCustomerServices) {
  172. return true;
  173. }
  174. return false;
  175. }
  176. /**
  177. * 判断并通过 顾客 获取顾客的客服
  178. */
  179. public function getCustomerServiceByCustomerSessionId($session_id)
  180. {
  181. $customerServices = $this->getSessionsById($session_id, 'customer', 'customer_service');
  182. return current($customerServices) ?? null;
  183. }
  184. /**
  185. * (获取客服正在服务的顾客)根据客服获取客服房间中所有的被服务用户
  186. *
  187. * @param string $room_id 客服房间号
  188. * @param integer $customer_service_id 客服 id
  189. * @param string $is_unique 默认过滤重复的数据
  190. * @return array
  191. */
  192. public function getCustomersIngByCustomerService($room_id, $customer_service_id, $is_unique = true)
  193. {
  194. // 要接入的客服所在的房间,默认 admin 房间,z这里的客服的状态都是 在线的,如果手动切换为离线,则会被移除该房间
  195. $room = $this->getRoomName('customer_service_room_user', ['room_id' => $room_id, 'customer_service_id' => $customer_service_id]);
  196. $customers = $this->getSessionsByRoom($room, 'chat_user', $is_unique);
  197. return $customers;
  198. }
  199. /**
  200. * (获取等待被接入的用户)根据房间号获取被服务对象
  201. *
  202. * @param string $room_id 客服房间号
  203. * @param integer $customer_service_id 客服 id
  204. * @param string $is_unique 默认过滤重复的数据
  205. * @return array
  206. */
  207. public function getCustomersWaiting($room_id, $is_unique = true)
  208. {
  209. // 要接入的客服所在的房间,默认 admin 房间,z这里的客服的状态都是 在线的,如果手动切换为离线,则会被移除该房间
  210. $room = $this->getRoomName('customer_service_room_waiting', ['room_id' => $room_id]);
  211. $customers = $this->getSessionsByRoom($room, 'chat_user', $is_unique);
  212. return $customers;
  213. }
  214. /**
  215. * 通过 session_id 判断顾客是否在线
  216. *
  217. * @param string $id 客服 id
  218. * @return boolean
  219. */
  220. public function isOnLineCustomerById($session_id)
  221. {
  222. return $this->isUIdOnline($session_id, 'customer');
  223. }
  224. /**
  225. * 通过 session_id 判断 auth 是否在线
  226. *
  227. * @param string $id 客服 id
  228. * @return boolean
  229. */
  230. public function isOnlineAuthBySessionId($session_id, $auth)
  231. {
  232. return $this->isUIdOnline($session_id, $auth);
  233. }
  234. /**
  235. * 通过 id 获取这个人在 type 下的所有客户端 session 数据
  236. *
  237. * @param string $id 要获取的用户的 id
  238. * @param string $type bind 类型:user,admin,customer_service 等
  239. * @param string $name 要获取session 中的特定值,默认全部数据
  240. * @return array
  241. */
  242. public function getSessionsById($id, $type, $name = null)
  243. {
  244. $currentClientIds = $this->getClientIdByUId($id, $type);
  245. $sessionDatas = $this->getSessionByClientIds($currentClientIds, $name);
  246. return $sessionDatas;
  247. }
  248. /**
  249. * 通过 id 更新 id 绑定的所有客户端的 session
  250. *
  251. * @param integer $id
  252. * @param string $type
  253. * @param array $data
  254. * @return void
  255. */
  256. public function updateSessionsById($id, $type, $data = [])
  257. {
  258. // 当前id 在当前类型下绑定的所有客户端
  259. $currentClientIds = $this->getClientIdByUId($id, $type);
  260. $this->updateSessionByClientIds($currentClientIds, $data);
  261. }
  262. /**
  263. * 获取房间中的所有客户端的 session
  264. *
  265. * @param string $room 房间真实名称
  266. * @param string $name 要取用的 session 中的键名,默认全部取出
  267. * @param string $is_unique 默认根据绑定的Uid 过滤重复的 session
  268. * @return array
  269. */
  270. public function getSessionsByRoom($room, $name = null, $is_unique = true) {
  271. // 房间中的所有客服的 clientids
  272. $roomClientIds = $this->getClientIdsByRoom($room);
  273. $sessionDatas = $this->getSessionByClientIds($roomClientIds); // 要过滤重复,没办法直接获取指定数据
  274. // 处理数据
  275. $newDatas = [];
  276. foreach ($sessionDatas as $sessionData) {
  277. if ($is_unique) {
  278. // 过滤重复
  279. $newDatas[$sessionData['session_id']] = $name ? $sessionData[$name] : $sessionData;
  280. } else {
  281. // 全部数据
  282. $newDatas[] = $name ? $sessionData[$name] : $sessionData;
  283. }
  284. }
  285. return array_values(array_filter($newDatas));
  286. }
  287. }