sessionLog.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /**
  2. * @class SessionLog 基础会话日志模型
  3. */
  4. const BaseMod = require('./base')
  5. const Page = require('./page')
  6. const Platform = require('./platform')
  7. const Channel = require('./channel')
  8. const UserSessionLog = require('./userSessionLog')
  9. const Device = require('./device')
  10. const {
  11. DateTime
  12. } = require('../lib')
  13. module.exports = class SessionLog extends BaseMod {
  14. constructor() {
  15. super()
  16. this.tableName = 'session-logs'
  17. }
  18. /**
  19. * 会话日志批量填充
  20. * @param {Object} reportParams 上报参数
  21. */
  22. async batchFill(reportParams) {
  23. let params, pageInfo, nowTime, firstVistTime, lastVistTime;
  24. const fillParams = []
  25. const page = new Page()
  26. const platform = new Platform()
  27. const dateTime = new DateTime()
  28. const channel = new Channel()
  29. const device = new Device()
  30. let res
  31. for (const pk in reportParams) {
  32. params = reportParams[pk]
  33. res = await this.fill(params)
  34. if (res.code) {
  35. console.error(res.msg)
  36. } else {
  37. //添加设备信息
  38. await device.setDevice(params)
  39. }
  40. }
  41. return res
  42. }
  43. /**
  44. * 会话日志填充
  45. * @param {Object} params 上报参数
  46. */
  47. async fill(params) {
  48. // 应用信息
  49. if (!params.ak) {
  50. return {
  51. code: 200,
  52. msg: 'Parameter "ak" not found'
  53. }
  54. }
  55. // 平台信息
  56. if (!params.ut) {
  57. return {
  58. code: 200,
  59. msg: 'Parameter "ut" not found'
  60. }
  61. }
  62. // 设备信息
  63. if (!params.did) {
  64. return {
  65. code: 200,
  66. msg: 'Parameter "did" not found'
  67. }
  68. }
  69. // 页面信息
  70. const page = new Page()
  71. const pageInfo = await page.getPageAndCreate(params.ak, params.url, params.ttpj)
  72. if (!pageInfo || pageInfo.length === 0) {
  73. return {
  74. code: 300,
  75. msg: 'Not found this entry page'
  76. }
  77. }
  78. if (this.debug) {
  79. console.log('pageInfo', JSON.stringify(pageInfo))
  80. }
  81. const platform = new Platform()
  82. const dateTime = new DateTime()
  83. const channel = new Channel()
  84. const nowTime = dateTime.getTime()
  85. const firstVistTime = params.fvts ? dateTime.strToTime(params.fvts) : nowTime
  86. const lastVistTime = (params.lvts && params.lvts !== '0') ? dateTime.strToTime(params.lvts) : 0
  87. const fillParams = {
  88. appid: params.ak,
  89. version: params.v ? params.v : '',
  90. platform: platform.getPlatformCode(params.ut, params.p),
  91. channel: channel.getChannelCode(params),
  92. type: params.cst ? parseInt(params.cst) : 0,
  93. // 访问设备
  94. device_id: params.did,
  95. //是否为首次访问,判断标准:最后一次访问时间为0
  96. is_first_visit: (params.lt === '1' && !lastVistTime) ? 1 : 0,
  97. first_visit_time: firstVistTime,
  98. last_visit_time: nowTime,
  99. visit_count: params.tvc ? parseInt(params.tvc) : 1,
  100. // 用户相关
  101. last_visit_user_id: params.uid ? params.uid : '',
  102. // 页面相关
  103. entry_page_id: pageInfo._id,
  104. exit_page_id: pageInfo._id,
  105. page_count: 0,
  106. event_count: 0,
  107. duration: 1,
  108. // 版本
  109. sdk_version: params.mpsdk ? params.mpsdk : '',
  110. platform_version: params.mpv ? params.mpv : '',
  111. // 设备相关
  112. device_os_name: params.on ? params.on : platform.getOsName(params.p),
  113. device_os_version: params.sv ? params.sv : '',
  114. device_vendor: params.brand ? params.brand : '',
  115. device_model: params.md ? params.md : '',
  116. device_language: params.lang ? params.lang : '',
  117. device_pixel_ratio: params.pr ? params.pr : '',
  118. device_window_width: params.ww ? params.ww : '',
  119. device_window_height: params.wh ? params.wh : '',
  120. device_screen_width: params.sw ? params.sw : '',
  121. device_screen_height: params.sh ? params.sh : '',
  122. // 地区相关
  123. location_ip: params.ip ? params.ip : '',
  124. location_latitude: params.lat ? parseFloat(params.lat) : -1,
  125. location_longitude: params.lng ? parseFloat(params.lng) : -1,
  126. location_country: params.cn ? params.cn : '',
  127. location_province: params.pn ? params.pn : '',
  128. location_city: params.ct ? params.ct : '',
  129. is_finish: 0,
  130. create_time: nowTime
  131. }
  132. const res = await this.insert(this.tableName, fillParams)
  133. if (res && res.id) {
  134. //填充用户的会话日志
  135. if (params.uid) {
  136. await new UserSessionLog().fill({
  137. ...params,
  138. page_id: pageInfo._id,
  139. sid: res.id
  140. })
  141. }
  142. return {
  143. code: 0,
  144. msg: 'success',
  145. data: {
  146. pageId: pageInfo._id,
  147. sessionLogId: res.id,
  148. entryPageId: fillParams.entry_page_id,
  149. eventCount: fillParams.event_count,
  150. startTime: fillParams.first_visit_time,
  151. createTime: fillParams.create_time,
  152. pageCount: fillParams.page_count,
  153. uid: fillParams.last_visit_user_id
  154. }
  155. }
  156. } else {
  157. return {
  158. code: 500,
  159. msg: 'Session log filled error'
  160. }
  161. }
  162. }
  163. /**
  164. * 获取会话
  165. * @param {Object} params 上报参数
  166. */
  167. async getSession(params) {
  168. // 页面信息
  169. const page = new Page()
  170. const pageInfo = await page.getPageAndCreate(params.ak, params.url, params.ttpj)
  171. if (!pageInfo || pageInfo.length === 0) {
  172. return {
  173. code: 300,
  174. msg: 'Not found this entry page'
  175. }
  176. }
  177. const platformObj = new Platform()
  178. const platform = platformObj.getPlatformCode(params.ut, params.p)
  179. // 查询日志
  180. const sessionLogInfo = await this.getCollection(this.tableName).where({
  181. appid: params.ak,
  182. platform: platform,
  183. device_id: params.did,
  184. is_finish: 0
  185. }).orderBy('create_time', 'desc').limit(1).get()
  186. if (sessionLogInfo.data.length > 0) {
  187. const userSessionLog = new UserSessionLog()
  188. const sessionLogInfoData = sessionLogInfo.data[0]
  189. // 最后一次访问时间距现在超过半小时算上次会话已结束并生成一次新的会话
  190. let sessionExpireTime = this.getConfig('sessionExpireTime')
  191. sessionExpireTime = sessionExpireTime ? sessionExpireTime : 1800
  192. const sessionTime = new DateTime().getTime() - sessionLogInfoData.last_visit_time
  193. if (sessionTime >= sessionExpireTime * 1000) {
  194. if (this.debug) {
  195. console.log('session log time expired', sessionTime)
  196. }
  197. await this.update(this.tableName, {
  198. is_finish: 1
  199. }, {
  200. appid: params.ak,
  201. platform: platform,
  202. device_id: params.did,
  203. is_finish: 0
  204. })
  205. //关闭用户会话
  206. await userSessionLog.closeUserSession()
  207. return await this.fill(params)
  208. } else {
  209. //如果当前会话切换了用户则生成新的用户会话
  210. if (params.uid != sessionLogInfoData.last_visit_user_id) {
  211. await userSessionLog.checkUserSession({
  212. ...params,
  213. page_id: pageInfo._id,
  214. sid: sessionLogInfoData._id,
  215. last_visit_user_id: sessionLogInfoData.last_visit_user_id
  216. })
  217. await this.update(this.tableName, {
  218. last_visit_user_id: params.uid ? params.uid : ''
  219. }, {
  220. _id: sessionLogInfoData._id
  221. })
  222. }
  223. return {
  224. code: 0,
  225. msg: 'success',
  226. data: {
  227. pageId: pageInfo._id,
  228. sessionLogId: sessionLogInfoData._id,
  229. entryPageId: sessionLogInfoData.entry_page_id,
  230. eventCount: sessionLogInfoData.event_count,
  231. startTime: sessionLogInfoData.first_visit_time,
  232. createTime: sessionLogInfoData.create_time,
  233. pageCount: sessionLogInfoData.page_count,
  234. uid: sessionLogInfoData.last_visit_user_id
  235. }
  236. }
  237. }
  238. } else {
  239. return await this.fill(params)
  240. }
  241. }
  242. /**
  243. * 更新会话信息
  244. * @param {String} sid 会话编号
  245. * @param {Object} data 更新数据
  246. */
  247. async updateSession(sid, data) {
  248. const nowTime = new DateTime().getTime()
  249. const accessTime = nowTime - data.createTime
  250. const accessSenconds = accessTime > 1000 ? parseInt(accessTime / 1000) : 1
  251. const updateData = {
  252. last_visit_time: nowTime,
  253. duration: accessSenconds,
  254. }
  255. //访问页面数量
  256. if (data.addPageCount) {
  257. updateData.page_count = data.pageCount
  258. }
  259. //最终访问的页面编号
  260. if (data.pageId) {
  261. updateData.exit_page_id = data.pageId
  262. }
  263. //产生事件次数
  264. if (data.eventCount) {
  265. updateData.event_count = data.eventCount
  266. }
  267. if (this.debug) {
  268. console.log('update session log by sid-' + sid, updateData)
  269. }
  270. //更新会话
  271. await this.update(this.tableName, updateData, {
  272. _id: sid
  273. })
  274. //更新用户会话
  275. if (data.uid) {
  276. data.nowTime = nowTime
  277. await new UserSessionLog().updateUserSession(sid, data)
  278. }
  279. return true
  280. }
  281. /**
  282. * 清理日志数据
  283. * @param {Number} days 保留天数, 留存统计需要计算30天后留存率,因此至少应保留31天的日志数据
  284. */
  285. async clean(days) {
  286. days = Math.max(parseInt(days), 1)
  287. console.log('clean session logs - day:', days)
  288. const dateTime = new DateTime()
  289. const res = await this.delete(this.tableName, {
  290. create_time: {
  291. $lt: dateTime.getTimeBySetDays(0 - days)
  292. }
  293. })
  294. if (!res.code) {
  295. console.log('clean session log:', res)
  296. }
  297. return res
  298. }
  299. }