| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430 |
- //
- // GWebSocket.m
- // TUIContact
- //
- // Created by gan on 2025/3/24.
- //
- #import <Foundation/Foundation.h>
- #import "GWebSocket.h"
- #import "SocketRocket/SRWebSocket.h"
- //#import "AFNetworking/AFNetworkReachabilityManager.h"
- #import "GDBManager.h"
- //#import "AFNetworkReachabilityManager.h"
- #import "ChatListStore.h"
- #import "ChatsStore.h"
- #import "WebRTCStore.h"
- #import "UserNetApi.h"
- static int const kHeartbeatDuration = 1;
- static int const timeoutError = 5;
- static NSString *ping = @"{\"code\":0}";
- static NSString *redeady = @"{\"code\":1}";
- @interface GWebSocket ()<SRWebSocketDelegate>
- @property (nonatomic,strong) SRWebSocket *socket;
- @property (strong, nonatomic) NSTimer *heatBeat;
- @property (nonatomic,strong) NSString *serverIpString;
- @property (nonatomic,strong) NSString *userid;
- @property (nonatomic,assign) BOOL autoReconnect;
- @property (nonatomic,assign) NSInteger pingCount;
- @property (nonatomic,assign) NSInteger reconnetCount;
- @property (nonatomic,assign) BOOL isFirstload;
- @property (nonatomic,strong) NSString *UUID;
- @end
- @implementation GWebSocket
- + (GWebSocket *_Nonnull)shareInstance{
- static id gShareInstance = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- gShareInstance = [[self alloc] init];
- });
- return gShareInstance;
- }
- - (instancetype)init {
- if (self = [super init]) {
- self.pingCount = 0;
- self.reconnetCount = 0;
- NSUUID *uid = [NSUUID UUID];
- _UUID=uid.UUIDString;
- NSLog(@"_UUID:%@",_UUID);
- }
- return self;
- }
- #pragma mark - Public -
- - (void)connectWebSocket {
- self.autoReconnect = YES;
- [self initWebSocket];
- [self startHeartbeat];
- }
- - (void)closeWebSocket {
- self.autoReconnect = NO;
- // _UUID=nil;
- [self close];
- }
- #pragma mark 探测socket 状态
- - (void)chekWebSocket{
-
- }
- - (void)sendMsg:(NSString *)msg {
- if (self.socket && self.socket.readyState == SR_OPEN) {
- // 只有在socket状态为SR_OPEN 时,才可以发送消息
- // 在socket状态不为SR_OPEN,可以将消息放进队列里,在websocket连上时,再发送
- NSLog(@"sendMsg:%@",msg);
- [self.socket sendString:msg error:nil];
- }
- else{
- NSLog(@"socket--------不可用");
- [self reConnect];
- }
- // NSLog(@"_UUID:%@",_UUID);
- }
- #pragma mark -- WebSocket
- //初始化 WebSocket
- - (void)initWebSocket{
- if (_socket) {
- return;
- }
- self.isFirstload =YES;
- // [self destoryHeartbeat];
- NSDictionary *userinfo =[UDManager.shareInstance getDDManager:dkuserinfo];
- self.userid =userinfo[@"id"];
-
- NSString *token = (NSString *)[UDManager.shareInstance getSDManager:gkeytoken];
- if(_UUID==nil){
- NSUUID *uid = [NSUUID UUID];
- _UUID=uid.UUIDString;
- }
- NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@token=%@&client=mobile&uuid=%@",WebSocketUrl,token,_UUID]];
- //请求
- //NSLog(@"url:%@",url);
- NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
- //初始化请求`
- _socket = [[SRWebSocket alloc] initWithURLRequest:request];
-
- //代理协议`
- _socket.delegate = self;
- //直接连接
- [_socket open];
- }
- -(void)sendReady{
- NSLog(@"------%@",redeady);
- [self.socket sendString:redeady error:nil];
- }
- -(void)sendPing{
- [self.socket sendString:ping error:nil];
- }
- #pragma mark - Heart Timer -
- //保活机制 探测包
- - (void)startHeartbeat {
- if(self.heatBeat){
- return;
- }
- self.heatBeat = [NSTimer scheduledTimerWithTimeInterval:kHeartbeatDuration target:self selector:@selector(heartbeatAction) userInfo:nil repeats:YES];
- [self.heatBeat setFireDate:[NSDate distantPast]];
- [[NSRunLoop currentRunLoop] addTimer:_heatBeat forMode:NSRunLoopCommonModes];
- }
- //断开连接时销毁心跳
- - (void)destoryHeartbeat{
- if(self.heatBeat){
- [self.heatBeat invalidate];
- self.heatBeat = nil;
- }
- }
- // 发送心跳
- - (void)heartbeatAction {
- if (self.socket.readyState == SR_OPEN) {
- // NSLog(@"heartbeatAction1111");
- self.pingCount = self.pingCount+1;
- self.reconnetCount = self.reconnetCount+1;
- if(self.pingCount>5){//连续多次发送ping 没有收到回复,发起重连;
- [self.socket close];
- self.socket = nil;
- self.pingCount=0;
- [self reConnect];
- }
- if(self.pingCount>=3&&self.socket){
- [self sendPing];
- }
- }
- else{
- // NSLog(@"heartbeatAction222");
- self.pingCount = self.pingCount+1;
- self.reconnetCount = self.reconnetCount+1;
- if(self.pingCount>5){//连续多次发送ping 没有收到回复,发起重连;
- [self.socket close];
- self.socket = nil;
- self.pingCount=0;
- [self reConnect];
- }
- }
- }
- //重连机制
- - (void)reConnect{
- if (!self.autoReconnect) {
- return;
- }
-
- self.socket = nil;
- [self initWebSocket];
-
- // NSLog(@"reConnect1111---------:%ld",(long)self.reconnetCount);
- if(self.reconnetCount>15){
- NSString *token = [UDManager.shareInstance getSDManager:gkeytoken];
- if([token isKindOfClass:[NSString class]]&&token.length>10){
- [UserNetApi getUserinfo:^(int code, NSDictionary * res) {
- NSNumber *gcode=res[@"code"];
- NSLog(@"gcode11");
- if([gcode intValue]==401){//token有效
- [self logoutAct];
- }
- } fail:^(NSError * _Nonnull error) {
- NSLog(@"11%@", error);
- }];
- }
- }
-
- }
- // 关闭Socket
- - (void)close {
- [self destoryHeartbeat];
- [self.socket close];
- self.socket = nil;
- }
- #pragma mark -- SRWebSocketDelegate
- //收到服务器消息是回调
- - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message{
- //NSLog(@"----XTWebSocket didReceiveMessage:%@",message);
- if ([message isKindOfClass:[NSString class]]) {
- NSString *msg = (NSString *)message;
- NSError *error;
- self.pingCount = 0;
- self.reconnetCount = 0;
- if([msg isEqual:ping]){
- if(self.isFirstload){//第一次打开socket数据加载完成需要执行的
-
- }
- return;
- }
- // NSLog(@"didReceiveMessage:%@",msg);
- NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];
-
- NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
- if (error) {
- NSLog(@"JSON解析错误: %@", error);
- } else {
- // NSLog(@"解析后的字典: %@", jsonDict);
- NSString *code =jsonDict[@"code"];
- if([code isEqualToString:SendCode_MESSAGE]){//收到消息数据
- [self onmessage:jsonDict[@"message"]];
- return;
- }
- if([code isEqualToString:SendCode_READ]){//已读消息
- [self onRead:jsonDict[@"message"]];
- return;
- }
- if([code isEqualToString:SendCode_OTHER_LOGIN]){//账号在其他地方登陆
- NSDictionary *mmsg = jsonDict[@"message"];
- NSString *uuid =mmsg[@"uuid"];
- if([uuid isEqualToString:_UUID]){
- return;
- }
- else{
- [self logoutAct];
- }
- return;
- }
- if([code isEqualToString:SendCode_NEW_FRIEND]){//好友申请
- NSLog(@"好友申请----------");
- [[NSNotificationCenter defaultCenter] postNotificationName: nkonAddFriendNote object:nil];
- return;
- }
- if([code isEqualToString:SendCode_GROUP_VALIDATE]){//群申请验证
- [[NSNotificationCenter defaultCenter] postNotificationName: nkonEXGroupdNote object:nil];
- return;
- }
- if([code isEqualToString:SendCode_WEBRTC_result]){//音视频通话结果
- [self onmessage:jsonDict[@"message"]];
- return;
- }
- if([code isEqualToString:SendCode_WEBRTC_CALL]){//音视频通话请求
- [WebRTCStore.shareInstance reciveMsg:jsonDict[@"message"]];
- return;
- }
- if([code isEqualToString:SendCode_WEBRTC_CLOSE]){//关闭音视频通话
- [WebRTCStore.shareInstance reciveMsg:jsonDict[@"message"]];
- return;
- }
- if([code isEqualToString:SendCode_WEBRTC_BUSY]){//音视频通话忙碌
- [WebRTCStore.shareInstance reciveMsg:jsonDict[@"message"]];
- return;
- }
- if([code isEqualToString:SendCode_WEBRTC_xinling]){//webrtc信令交互
- [WebRTCStore.shareInstance reciveMsg:jsonDict[@"message"]];
- return;
- }
- if([code isEqualToString:SendCode_deletemsg]){//删除消息
-
- return;
- }
- if([code isEqualToString:SendCode_WEBRTC_DFBUSY]){//对方正在忙
- [WebRTCStore.shareInstance reciveMsg:jsonDict[@"message"]];
- return;
- }
- if([code isEqualToString:SendCode_RECMsg]){//收到消息回执
-
- return;
- }
- }
- if(self.delegate){
- [self.delegate GWebSocketAction:message];
- }
- }
- }
- //连接成功
- - (void)webSocketDidOpen:(SRWebSocket *)webSocket{
- NSLog(@"-----XTWebSocket DidOpen");
-
- // 下面逻辑,根据业务情况处理
- if (self.socket != nil) {
- // 只有 SR_OPEN 开启状态才能调 send 方法啊,不然要崩
- if (_socket.readyState == SR_OPEN) {
- //NSString *jsonString = @"{\"sid\": \"13b313a3-fea9-4e28-9e56-352458f7007f\"}";
- //[_socket sendString:jsonString error:nil]; //发送数据包
- [self sendReady];
- } else if (_socket.readyState == SR_CONNECTING) {
- NSLog(@"正在连接中,重连后其他方法会去自动同步数据");
- // 每隔2秒检测一次 socket.readyState 状态,检测 10 次左右
- // 只要有一次状态是 SR_OPEN 的就调用 [ws.socket send:data] 发送数据
- // 如果 10 次都还是没连上的,那这个发送请求就丢失了,这种情况是服务器的问题了,小概率的
- // 代码有点长,我就写个逻辑在这里好了
-
- } else if (_socket.readyState == SR_CLOSING || _socket.readyState == SR_CLOSED) {
- // websocket 断开了,调用 reConnect 方法重连
- NSLog(@"websocket 断开了,调用 reConnect 方法重连");
- [self reConnect];
- }
- }
- }
- //连接失败的回调
- - (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error{
- NSLog(@"XTWebSocket didFailWithError %@",error);
- // 1.判断当前网络环境,如果断网了就不要连了,等待网络到来,在发起重连
- // 2.判断调用层是否需要连接,例如用户都没在聊天界面,连接上去浪费流量
-
- // [self reConnect];
- }
- //连接断开的回调
- - (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean{
- NSLog(@"XTWebSocket Close code %ld reason %@",(long)code,reason);
- }
- - (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload {
- NSLog(@"XTWebSocket Pong");
- }
- #pragma mark - 其他 -
- - (void)dealloc {
- NSLog(@"LFC: dealloc: %@", self);
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- }
- #pragma mark -数据处理-
- -(void)onmessage:(NSDictionary *)msg{
- NSLog(@"onmessage:%@",msg);
- // NSLog(@"%@",msg[@"chatId"]);
- // NSLog(@"%@",msg[@"fromId"]);
- //NSLog(@"%@",msg[@"content"]);
-
- NSMutableDictionary *mutablemsg = [msg mutableCopy];
-
-
- if([self.userid isEqual:msg[@"fromId"]]){
- [mutablemsg setObject:[NSNumber numberWithBool:YES] forKey:@"mine"];
- // NSLog(@"----------------------11");
- [ChatsStore.shareInstance deleteMineTmpMsg:msg];//删除本地临时消息
- }else{
- if([Friendchat isEqual:msg[@"type"]]){
- [mutablemsg setObject:msg[@"fromId"] forKey:@"chatId"];
- }
- }
- [ChatsStore.shareInstance reciveMsg:mutablemsg];//聊天窗信息
- [ChatListStore.shareInstance reciveMsg:[mutablemsg copy]];//聊天窗列表
- [[NSNotificationCenter defaultCenter] postNotificationName:nkonNewMessageNote object:mutablemsg];
- }
- //消息已收到回执
- -(void)sendRecNote:(NSDictionary *)msg{
- NSDictionary *dic =@{
- @"chatId":msg[@"chatId"],
- @"userId":self.userid,
- @"msgId":msg[@"id"],
- @"type":msg[@"type"]
- };
- NSDictionary *sendInfo = @{
- @"code":SendCode_RECMsg,
- @"message":dic,
- };
- NSError *error;
- NSData *jsonData = [NSJSONSerialization dataWithJSONObject:sendInfo options:0 error:&error];
- if (!jsonData) {
- NSLog(@"Got an error: %@", error);
- } else {
- NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
- // NSLog(@"jsonString:%@",jsonString);
- [self sendMsg:jsonString];
- }
- }
- //收到已读消息
- -(void)onRead:(NSDictionary *)dis{
- [ChatsStore.shareInstance updatereadTime:dis];
- }
- //异地登录
- -(void)logoutAct{
- NSLog(@"logoutAct");
- [UserNetApi logout:nil succ:^(int code, NSDictionary * res) {
- // NSLog(@"res:%@",res);
- [[NSNotificationCenter defaultCenter] postNotificationName: nkonLogoutSucc object:nil];
- } fail:^(NSError * _Nonnull error) {
- NSLog(@"");
- }];
- }
- @end
|