PhobosDataManager.m 8.62 KB
//
//  PhobosDataManager.m
//  GMCache
//
//  Created by Locus on 2020/1/21.
//

#import "PhobosDataManager.h"
#import "PhobosSendManager.h"
#import "PhobosConfig.h"
#import "PhobosUtil.h"
#import "GMSQliteManager.h"
#import "GMPhobosSqulitModel.h"
#import "GMPhobosPageViewModel.h"
#import <MJExtension/MJExtension.h>
#import "GMPhobosThread.h"
#import "GMPhobosTool.h"
#define KtableName @"phobosTable"
#define KPageViewTableName @"pageViewTable"

#define KName @"tableName"
#define KClass @"class"

@interface PhobosDataManager ()
//数据库操作对象(单利)
@property (nonatomic, strong) GMSQliteManager *squlitManager;
/// 记录没有发送的数据个数(大于50 就要发送数据)
@property (nonatomic, assign) NSInteger messageCont;
/// runloop线程,用来处理埋点的数据
@property (nonatomic, strong) GMPhobosThread *phobosThread;
@property (nonatomic, strong) NSArray *tableMessageArray;
@end

@implementation PhobosDataManager

static PhobosDataManager *dataManager;

+ (PhobosDataManager *)sharedPhobosDataManager {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        dataManager = [[PhobosDataManager alloc] init];
    });
    return dataManager;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _tableMessageArray = @[
            @{
                KName:KtableName,
                KClass:[GMPhobosSqulitModel class]
            },
            @{
                KName:KPageViewTableName,
                KClass:[GMPhobosPageViewModel class]
            }
        ];
        [self setupSDK];
    }
    return self;
}

- (void)removeAll {
    [self performSelector:@selector(remove) onThread:_phobosThread withObject:nil waitUntilDone:YES];
}

- (void)remove {
    bool status = [_squlitManager gm_deleteAllDataFromTable:KtableName];
    bool status1 = [_squlitManager gm_deleteAllDataFromTable:KPageViewTableName];
    NSLog(@"清空表格数状态-KtableName:%d KPageViewTableName:%d",status,status1);
}

- (int)messageCount {
    int count = [_squlitManager gm_tableItemCount:KtableName whereFormat:nil];
    int count1 = [_squlitManager gm_tableItemCount:KPageViewTableName whereFormat:nil];
    NSLog(@"数据总数:%d - KtableName:%d KPageViewTableName:%d", count + count1, count, count1);
    return count;
}

#pragma mark - 初始化
- (void)setupSDK {
    //创建数据库和表格
    _squlitManager = [[GMSQliteManager alloc] init];
    for (NSDictionary *dict in _tableMessageArray) {
         [_squlitManager gm_createTable:dict[KName] model:dict[KClass]];
    }
    //初始化线程和runloop
    __weak typeof(self) weakSelf = self;
    _phobosThread = [[GMPhobosThread alloc] initWithBlock:^{
        [[NSRunLoop currentRunLoop] addPort:[NSPort new] forMode:NSDefaultRunLoopMode];
        while (weakSelf) {
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        }
    }];
    _phobosThread.name = @"phobosThread";
    [_phobosThread start];
    //修改数据
    [self performSelector:@selector(resetData) onThread:_phobosThread withObject:nil waitUntilDone:NO];
}

#pragma mark - 方法只用在APP启动的时候
- (void)resetData {
    for (NSDictionary *dict in _tableMessageArray) {
        /** 将上次没有获取到发送结果的数据的状态修改为发送失败,待下次重新发送 */
        NSString *whereStr = [NSString stringWithFormat:@"where status = %d", PhobosDataSendStatus_send];
        [_squlitManager gm_updateTable:dict[KName] dicOrModel:@{@"status":@(PhobosDataSendStatus_error)} whereFormat:whereStr];
        /** 将发送成功的数据删除 */
        NSString *whereDelet = [NSString stringWithFormat:@"where status = %d", PhobosDataSendStatus_finish];
        [_squlitManager gm_deleteTable:dict[KName] whereFormat:whereDelet];
    }
    
}

#pragma mark - 插入数据
- (void)insertData:(NSDictionary *)data
           sendAPI:(NSString *)sendAPI
        phobosType:(NSString *)phoboType
       immediately:(BOOL)status {
    if (!sendAPI || [sendAPI isEqualToString:@""] || !data) return;
    if ([phoboType containsString:@"page_view"]) {
        GMPhobosPageViewModel *squlitModel = [GMPhobosPageViewModel pageViewModelOfDict:data type:phoboType urlApi:sendAPI tableName:KPageViewTableName immediately:status];
        [self performSelector:@selector(insertModel:) onThread:_phobosThread withObject:squlitModel waitUntilDone:NO];
    } else {
        GMPhobosSqulitModel *squlitModel = [GMPhobosSqulitModel modelOfDict:data type:phoboType urlApi:sendAPI tableName:KtableName immediately:status];
        [self performSelector:@selector(insertModel:) onThread:_phobosThread withObject:squlitModel waitUntilDone:NO];
    }
}

- (void)insertModel:(GMPhobosSqulitModel *)squlitModel {

    BOOL insertType = [_squlitManager gm_insertTable:squlitModel.table_name model:squlitModel];
    if (!insertType) {//如果插入失败,就直接发送给服务器
        [self sendModelArray:@[squlitModel]];
    } else if (squlitModel.immediately) {//需要立刻发送的埋点
        [self disposeSendDataWithImmediately:YES];
    } else {//插入到数据中
        self.messageCont++;
        [self disposeSendDataWithImmediately:NO];
    }
    NSLog(@"插入%@状态%d count:%d",squlitModel.phobos_type, insertType,_messageCont);
}

#pragma mark - 获取待发送数据并修改状态为“发送”
- (NSMutableArray *)fetchToBeSendDataEntitiesAndUpdateWithSendStatus {
    NSString *where = [NSString stringWithFormat:@"where status = %d or status = %d", PhobosDataSendStatus_wait, PhobosDataSendStatus_error];
    NSMutableArray *array = [NSMutableArray array];
    for (NSDictionary *dict in _tableMessageArray) {
        /**获取待发送的数据*/
        NSArray *sub = [_squlitManager gm_lookupTable:dict[KName] filterArray:nil objectClass:dict[KClass] whereFormat:where];
        [array addObjectsFromArray:sub];
        /**将待发送的数据修改为“发送中”*/
        [_squlitManager gm_updateTable:dict[KName] dicOrModel:@{@"status":@(PhobosDataSendStatus_send)} whereFormat:where];
    }
    return array;
}

//获取待发送的数据个数
- (int)getAllTabelNeedSendMessageCount {
    int count = 0;
    NSString *where = [NSString stringWithFormat:@"where status = %d or status = %d", PhobosDataSendStatus_wait, PhobosDataSendStatus_error];
    for (NSDictionary *dict in _tableMessageArray) {
         int tableCount  = [_squlitManager gm_tableItemCount:dict[KName] whereFormat:where];
        count += tableCount;
    }
    return count;
}

#pragma mark - 是否需要发送数据
- (void)disposeSendDataWithImmediately:(BOOL)status {
    if (!status) {
        _messageCont = [self getAllTabelNeedSendMessageCount];
        if (_messageCont < PhobosShardCount) return;
    }
    /**
     能走到下面说明“满足上报埋点条件 status == yes || _messageCont >= PhobosShardCount”
     */
    NSMutableArray *entities = [self fetchToBeSendDataEntitiesAndUpdateWithSendStatus];
    if (entities.count >= PhobosMaxSendCount) { //大于100条 要对数据进行拆分
        //拆分数组
        NSArray *array = [GMPhobosTool splitArray:entities withSubSize:PhobosShardCount];
        for (NSArray *sub in array) {
            [self sendModelArray:sub];
        }
    } else {
        [self sendModelArray:entities];
    }
}

- (void)sendModelArray:(NSArray<GMPhobosSqulitModel *> *)entities {
    NSLog(@"发送*******%lld", entities.count);
    [PhobosSendManager sendDataWithEntities:entities completion:^(NSArray<GMPhobosSqulitModel *> *finishEntities, NSInteger code) {
        SEL selelct = code == 200 ?  @selector(sendSuccess:) :@selector(sendError:);
        [self performSelector:selelct onThread:_phobosThread withObject:finishEntities waitUntilDone:NO];
    }];
}

#pragma mark - 上报数据成功
- (void)sendSuccess:(NSArray<GMPhobosSqulitModel*> *)entities {
    for (GMPhobosSqulitModel *model in entities) {
        NSString *whereStr = [NSString stringWithFormat:@"where message_item_id = '%@'", model.message_item_id];
        bool status = [_squlitManager gm_deleteTable:model.table_name whereFormat:whereStr];
        NSLog(@"发送数据成功-删除状态:%d", status);
    }
}

#pragma mark - 上报数据失败
- (void)sendError:(NSArray<GMPhobosSqulitModel*> *)entities {
    for (GMPhobosSqulitModel *model in entities) {
        NSString *whereStr = [NSString stringWithFormat:@"where message_item_id = '%@'", model.message_item_id];
        bool status = [_squlitManager gm_updateTable:model.table_name
                                          dicOrModel: @{@"status":@(PhobosDataSendStatus_error)}
                                         whereFormat:whereStr];
        NSLog(@"发送失败后-修改状态:%d",status);
    }
}

@end