YH_SocketService.m 12 KB
//
//  YH_SocketService.m
//  Yoho
//
//  Created by Arthur on 16/6/16.
//  Copyright © 2016年 YOHO. All rights reserved.
//

#import "YH_SocketService.h"
#import "GCDAsyncSocket+SocketHandler.h"

#define TimeIntervalForHeartBeat    30
#define SOCKET_COMMAND          @"cmd"
#define SOCKET_CONNECT_MAX_COUNT        9

@interface YH_SocketService ()<GCDAsyncSocketDelegate>
{
    GCDAsyncSocket *_socket;
    NSTimer *_heartBeatTimer; // ❤️
    BOOL _hasLoginWithNameSuccessed;
}
@property (nonatomic, strong) NSTimer *connectTimer;

@end


@implementation YH_SocketService

- (instancetype)init
{
    self = [super init];
    if (self) {
        _socket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
        _heartBeatTimer = [NSTimer scheduledTimerWithTimeInterval:TimeIntervalForHeartBeat target:self selector:@selector(_heartbeat) userInfo:nil repeats:YES];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkReachabilityDidChange:) name:AFNetworkingReachabilityDidChangeNotification object:nil];

    }
    
    return self;
}

- (NSString *)getProperIPWithAddress:(NSString *)ipAddr port:(UInt32)port
{
    NSError *addresseError = nil;
    NSArray *addresseArray = [GCDAsyncSocket lookupHost:ipAddr
                                                   port:port
                                                  error:&addresseError];
    if (addresseError) {
        NSLog(@"");
    }
    
    NSString *ipv6Addr = @"";
    for (NSData *addrData in addresseArray) {
        if ([GCDAsyncSocket isIPv6Address:addrData]) {
            ipv6Addr = [GCDAsyncSocket hostFromAddress:addrData];
        }
    }
    
    if (ipv6Addr.length == 0) {
        ipv6Addr = ipAddr;
    }
    
    return ipv6Addr;
}

//网络发生变化时重连
- (void)networkReachabilityDidChange:(NSNotification *)notification
{
    [_socket disconnect];
    [self connectToHostRepeat];
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}


- (void)reset
{
    DLog(@"socket service reset!!");
    if (_heartBeatTimer) {
        [_heartBeatTimer invalidate];
        _heartBeatTimer = nil;
    }
    
    [_socket disconnect];
}

#pragma mark - Private Methods
- (void)_heartbeat{
    
    
//    //TEST
//    self.userName = [NSString stringWithFormat:@"%@",[NSDate date]];
//    self.uid = [NSString stringWithFormat:@"%@",[NSDate date]];
//    self.avartar = @"http://img02.yohoboys.com/contentimg/2016/06/16/15/021a29c892e7088fd7d96cbd41519da50d.jpg";
//    [self sendMessage:@"21313"];
//    [self userPraise];

    
    NSDictionary *params = @{@"cmd":@(SOCKET_TAG_HEARTBEAT),
                             @"msg":@"heart_ios",
                             @"room":MakeStringNotNil(self.room),
                             };
    [_socket writeDataWithParams:params tag:SOCKET_TAG_SEND_MSG];
    
//    [self loginToServer];
//    [self listenData];

}

#pragma mark - Service
- (BOOL)connect
{
    [self getAddressList:^(BOOL flag, NSError *error) {
        if (flag) {
            [self generateRandomHostAndPort];
            if (![self connectToHost:self.socketLiveHost onPort:self.socketLivePort]) {
                self.connectTimer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(connectToHostRepeat) userInfo:nil repeats:YES];
                [[NSRunLoop mainRunLoop] addTimer:self.connectTimer forMode:NSRunLoopCommonModes];
            } else {
                NSLog(@"connent success!");
            }
        } else {
            NSLog(@"get addressList failed!");
        }
    }];
    
    return YES;
}

- (void)getAddressList:(BoolBlock)block
{
    [self barrageList:nil completionBlock:^(NSMutableArray *models, NSError *error) {
        if (error) {
            if (block) {
                block(NO, error);
            }
        }else {
            self.addressList = models;
            if (block) {
                block(YES, nil);
            }
        }
    }];
}

- (void)connectToHostRepeat
{
    if ([self connectToHost:self.socketLiveHost onPort:self.socketLivePort]) {
        [self.connectTimer invalidate];
        self.connectTimer = nil;
    }else {
        for (int i = 0; i < SOCKET_CONNECT_MAX_COUNT; i++) {
            [self generateRandomHostAndPort];
            if ([self connectToHost:self.socketLiveHost onPort:self.socketLivePort]){
                [self.connectTimer invalidate];
                self.connectTimer = nil;
                break;
            }
        }
    }
}

- (void)generateRandomHostAndPort
{
    int y = (arc4random() % [self.addressList count]);
    self.socketLiveHost = [self.addressList[y] objectForKey:@"ip"];
    self.socketLivePort = [[self.addressList[y] objectForKey:@"port"] integerValue];
}

- (BOOL)connectToHost:(NSString *)host onPort:(uint16_t)port
{
    NSString *hostProper = [self getProperIPWithAddress:host port:port];
    
    NSError *socketConnectError = nil;
    
    NSAssert(_socket, @"You must init YH_SocketService first!");
    
    [_socket connectToHost:hostProper onPort:port error:&socketConnectError];
    
    if (socketConnectError) {
        DLog(@"connect host error: %@", [socketConnectError localizedDescription]);
        
        return NO;
    } else {
        return YES;
    }
}

- (BOOL)writeDataWithParams:(NSDictionary *)params tag:(long)tag
{
    NSAssert(_socket, @"You must init YH_SocketService first!");
    return [_socket writeDataWithParams:params tag:tag];
}

#pragma mark - GCDAsyncSocketDelegate

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
    DLog(@"socket connect success!");
    [self loginToServer];
    [self listenData];
}



- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
    if (err) {
        NSLog(@"%@",err);
        
        // 断线重连
        [sock connectToHost:self.socketLiveHost onPort:self.socketLivePort error:nil];
    }
}

// 数据成功发送到服务器
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
    
    
    switch (tag) {
        case SOCKET_TAG_LOGIN:
        {
            [self _heartbeat];
        }
            break;
            
        case SOCKET_TAG_RESIVE_MSG:
        {
            
            
        }
            break;
            
        default:
            break;
    }
    
    [self listenData];
}


- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    
//    NSString * str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    
    [sock didWriteDataWithParams:data tag:tag dataProcessingHandler:^(NSDictionary *resDic) {
        //过滤当前用户的信息 新用户加入  赞
//        if (resDic && [resDic.allKeys containsObject:@"uid"] && [resDic[@"uid"] isEqualToString:self.uid])
//        {
//            if (resDic && [resDic.allKeys containsObject:SOCKET_COMMAND]) {
//                int cmd = [[resDic objectForKey:SOCKET_COMMAND] intValue];
//                if(cmd == SOCKET_TAG_USER_JOIN)
//                {
//                    return;
//                }
//            }
//           
//        }
        
        if (resDic && [resDic.allKeys containsObject:SOCKET_COMMAND]) {
            int cmd = [[resDic objectForKey:SOCKET_COMMAND] intValue];
            switch (cmd) {
                case SOCKET_TAG_RESIVE_MSG:
                case SOCKET_TAG_USER_JOIN:
                {
                    if (resDic && [resDic.allKeys containsObject:@"uid"] && [resDic[@"uid"] isEqualToString:self.uid] && [self.uid notNilOrEmpty]) {
                        _hasLoginWithNameSuccessed = YES;
                    }
                    [self.barrageViewController insertItem:resDic];
                }
                    break;
                case SOCKET_TAG_NotifyPRAISE:
                {
                    if ([self.delegate respondsToSelector:@selector(userPraised:isSelfPraise:)] && [resDic.allKeys containsObject:@"msg"]) {
                        yh_dispatch_execute_in_main_queue(^{
                            
                            [self.delegate userPraised:resDic[@"msg"] isSelfPraise:([resDic[@"uid"] isEqualToString:self.uid])];
                        });
                    }
                }
                    break;
                case SOCKET_TAG_NotifyPeopleNumber:
                {
                    if ([self.delegate respondsToSelector:@selector(currentPeopleNumber:)] && [resDic.allKeys containsObject:@"msg"]) {
                        yh_dispatch_execute_in_main_queue(^{
                            [self.delegate currentPeopleNumber:resDic[@"msg"]];
                        });
                    }
                }
                    break;
                case SOCKET_TAG_NotifyEndPlay:
                {
                    if ([self.delegate respondsToSelector:@selector(livePalyEnd:likeNums:videoLen:)]) {
                        yh_dispatch_execute_in_main_queue(^{
                           [self.delegate livePalyEnd:resDic[@"audienceNums"] likeNums:resDic[@"likeNums"] videoLen:resDic[@"videoLen"]];
                        });
                    }
                }
                    break;
                default:
                    break;
            }
        }
    }];
    
    [self listenData];

}

-(void)listenData {
    
    [_socket readDataToData:[GCDAsyncSocket LFData] withTimeout:-1 tag:1];
}

- (void)logout
{
    if (_heartBeatTimer) {
        [_heartBeatTimer invalidate];
        _heartBeatTimer = nil;
    }
    if (_connectTimer) {
        [self.connectTimer invalidate];
        self.connectTimer = nil;
    }
    [_socket disconnect];
}

//testOK
- (void)loginToServer
{
    NSDictionary *params = @{@"cmd":@(SOCKET_TAG_LOGIN),
                             @"uid":(_hasLoginWithNameSuccessed?@"":MakeStringNotNil(self.uid)),
                             @"room":MakeStringNotNil(self.room),
                             @"name":(_hasLoginWithNameSuccessed?@"":MakeStringNotNil(self.userName)),
                             @"avatar":(_hasLoginWithNameSuccessed?@"":MakeStringNotNil(self.avartar)),
                             };
    
    [_socket writeDataWithParams:params tag:SOCKET_TAG_LOGIN];

}

//testOK
- (void)sendMessage:(NSString *)msg
{
    NSDictionary *params = @{@"cmd":@(SOCKET_TAG_SEND_MSG),
                             @"uid":MakeStringNotNil(self.uid),
                             @"msg":MakeStringNotNil(msg),
                             @"name":MakeStringNotNil(self.userName),
                             @"avatar":MakeStringNotNil(self.avartar),
                             @"room":MakeStringNotNil(self.room)
                             };
    [_socket writeDataWithParams:params tag:SOCKET_TAG_SEND_MSG];
}

//testOK
- (void)userPraise
{
    NSDictionary *params = @{@"cmd":@(SOCKET_TAG_PRAISE),
                             @"uid":MakeStringNotNil(self.uid),
                             @"msg":@"",
                             @"room":MakeStringNotNil(self.room)
                             };
    [_socket writeDataWithParams:params tag:SOCKET_TAG_SEND_MSG];
}

//结束播放//testOK
- (void)endPaly:(NSString *)videoLen
{
    NSDictionary *params = @{@"cmd":@(SOCKET_TAG_EndPlay),
                             @"uid":MakeStringNotNil(self.uid),
                             @"msg":@"",
                             @"videoLen":MakeStringNotNil(videoLen),
                             @"room":MakeStringNotNil(self.room)
                             };
    [_socket writeDataWithParams:params tag:SOCKET_TAG_SEND_MSG];
}

- (AFHTTPRequestOperation *)barrageList:(NSDictionary *)parameters completionBlock:(ArrayBlock)block
{
    return [[M16HttpClient BaseSharedClient] GET:GET_BARRAGELIST parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
        
        NSArray *addressList = responseObject;
        if (block) {
            block([NSMutableArray arrayWithArray:addressList], nil);
        }
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        
        if (block) {
            block([NSMutableArray array], error);
        }
        
    }];
}

@end