13. 上报模块实现
大家好,我是程序喵。
在前面几期中,我已经介绍过如何发起http通信,如何实现加解密功能,如何进行多线程开发,这一期,我会把这些能力整合到一起,完成整个上报模块。
在写代码前,首先要梳理出上报模块需要提供什么能力。我的设计是,上报模块可以提供一个开关,只要打开开关,塞进来的消息就会每隔一段时间自动上报,同时,之前由于网络等原因上报失败的数据,也会自动从数据库中提取出来并上报。
核心点就是:
- 有开关,需要每隔一段时间自动上报
- 上报失败的数据,需要有重试
梳理后,看下对应的头文件代码:
头文件代码中有几个关键点:
- BuriedData的结构定义:包含优先级、标题和详细数据,这三个由外部调用方传入具体数据
- 构造函数中的logger、common_service、work_path:因为整个SDK需要支持多实例,所以里面的各个模块,需要传递进来实际的子模块实例对象和工作目录。
- Start接口:整个上报模块的开关,调用此接口后,会自动获取数据并上报。
- InsertData接口:外部调用方想要上报某条数据就调用此接口,然后模块内部会自动挑时机上报这条数据,无需担心上报成功与否,只要调用此接口,数据就会上报成功。
- BuriedReportImpl:pimpl模式,C++中的一个很常用的设计模式,相关的实现都放在源文件中,不暴露到外边,这个模式建议大家重点学习。
然后我们再看它的实现:
这里就是使用的pimpl模式,BuriedReport相关实现其实是调用了BuriedReportImpl的相关方法。
BuriedReportImpl类的定义如下:
整个类不是只有Start和InsertData的public方法,还有好多个private方法,供类内部调用。
内部还有很多成员变量:
- logger_:打印日志的实例
- work_dir_:工作目录
- db_:数据库实例,数据库相关的方法都通过此实例调用
- common_service_:公共数据通过此实例获取
- crypt_:加解密相关的能力通过此实例调用
- timer_:定时器相关的能力使用此实例
- data_caches_:装载要上报的数据,会不停的从数据库中按优先级取数据,装载到这个cache中
构造函数
从代码中,可以看到,构造或赋值了logger和crypt对象后,通过ReportStrand调度Init_方法,看了后面的几个方法的实现后,大家就会发现整个report相关的方法都会通过ReportStrand调度,也就是说它既是在子线程中调用,又确保了所有与report相关的方法都在一个线程顺序实现,也就无需加锁处理,无需处理数据竞争问题。
Init_方法
在此方法中,会传入数据库路径,构建db数据库对象。
Start方法
在Start方法中,通过asio中的deadline_timer创建了一个定时器,并约定在5s后调用ReportCache_方法。
ps:asio中的这个定时器我个人感觉挺难用,不过这个项目中,为了保持简洁,不引入其他复杂的代码,我最终还是选择使用它,大家自己的项目中,可以考虑自己实现一个定时器和strand。
再看ReportCache_方法
每次调用此方法时,会通过db对象从数据库中按优先级取10条数据,再通过GenReportData_构造网络上报的body,再调用ReportData_上报数据,上报成功后通过db对象从数据库中删除对应数据,并清空data_caches_,防止重复上报,然后调用NexeCycle_启动下一次定时任务。
如何构造网络上报的body
因为数据库中拿出来的10条数据都是被加密过的,所以取出来后我们需要先进行解密操作,然后通过json构造成一个json array,最后再序列化成string,也就是网络上报的body。
如何启动下一次循环任务
还是使用asio的定时器,约定5s后再次调用ReportCache_方法即可。
用户如何向上报模块插入数据
首先需要切线程,统一放到ReportStrand模块调度任务,因为我们也不知道外部究竟是在哪个线程调用的此方法,如果不是相同的Strand,就会产生数据竞争的问题,所以这里需要通过ReportStrand post对应的任务。
如何将数据存入数据库中
BuriedData中有用户传进来的优先级、title、data等数据,再加上common_service中的公共数据,再加上当前时间等数据,构造成一个json object,然后序列化后再加密,即可通过db对象存入数据库中。
整个上报模块需要特别注意几个关键点:
- 通过定时器启动任务,确保每隔一段时间都能上报数据
- 通过strand调度任务,确保report模块内的操作都通过一个strand调度,避免数据竞争问题
- 存数据前要加密,取数据后要解密,更安全一些
到这里,整个上报模块已经介绍完毕,下期我会具体介绍下如何获取的系统信息,下期见。
