UserController.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. package com.ym.controller;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.microsvc.toolkit.middleware.live.LivePluginContext;
  5. import com.microsvc.toolkit.middleware.live.LivePluginService;
  6. import com.microsvc.toolkit.middleware.live.impl.TencentCloudLivePlugin;
  7. import com.ym.common.BaseResponse;
  8. import com.ym.mec.biz.dal.dto.TencentData;
  9. import com.ym.mec.biz.dal.dto.TencentImCallbackResult;
  10. import com.ym.mec.biz.dal.enums.ETencentImCallbackCommand;
  11. import com.ym.mec.biz.service.ImGroupService;
  12. import com.ym.mec.biz.service.ImLiveBroadcastRoomService;
  13. import com.ym.mec.common.entity.ImUserState;
  14. import com.ym.service.LiveRoomService;
  15. import com.ym.service.RoomService;
  16. import com.ym.service.UserService;
  17. import io.rong.models.user.UserModel;
  18. import io.swagger.annotations.ApiOperation;
  19. import org.apache.commons.collections.CollectionUtils;
  20. import org.apache.commons.lang3.StringUtils;
  21. import org.slf4j.Logger;
  22. import org.slf4j.LoggerFactory;
  23. import org.springframework.beans.factory.annotation.Autowired;
  24. import org.springframework.web.bind.annotation.PostMapping;
  25. import org.springframework.web.bind.annotation.RequestBody;
  26. import org.springframework.web.bind.annotation.RequestMapping;
  27. import org.springframework.web.bind.annotation.RequestMethod;
  28. import org.springframework.web.bind.annotation.RestController;
  29. import javax.servlet.http.HttpServletRequest;
  30. import java.util.Arrays;
  31. import java.util.List;
  32. import static com.ym.mec.common.controller.BaseController.succeed;
  33. @RestController
  34. @RequestMapping("/user")
  35. public class UserController {
  36. private static final Logger log = LoggerFactory.getLogger(UserController.class);
  37. @Autowired
  38. private UserService userService;
  39. @Autowired
  40. private ImLiveBroadcastRoomService imLiveBroadcastRoomService;
  41. @Autowired
  42. private LiveRoomService liveRoomService;
  43. @Autowired
  44. private LivePluginContext livePluginContext;
  45. @Autowired
  46. private RoomService roomService;
  47. @Autowired
  48. private ImGroupService imGroupService;
  49. @RequestMapping(value = "/register", method = RequestMethod.POST)
  50. public Object register(@RequestBody UserModel userModel) throws Exception {
  51. return userService.register(userModel);
  52. }
  53. @RequestMapping(value = "/update", method = RequestMethod.POST)
  54. public Object update(@RequestBody UserModel userModel) throws Exception {
  55. return userService.update(userModel);
  56. }
  57. /**
  58. * 监听融云用户状态变更
  59. *
  60. * @param userState List<ImUserState>
  61. */
  62. @PostMapping(value = "/statusImUser")
  63. public BaseResponse statusImUser(@RequestBody List<ImUserState> userState) {
  64. log.info("statusImUser >>>>> : {}", JSONObject.toJSONString(userState));
  65. imLiveBroadcastRoomService.opsRoom(userState);
  66. return new BaseResponse<>();
  67. }
  68. /**
  69. * 监听融云用户状态变更
  70. *
  71. * @param userState List<ImUserState>
  72. */
  73. @PostMapping(value = "/update/statusImUser")
  74. public Object updateStatusImUser(@RequestBody List<ImUserState> userState) {
  75. log.info("statusImUser >>>>> : {}", JSONObject.toJSONString(userState));
  76. imLiveBroadcastRoomService.opsRoom(userState);
  77. return succeed();
  78. }
  79. @PostMapping(value = "/syncLikeCount")
  80. public Object syncLikeCount(String roomUid) {
  81. log.info("statusImUser >>>>> : {}", JSONObject.toJSONString(roomUid));
  82. imLiveBroadcastRoomService.syncLikeCount(roomUid);
  83. return succeed();
  84. }
  85. @ApiOperation("腾讯im 回调接口")
  86. @PostMapping(value = "/tencentImCallback")
  87. public TencentImCallbackResult tencentImCallback(@RequestBody String body, HttpServletRequest request) {
  88. log.info("tencentImCallback body:{}", body);
  89. LivePluginService pluginService = livePluginContext.getPluginService(TencentCloudLivePlugin.PLUGIN_NAME);
  90. String appKey = pluginService.getLiveRoomConfig().getAppKey();
  91. log.info("tencentImCallback request param:{}", JSON.toJSONString(request.getParameterMap()));
  92. List<String> sdkList = Arrays.asList(request.getParameterValues("SdkAppid"));
  93. if (sdkList == null || sdkList.size() == 0) {
  94. log.error("tencentImCallback sdkAppid is null");
  95. return new TencentImCallbackResult();
  96. }
  97. if (!sdkList.contains(appKey)) {
  98. log.error("tencentImCallback sdkAppid is not match");
  99. return new TencentImCallbackResult();
  100. }
  101. String clientIP = request.getParameter("ClientIP");
  102. String optPlatform = request.getParameter("OptPlatform");
  103. if(request.getParameter("CallbackCommand").equals(ETencentImCallbackCommand.GROUP_CALLBACKONMEMBERSTATECHANGE.getCommand())) {
  104. // 直播群成员在线状态回调
  105. TencentData.CallbackOnMemberStateChange callbackOnMemberStateChange = TencentData.CallbackOnMemberStateChange.toObject(
  106. body);
  107. log.debug("callbackOnMemberStateChange: {}", callbackOnMemberStateChange);
  108. callbackOnMemberStateChange.setClientIP(clientIP);
  109. callbackOnMemberStateChange.setOptPlatform(optPlatform);
  110. if (callbackOnMemberStateChange.getGroupId().startsWith("LIVE")) {
  111. for (TencentData.MemberListDTO memberListDTO : callbackOnMemberStateChange.getMemberList()) {
  112. if (!imGroupService.checkImUserId(memberListDTO.getMemberAccount())) {
  113. return new TencentImCallbackResult();
  114. }
  115. }
  116. // 直播间成员状态变更
  117. imLiveBroadcastRoomService.callbackOnMemberStateChange(callbackOnMemberStateChange);
  118. // 直播课学生签退
  119. String[] values = callbackOnMemberStateChange.getGroupId().split("-");
  120. String roomId = values.length > 2 ? values[1] : "";
  121. // 直播课学生签退、签退
  122. if ((roomId.startsWith("S") || roomId.startsWith("I"))
  123. && CollectionUtils.isNotEmpty(callbackOnMemberStateChange.getMemberList())) {
  124. // 学生编号
  125. String userId = callbackOnMemberStateChange.getMemberList().get(0).getMemberAccount();
  126. if (!imGroupService.checkImUserId(userId)) {
  127. return new TencentImCallbackResult();
  128. }
  129. String eventType = callbackOnMemberStateChange.getEventType();
  130. // 学生离线消息通知
  131. if ("Offline".equals(eventType)) {
  132. try {
  133. roomService.leaveRoomSuccess(roomId, userId, null);
  134. } catch (Exception e) {
  135. log.error("tencentImCallback leaveRoomSuccess error, roomId={}, userId={}", roomId, userId, e);
  136. }
  137. }
  138. // 学生在线消息通知
  139. if ("Online".equals(eventType)) {
  140. try {
  141. roomService.joinRoomSuccess(roomId, userId, null);
  142. } catch (Exception e) {
  143. log.error("tencentImCallback joinRoomSuccess error, roomId={}, userId={}", roomId, userId, e);
  144. }
  145. }
  146. }
  147. }
  148. } else if(request.getParameter("CallbackCommand").equals(ETencentImCallbackCommand.GROUP_CALLBACKAFTERMEMBEREXIT.getCommand())) {
  149. // 群成员离开之后回调
  150. TencentData.CallbackAfterMemberExit callbackAfterMemberExit = TencentData.CallbackAfterMemberExit.toObject(
  151. body);
  152. log.debug("callbackAfterMemberExit: {}", callbackAfterMemberExit);
  153. callbackAfterMemberExit.setClientIP(clientIP);
  154. callbackAfterMemberExit.setOptPlatform(optPlatform);
  155. if (callbackAfterMemberExit.getGroupId().startsWith("LIVE")) {
  156. for (TencentData.MemberListDTO memberListDTO : callbackAfterMemberExit.getExitMemberList()) {
  157. if (!imGroupService.checkImUserId(memberListDTO.getMemberAccount())) {
  158. return new TencentImCallbackResult();
  159. }
  160. }
  161. // 直播间成员状态变更
  162. imLiveBroadcastRoomService.callbackAfterMemberExit(callbackAfterMemberExit);
  163. // 直播课学生签退
  164. String[] values = callbackAfterMemberExit.getGroupId().split("-");
  165. String roomId = values.length > 2 ? values[1] : "";
  166. // 直播课学生签退、签退
  167. if ((roomId.startsWith("S") || roomId.startsWith("I"))
  168. && CollectionUtils.isNotEmpty(callbackAfterMemberExit.getExitMemberList())) {
  169. // 学生编号
  170. String userId = callbackAfterMemberExit.getExitMemberList().get(0).getMemberAccount();
  171. if (!imGroupService.checkImUserId(userId)) {
  172. return new TencentImCallbackResult();
  173. }
  174. try {
  175. roomService.leaveRoomSuccess(roomId, userId, null);
  176. } catch (Exception e) {
  177. log.error("tencentImCallback leaveRoomSuccess error, roomId={}, userId={}", roomId, userId, e);
  178. }
  179. }
  180. }
  181. } else if(request.getParameter("CallbackCommand").equals(ETencentImCallbackCommand.GROUP_CALLBACKAFTERNEWMEMBERJOIN.getCommand())) {
  182. // 新成员入群之后回调
  183. TencentData.CallbackAfterNewMemberJoin callbackAfterNewMemberJoin = TencentData.CallbackAfterNewMemberJoin.toObject(
  184. body);
  185. log.debug("CallbackAfterNewMemberJoin: {}", callbackAfterNewMemberJoin);
  186. callbackAfterNewMemberJoin.setClientIP(clientIP);
  187. callbackAfterNewMemberJoin.setOptPlatform(optPlatform);
  188. if (callbackAfterNewMemberJoin.getGroupId().startsWith("LIVE")) {
  189. for (TencentData.MemberListDTO memberListDTO : callbackAfterNewMemberJoin.getNewMemberList()) {
  190. if (!imGroupService.checkImUserId(memberListDTO.getMemberAccount())) {
  191. return new TencentImCallbackResult();
  192. }
  193. }
  194. // 直播间成员状态变更
  195. imLiveBroadcastRoomService.callbackAfterNewMemberJoin(callbackAfterNewMemberJoin);
  196. // 直播课学生签到
  197. String[] values = callbackAfterNewMemberJoin.getGroupId().split("-");
  198. String roomId = values.length > 2 ? values[1] : "";
  199. // 直播课学生签退、签退
  200. if ((roomId.startsWith("S") || roomId.startsWith("I"))
  201. && CollectionUtils.isNotEmpty(callbackAfterNewMemberJoin.getNewMemberList())) {
  202. // 学生编号
  203. String userId = callbackAfterNewMemberJoin.getNewMemberList().get(0).getMemberAccount();
  204. try {
  205. roomService.joinRoomSuccess(roomId, userId, null);
  206. } catch (Exception e) {
  207. log.error("tencentImCallback joinRoomSuccess error, roomId={}, userId={}", roomId, userId, e);
  208. }
  209. }
  210. }
  211. }
  212. return new TencentImCallbackResult();
  213. }
  214. private boolean checkStream(String streamId) {
  215. return imGroupService.checkImUserId(streamId.split("_",2)[1]);
  216. }
  217. @ApiOperation("腾讯云直播-推流 回调接口")
  218. @PostMapping(value = "/tencentStreamEventCallback")
  219. public TencentData.StreamEventCallbackResult tencentStreamEventCallback(@RequestBody String body) {
  220. log.info("tencentStreamEventCallback body:{}", body);
  221. TencentData.CallbackStreamStateEvent event = TencentData.CallbackStreamStateEvent.from(body);
  222. boolean b = checkStream(event.getStreamId());
  223. if (!b) {
  224. return TencentData.StreamEventCallbackResult.builder().code(0).build();
  225. }
  226. // 直播间推流事件
  227. if (event.getStreamId().startsWith("LIVE")) {
  228. ImUserState imUserState = new ImUserState();
  229. imUserState.setUserid(getSpeakerId(event.getStreamId()).toString());
  230. // 断流事件通知
  231. if (event.getEventType() == 0) {
  232. // 更新推流时长
  233. if (StringUtils.isNotBlank(event.getPushDuration()) && event.getPushDuration().matches("\\d+")) {
  234. // 更新直播推流时长
  235. imLiveBroadcastRoomService.updateLiveRoomPushStreamTime(event);
  236. }
  237. imUserState.setStatus("3");
  238. // 自动关闭录制
  239. imLiveBroadcastRoomService.closeLive(getRoomUid(event.getStreamId()), getSpeakerId(event.getStreamId()),event.getSequence());
  240. // 同步点赞数
  241. imLiveBroadcastRoomService.syncLikeCount(getRoomUid(event.getStreamId()));
  242. }
  243. // 推流事件通知
  244. if (event.getEventType() == 1) {
  245. // 自动开启录制
  246. imLiveBroadcastRoomService.startLive(getRoomUid(event.getStreamId()), getSpeakerId(event.getStreamId()), null,event.getSequence());
  247. imUserState.setStatus("0");
  248. }
  249. //imLiveBroadcastRoomService.opsRoom(Lists.newArrayList(imUserState));
  250. }
  251. return TencentData.StreamEventCallbackResult.builder().code(0).build();
  252. }
  253. private Integer getSpeakerId(String streamId) {
  254. return Integer.parseInt(streamId.split("_")[1]);
  255. }
  256. private String getRoomUid(String streamId) {
  257. return streamId.split("_")[0];
  258. }
  259. @ApiOperation("腾讯云直播-录制 回调接口")
  260. @PostMapping(value = "/tencentStreamRecordCallback")
  261. public TencentData.StreamEventCallbackResult tencentStreamRecordCallback(@RequestBody String body) {
  262. log.info("tencentStreamRecordCallback body:{}", body);
  263. TencentData.CallbackSteamRecordEvent event = TencentData.CallbackSteamRecordEvent.from(body);
  264. boolean b = checkStream(event.getStreamId());
  265. if (!b) {
  266. return TencentData.StreamEventCallbackResult.builder().code(0).build();
  267. }
  268. // 直播录制事件通知
  269. if (event.getStreamId().startsWith("LIVE")) {
  270. log.info("taskId={}, url={}", event.getTaskId(), event.getVideoUrl());
  271. // 生成直播录制信息
  272. liveRoomService.createLiveRoomVideoRecord(event);
  273. }
  274. return TencentData.StreamEventCallbackResult.builder().code(0).build();
  275. }
  276. @ApiOperation("腾讯云直播-推流异常 回调接口")
  277. @PostMapping(value = "/tencentStreamExceptionCallback")
  278. public TencentData.StreamEventCallbackResult tencentStreamExceptionCallback(@RequestBody String body) {
  279. log.info("tencentStreamExceptionCallback body:{}", body);
  280. return TencentData.StreamEventCallbackResult.builder().code(0).build();
  281. }
  282. }