@aochuang/client-sdk 1.0.367 → 1.0.369
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/services/client-chat/client-chat-wechat/client-chat-account.js +57 -14
- package/services/client-chat/client-chat-wechat/client-chat-session.js +23 -4
- package/services/client-chat/client-chat-wechat/client-chat-socket.js +5 -1
- package/services/client-chat/client-chat-wechat/client-chat.js +108 -56
- package/services/client-chat/client-chat-wechat/docs//350/264/246/345/217/267/346/234/252/350/257/273/346/225/260/351/207/217/344/270/216/344/274/232/350/257/235/346/234/252/350/257/273/346/225/260/351/207/217/344/270/215/344/270/200/350/207/264/351/227/256/351/242/230/344/277/256/345/244/215.md +296 -0
- package/services/socket/socket.js +9 -5
- package/utils/log.js +579 -220
package/utils/log.js
CHANGED
|
@@ -1,243 +1,602 @@
|
|
|
1
|
-
import { unique } from './string'
|
|
2
|
-
import { parse } from './json'
|
|
3
1
|
import { formatDate } from './date'
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
3
|
+
let uniqueId = Date.now()
|
|
4
|
+
|
|
5
|
+
function unique () {
|
|
6
|
+
uniqueId++
|
|
7
|
+
return uniqueId
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function parse (value) {
|
|
11
|
+
try {
|
|
12
|
+
return typeof value === 'string' ? JSON.parse(value) : value
|
|
13
|
+
} catch (e) {
|
|
14
|
+
return value
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const INDEXED_DB_VERSION = 2
|
|
19
|
+
const INDEXED_DB_STORE_NAME = 'logs'
|
|
20
|
+
const INDEXED_DB_META_STORE_NAME = 'meta'
|
|
21
|
+
const INDEXED_DB_ORDER_INDEX_NAME = 'order'
|
|
22
|
+
const INDEXED_DB_MAX_SIZE = 50 * 1024 * 1024
|
|
23
|
+
const INDEXED_DB_STATS_KEY = 'stats'
|
|
24
|
+
|
|
25
|
+
function isUniRuntime () {
|
|
26
|
+
try {
|
|
27
|
+
return !!uni
|
|
28
|
+
} catch (e) {
|
|
29
|
+
return false
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function isIndexedDbSupported () {
|
|
34
|
+
return typeof window !== 'undefined' && !isUniRuntime() && !!window.indexedDB
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getLogSize (item) {
|
|
38
|
+
return item && item.size ? item.size : JSON.stringify(item || {}).length
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getLogByteSize (item) {
|
|
42
|
+
const value = JSON.stringify(item || {})
|
|
43
|
+
if (typeof Blob !== 'undefined') {
|
|
44
|
+
return new Blob([value]).size
|
|
45
|
+
}
|
|
46
|
+
return unescape(encodeURIComponent(value)).length
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function normalizeLogStore (store) {
|
|
50
|
+
let nextStore = store
|
|
51
|
+
if (!nextStore) {
|
|
52
|
+
nextStore = {
|
|
53
|
+
size: 0,
|
|
54
|
+
data: []
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (Array.isArray(nextStore)) {
|
|
58
|
+
let totalSize = 0
|
|
59
|
+
nextStore = {
|
|
60
|
+
data: nextStore.map(item => {
|
|
61
|
+
if (item && !item.size) {
|
|
62
|
+
item.size = JSON.stringify(item).length
|
|
63
|
+
}
|
|
64
|
+
totalSize += getLogSize(item)
|
|
65
|
+
return item
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
nextStore.size = totalSize
|
|
69
|
+
}
|
|
70
|
+
if (!Array.isArray(nextStore.data)) {
|
|
71
|
+
nextStore.data = []
|
|
72
|
+
}
|
|
73
|
+
if (!nextStore.size) {
|
|
74
|
+
nextStore.size = nextStore.data.reduce((totalSize, item) => {
|
|
75
|
+
return totalSize + getLogSize(item)
|
|
76
|
+
}, 0)
|
|
77
|
+
}
|
|
78
|
+
return nextStore
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function parseLogStoreValue (value) {
|
|
82
|
+
if (!value) {
|
|
83
|
+
return null
|
|
84
|
+
}
|
|
85
|
+
if (typeof value === 'string') {
|
|
86
|
+
value = parse(value)
|
|
87
|
+
}
|
|
88
|
+
return normalizeLogStore(value)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function readLegacyStorage (storageKey) {
|
|
92
|
+
if (isUniRuntime()) {
|
|
93
|
+
return uni.getStorageSync(storageKey)
|
|
94
|
+
}
|
|
95
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
96
|
+
return window.localStorage.getItem(storageKey)
|
|
97
|
+
}
|
|
98
|
+
return null
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function writeLegacyStorage (storageKey, value) {
|
|
102
|
+
if (isUniRuntime()) {
|
|
103
|
+
uni.setStorageSync(storageKey, value)
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
107
|
+
window.localStorage.setItem(storageKey, typeof value === 'string' ? value : JSON.stringify(value))
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function removeLegacyStorage (storageKey) {
|
|
112
|
+
if (isUniRuntime()) {
|
|
113
|
+
uni.removeStorageSync(storageKey)
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
117
|
+
window.localStorage.removeItem(storageKey)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function hashString (value) {
|
|
122
|
+
let hash = 2166136261
|
|
123
|
+
for (let index = 0; index < value.length; index++) {
|
|
124
|
+
hash ^= value.charCodeAt(index)
|
|
125
|
+
hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24)
|
|
126
|
+
}
|
|
127
|
+
return (hash >>> 0).toString(16)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function getLogRecordId (log) {
|
|
131
|
+
if (log && log.id !== undefined && log.id !== null) {
|
|
132
|
+
return `id:${log.id}`
|
|
133
|
+
}
|
|
134
|
+
const value = JSON.stringify(log || {})
|
|
135
|
+
return `legacy:${hashString(value)}:${value.length}`
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function createIndexedDbStores (db) {
|
|
139
|
+
const logStore = db.createObjectStore(INDEXED_DB_STORE_NAME, { keyPath: 'recordId' })
|
|
140
|
+
logStore.createIndex(INDEXED_DB_ORDER_INDEX_NAME, 'order', { unique: false })
|
|
141
|
+
if (!db.objectStoreNames.contains(INDEXED_DB_META_STORE_NAME)) {
|
|
142
|
+
db.createObjectStore(INDEXED_DB_META_STORE_NAME, { keyPath: 'key' })
|
|
14
143
|
}
|
|
144
|
+
return logStore
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function createIndexedDbRecord (log, order) {
|
|
148
|
+
return {
|
|
149
|
+
recordId: getLogRecordId(log),
|
|
150
|
+
order,
|
|
151
|
+
byteSize: getLogByteSize(log),
|
|
152
|
+
log
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function uniqueLogs (logs) {
|
|
157
|
+
const recordIds = Object.create(null)
|
|
158
|
+
return logs.filter(log => {
|
|
159
|
+
const recordId = getLogRecordId(log)
|
|
160
|
+
if (recordIds[recordId]) {
|
|
161
|
+
return false
|
|
162
|
+
}
|
|
163
|
+
recordIds[recordId] = true
|
|
164
|
+
return true
|
|
165
|
+
})
|
|
15
166
|
}
|
|
16
167
|
|
|
17
|
-
function
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
this.list.push(logInstance)
|
|
35
|
-
},
|
|
36
|
-
remove: (logInstance) => {
|
|
37
|
-
let index = -1
|
|
38
|
-
this.list.some((v, i) => {
|
|
39
|
-
if (v === logInstance) {
|
|
40
|
-
index = i
|
|
41
|
-
return true
|
|
42
|
-
}
|
|
43
|
-
})
|
|
44
|
-
if (index < 0) {
|
|
45
|
-
return
|
|
46
|
-
}
|
|
47
|
-
this.list.splice(index, 1)
|
|
48
|
-
}
|
|
168
|
+
function trimRecordsToIndexedDbLimit (records) {
|
|
169
|
+
let totalBytes = 0
|
|
170
|
+
const retainedRecords = []
|
|
171
|
+
records.some(record => {
|
|
172
|
+
if (record.byteSize + totalBytes > INDEXED_DB_MAX_SIZE) {
|
|
173
|
+
return true
|
|
174
|
+
}
|
|
175
|
+
retainedRecords.push(record)
|
|
176
|
+
totalBytes += record.byteSize
|
|
177
|
+
return false
|
|
178
|
+
})
|
|
179
|
+
return {
|
|
180
|
+
records: retainedRecords,
|
|
181
|
+
totalBytes,
|
|
182
|
+
removedCount: records.length - retainedRecords.length
|
|
183
|
+
}
|
|
49
184
|
}
|
|
50
185
|
|
|
51
186
|
export default class Log {
|
|
52
187
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
console: false, // 是否控制台打印
|
|
65
|
-
maxSize: 1024 * 1024 * 3 // 最多存3M的日志数据
|
|
66
|
-
}, options)
|
|
67
|
-
if (!options.name) {
|
|
68
|
-
throw new Error('必须指定日志的name名称')
|
|
69
|
-
}
|
|
70
|
-
if (LogManage.list.some(v => v.name === options.name)) {
|
|
71
|
-
throw new Error('已存在同名的日志实例')
|
|
72
|
-
}
|
|
73
|
-
this.options = options
|
|
74
|
-
this.maxSize = options.maxSize
|
|
75
|
-
this.name = options.name
|
|
76
|
-
this.validTime = options.validTime
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
get storageKey () {
|
|
80
|
-
return this.prefix + '_' + this.name
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
onBeforeAdd (callback) {
|
|
84
|
-
this.beforeAddCallback = callback
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* 新增日志到内存
|
|
89
|
-
*/
|
|
90
|
-
addLog (data) {
|
|
91
|
-
data = Object.assign({
|
|
92
|
-
group: this.defautGroup,
|
|
93
|
-
refererId: undefined, // 可以关联一个日志
|
|
94
|
-
content: null
|
|
95
|
-
}, data, {
|
|
96
|
-
createTime: formatDate(new Date())
|
|
97
|
-
})
|
|
98
|
-
data.id = unique(data.group)
|
|
99
|
-
if (this.beforeAddCallback && this.beforeAddCallback({
|
|
100
|
-
data
|
|
101
|
-
}) === false) {
|
|
102
|
-
return
|
|
103
|
-
}
|
|
104
|
-
const size = JSON.stringify(data).length
|
|
105
|
-
data.size = size
|
|
106
|
-
this.tempStore.push(data)
|
|
107
|
-
if (this.tempStore.length > 5) {
|
|
108
|
-
this.publishLogData().then(null, err => {
|
|
109
|
-
console.log(err)
|
|
188
|
+
static checkAndSync (storageKeys) {
|
|
189
|
+
const keys = [].concat(storageKeys || []).filter((storageKey, index, list) => {
|
|
190
|
+
return typeof storageKey === 'string' && storageKey && list.indexOf(storageKey) === index
|
|
191
|
+
})
|
|
192
|
+
return Promise.all(keys.map(storageKey => {
|
|
193
|
+
const log = new Log({ name: storageKey })
|
|
194
|
+
log._customStorageKey = storageKey
|
|
195
|
+
return log.checkAndSync().then(result => {
|
|
196
|
+
return log._closeIndexedDb().then(() => {
|
|
197
|
+
return Object.assign({ storageKey }, result)
|
|
198
|
+
})
|
|
110
199
|
})
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
200
|
+
}))
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
constructor (options) {
|
|
204
|
+
this.prefix = 'log'
|
|
205
|
+
this.name = null
|
|
206
|
+
this.tempStore = []
|
|
207
|
+
this.beforeAddCallback = null
|
|
208
|
+
this._writePromise = Promise.resolve()
|
|
209
|
+
this._indexedDbPromise = null
|
|
210
|
+
this._syncPromise = null
|
|
211
|
+
this._customStorageKey = null
|
|
212
|
+
options = Object.assign({
|
|
213
|
+
name: null,
|
|
214
|
+
console: false, // 是否控制台打印
|
|
215
|
+
maxSize: 1024 * 1024 * 3 // 非网页版本默认最多存3M日志数据
|
|
216
|
+
}, options)
|
|
217
|
+
if (!options.name) {
|
|
218
|
+
throw new Error('必须指定日志的name名称')
|
|
114
219
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
220
|
+
this.options = options
|
|
221
|
+
this.maxSize = options.maxSize
|
|
222
|
+
this.name = options.name
|
|
223
|
+
this.validTime = options.validTime
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
get storageKey () {
|
|
227
|
+
return this._customStorageKey || this.prefix + '_' + this.name
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
get useIndexedDb () {
|
|
231
|
+
return isIndexedDbSupported()
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
get indexedDbName () {
|
|
235
|
+
return this.storageKey
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
onBeforeAdd (callback) {
|
|
239
|
+
this.beforeAddCallback = callback
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
_enqueueWrite (callback) {
|
|
243
|
+
const task = this._writePromise.then(callback, callback)
|
|
244
|
+
this._writePromise = task.catch(() => {})
|
|
245
|
+
return task
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
_closeIndexedDb () {
|
|
249
|
+
const indexedDbPromise = this._indexedDbPromise
|
|
250
|
+
this._indexedDbPromise = null
|
|
251
|
+
if (!indexedDbPromise) {
|
|
252
|
+
return Promise.resolve()
|
|
253
|
+
}
|
|
254
|
+
return indexedDbPromise.then(db => {
|
|
255
|
+
db.close()
|
|
256
|
+
}, () => {})
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
_upgradeIndexedDb (request) {
|
|
260
|
+
const db = request.result
|
|
261
|
+
const transaction = request.transaction
|
|
262
|
+
if (!db.objectStoreNames.contains(INDEXED_DB_STORE_NAME)) {
|
|
263
|
+
createIndexedDbStores(db)
|
|
264
|
+
transaction.objectStore(INDEXED_DB_META_STORE_NAME).put({
|
|
265
|
+
key: INDEXED_DB_STATS_KEY,
|
|
266
|
+
totalBytes: 0,
|
|
267
|
+
nextOrder: 0
|
|
268
|
+
})
|
|
269
|
+
return
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const legacyStore = transaction.objectStore(INDEXED_DB_STORE_NAME)
|
|
273
|
+
const legacyRequest = legacyStore.get(this.storageKey)
|
|
274
|
+
legacyRequest.onerror = () => {
|
|
275
|
+
transaction.abort()
|
|
276
|
+
}
|
|
277
|
+
legacyRequest.onsuccess = () => {
|
|
278
|
+
let legacyLogStore = null
|
|
279
|
+
try {
|
|
280
|
+
const result = legacyRequest.result
|
|
281
|
+
legacyLogStore = result && result.value ? parseLogStoreValue(result.value) : null
|
|
282
|
+
} catch (e) {
|
|
283
|
+
legacyLogStore = null
|
|
284
|
+
}
|
|
285
|
+
db.deleteObjectStore(INDEXED_DB_STORE_NAME)
|
|
286
|
+
if (db.objectStoreNames.contains(INDEXED_DB_META_STORE_NAME)) {
|
|
287
|
+
db.deleteObjectStore(INDEXED_DB_META_STORE_NAME)
|
|
288
|
+
}
|
|
289
|
+
const logStore = createIndexedDbStores(db)
|
|
290
|
+
const logs = uniqueLogs(legacyLogStore ? legacyLogStore.data : [])
|
|
291
|
+
const records = logs.map((log, index) => createIndexedDbRecord(log, logs.length - index))
|
|
292
|
+
const result = trimRecordsToIndexedDbLimit(records)
|
|
293
|
+
result.records.forEach(record => logStore.put(record))
|
|
294
|
+
transaction.objectStore(INDEXED_DB_META_STORE_NAME).put({
|
|
295
|
+
key: INDEXED_DB_STATS_KEY,
|
|
296
|
+
totalBytes: result.totalBytes,
|
|
297
|
+
nextOrder: logs.length
|
|
298
|
+
})
|
|
299
|
+
}
|
|
300
|
+
}
|
|
132
301
|
|
|
133
|
-
|
|
302
|
+
openIndexedDb () {
|
|
303
|
+
if (!this.useIndexedDb) {
|
|
304
|
+
return Promise.reject(new Error('indexedDB不可用'))
|
|
305
|
+
}
|
|
306
|
+
if (this._indexedDbPromise) {
|
|
307
|
+
return this._indexedDbPromise
|
|
308
|
+
}
|
|
309
|
+
this._indexedDbPromise = new Promise((resolve, reject) => {
|
|
310
|
+
const request = window.indexedDB.open(this.indexedDbName, INDEXED_DB_VERSION)
|
|
311
|
+
request.onerror = () => {
|
|
312
|
+
this._indexedDbPromise = null
|
|
313
|
+
reject(request.error || new Error('打开日志数据库失败'))
|
|
314
|
+
}
|
|
315
|
+
request.onupgradeneeded = () => {
|
|
316
|
+
this._upgradeIndexedDb(request)
|
|
317
|
+
}
|
|
318
|
+
request.onsuccess = () => {
|
|
319
|
+
const db = request.result
|
|
320
|
+
db.onversionchange = () => {
|
|
321
|
+
db.close()
|
|
322
|
+
this._indexedDbPromise = null
|
|
323
|
+
}
|
|
324
|
+
resolve(db)
|
|
325
|
+
}
|
|
326
|
+
})
|
|
327
|
+
return this._indexedDbPromise
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
_readIndexedDbLogData () {
|
|
331
|
+
return this.openIndexedDb().then(db => {
|
|
134
332
|
return new Promise((resolve, reject) => {
|
|
135
|
-
|
|
136
|
-
|
|
333
|
+
const transaction = db.transaction([INDEXED_DB_STORE_NAME], 'readonly')
|
|
334
|
+
const store = transaction.objectStore(INDEXED_DB_STORE_NAME)
|
|
335
|
+
const request = store.index(INDEXED_DB_ORDER_INDEX_NAME).openCursor(null, 'prev')
|
|
336
|
+
const data = []
|
|
337
|
+
let size = 0
|
|
338
|
+
request.onerror = () => {
|
|
339
|
+
reject(request.error || new Error('读取日志失败'))
|
|
137
340
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
reject('cancel')
|
|
144
|
-
},
|
|
145
|
-
execFn: () => {
|
|
146
|
-
rafId = requestAnimationFrame(() => {
|
|
147
|
-
let localTempStore
|
|
148
|
-
if (typeof uni !== 'undefined') {
|
|
149
|
-
localTempStore = uni.getStorageSync(this.storageKey)
|
|
150
|
-
} else {
|
|
151
|
-
localTempStore = window.localStorage.getItem(this.storageKey)
|
|
152
|
-
}
|
|
153
|
-
if (localTempStore) {
|
|
154
|
-
localTempStore = parse(localTempStore)
|
|
155
|
-
if (Array.isArray(localTempStore)) {
|
|
156
|
-
let totalSize = 0
|
|
157
|
-
localTempStore = {
|
|
158
|
-
data: localTempStore.map(v => {
|
|
159
|
-
if (!v.size) {
|
|
160
|
-
v.size = JSON.stringify(v).length
|
|
161
|
-
}
|
|
162
|
-
totalSize += v.size
|
|
163
|
-
return v
|
|
164
|
-
})
|
|
165
|
-
}
|
|
166
|
-
localTempStore.size = totalSize
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
if (!localTempStore) {
|
|
170
|
-
localTempStore = {
|
|
171
|
-
size: 0,
|
|
172
|
-
data: []
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
// 自清理一下
|
|
176
|
-
if (this._lastLoadLogDataRaf) {
|
|
177
|
-
cancelAnimationFrame(this._lastLoadLogDataRaf)
|
|
178
|
-
this._lastLoadLogDataRaf = null
|
|
179
|
-
}
|
|
180
|
-
resolve(localTempStore)
|
|
181
|
-
})
|
|
341
|
+
request.onsuccess = event => {
|
|
342
|
+
const cursor = event.target.result
|
|
343
|
+
if (!cursor) {
|
|
344
|
+
resolve({ size, data })
|
|
345
|
+
return
|
|
182
346
|
}
|
|
347
|
+
data.push(cursor.value.log)
|
|
348
|
+
size += getLogSize(cursor.value.log)
|
|
349
|
+
cursor.continue()
|
|
183
350
|
}
|
|
184
|
-
this._lastLoadLogDataRaf.execFn()
|
|
185
351
|
})
|
|
186
|
-
|
|
352
|
+
})
|
|
353
|
+
}
|
|
187
354
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
355
|
+
_writeIndexedDbLogs (logs) {
|
|
356
|
+
if (!logs.length) {
|
|
357
|
+
return Promise.resolve({ migratedCount: 0, duplicateCount: 0, removedCount: 0 })
|
|
358
|
+
}
|
|
359
|
+
const uniqueLogList = uniqueLogs(logs)
|
|
360
|
+
const repeatedInputCount = logs.length - uniqueLogList.length
|
|
361
|
+
return this.openIndexedDb().then(db => {
|
|
362
|
+
return new Promise((resolve, reject) => {
|
|
363
|
+
const transaction = db.transaction(
|
|
364
|
+
[INDEXED_DB_STORE_NAME, INDEXED_DB_META_STORE_NAME],
|
|
365
|
+
'readwrite'
|
|
366
|
+
)
|
|
367
|
+
const store = transaction.objectStore(INDEXED_DB_STORE_NAME)
|
|
368
|
+
const metaStore = transaction.objectStore(INDEXED_DB_META_STORE_NAME)
|
|
369
|
+
const metaRequest = metaStore.get(INDEXED_DB_STATS_KEY)
|
|
370
|
+
let result = null
|
|
371
|
+
transaction.oncomplete = () => {
|
|
372
|
+
resolve(result || { migratedCount: 0, duplicateCount: 0, removedCount: 0 })
|
|
373
|
+
}
|
|
374
|
+
transaction.onerror = () => {
|
|
375
|
+
reject(transaction.error || new Error('写入日志失败'))
|
|
376
|
+
}
|
|
377
|
+
transaction.onabort = () => {
|
|
378
|
+
reject(transaction.error || new Error('写入日志失败'))
|
|
379
|
+
}
|
|
380
|
+
metaRequest.onsuccess = () => {
|
|
381
|
+
const stats = metaRequest.result || {
|
|
382
|
+
key: INDEXED_DB_STATS_KEY,
|
|
383
|
+
totalBytes: 0,
|
|
384
|
+
nextOrder: 0
|
|
192
385
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
if (
|
|
202
|
-
|
|
386
|
+
const records = uniqueLogList.map((log, index) => {
|
|
387
|
+
return createIndexedDbRecord(log, stats.nextOrder + uniqueLogList.length - index)
|
|
388
|
+
})
|
|
389
|
+
let pendingCount = records.length
|
|
390
|
+
let duplicateCount = repeatedInputCount
|
|
391
|
+
records.forEach(record => {
|
|
392
|
+
const getRequest = store.get(record.recordId)
|
|
393
|
+
getRequest.onsuccess = () => {
|
|
394
|
+
if (getRequest.result) {
|
|
395
|
+
stats.totalBytes -= getRequest.result.byteSize || 0
|
|
396
|
+
duplicateCount++
|
|
397
|
+
}
|
|
398
|
+
stats.totalBytes += record.byteSize
|
|
399
|
+
store.put(record)
|
|
400
|
+
pendingCount--
|
|
401
|
+
if (!pendingCount) {
|
|
402
|
+
stats.nextOrder += uniqueLogList.length
|
|
403
|
+
trimOldestLogs(stats, duplicateCount)
|
|
203
404
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (this._lastPublishLogDataRaf) {
|
|
226
|
-
cancelAnimationFrame(this._lastPublishLogDataRaf)
|
|
227
|
-
this._lastPublishLogDataRaf = null
|
|
228
|
-
}
|
|
229
|
-
resolve()
|
|
230
|
-
}, reject)
|
|
231
|
-
})
|
|
405
|
+
}
|
|
406
|
+
})
|
|
407
|
+
|
|
408
|
+
function trimOldestLogs (nextStats, nextDuplicateCount) {
|
|
409
|
+
let removedCount = 0
|
|
410
|
+
const cursorRequest = store.index(INDEXED_DB_ORDER_INDEX_NAME).openCursor(null, 'next')
|
|
411
|
+
cursorRequest.onsuccess = event => {
|
|
412
|
+
const cursor = event.target.result
|
|
413
|
+
if (nextStats.totalBytes <= INDEXED_DB_MAX_SIZE || !cursor) {
|
|
414
|
+
metaStore.put(nextStats)
|
|
415
|
+
result = {
|
|
416
|
+
migratedCount: logs.length - nextDuplicateCount,
|
|
417
|
+
duplicateCount: nextDuplicateCount,
|
|
418
|
+
removedCount
|
|
419
|
+
}
|
|
420
|
+
return
|
|
421
|
+
}
|
|
422
|
+
nextStats.totalBytes -= cursor.value.byteSize || 0
|
|
423
|
+
cursor.delete()
|
|
424
|
+
removedCount++
|
|
425
|
+
cursor.continue()
|
|
232
426
|
}
|
|
233
427
|
}
|
|
234
|
-
|
|
428
|
+
}
|
|
429
|
+
})
|
|
430
|
+
})
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
_writeLegacyLogs (logs) {
|
|
434
|
+
const localLogStore = parseLogStoreValue(readLegacyStorage(this.storageKey)) || {
|
|
435
|
+
size: 0,
|
|
436
|
+
data: []
|
|
437
|
+
}
|
|
438
|
+
const allData = [].concat(logs, localLogStore.data)
|
|
439
|
+
const nextLocalStore = {
|
|
440
|
+
size: 0,
|
|
441
|
+
data: []
|
|
442
|
+
}
|
|
443
|
+
allData.some(item => {
|
|
444
|
+
const itemSize = getLogSize(item)
|
|
445
|
+
if (itemSize + nextLocalStore.size >= this.maxSize) {
|
|
446
|
+
return true
|
|
447
|
+
}
|
|
448
|
+
nextLocalStore.data.push(item)
|
|
449
|
+
nextLocalStore.size += itemSize
|
|
450
|
+
return false
|
|
451
|
+
})
|
|
452
|
+
writeLegacyStorage(this.storageKey, nextLocalStore)
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
checkAndSync () {
|
|
456
|
+
if (!this.useIndexedDb) {
|
|
457
|
+
return Promise.resolve({
|
|
458
|
+
synced: false,
|
|
459
|
+
migratedCount: 0,
|
|
460
|
+
duplicateCount: 0,
|
|
461
|
+
removedCount: 0
|
|
462
|
+
})
|
|
463
|
+
}
|
|
464
|
+
if (this._syncPromise) {
|
|
465
|
+
return this._syncPromise
|
|
466
|
+
}
|
|
467
|
+
const task = this._enqueueWrite(() => {
|
|
468
|
+
const legacyLogStore = parseLogStoreValue(readLegacyStorage(this.storageKey))
|
|
469
|
+
if (!legacyLogStore || !legacyLogStore.data.length) {
|
|
470
|
+
return {
|
|
471
|
+
synced: false,
|
|
472
|
+
migratedCount: 0,
|
|
473
|
+
duplicateCount: 0,
|
|
474
|
+
removedCount: 0
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
return this._writeIndexedDbLogs(legacyLogStore.data).then(result => {
|
|
478
|
+
removeLegacyStorage(this.storageKey)
|
|
479
|
+
return Object.assign({ synced: true }, result)
|
|
480
|
+
})
|
|
481
|
+
})
|
|
482
|
+
this._syncPromise = task.then(result => {
|
|
483
|
+
this._syncPromise = null
|
|
484
|
+
return result
|
|
485
|
+
}, () => {
|
|
486
|
+
this._syncPromise = null
|
|
487
|
+
return {
|
|
488
|
+
synced: false,
|
|
489
|
+
migratedCount: 0,
|
|
490
|
+
duplicateCount: 0,
|
|
491
|
+
removedCount: 0
|
|
492
|
+
}
|
|
493
|
+
})
|
|
494
|
+
return this._syncPromise
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* 新增日志到内存
|
|
499
|
+
*/
|
|
500
|
+
addLog (data) {
|
|
501
|
+
data = Object.assign({
|
|
502
|
+
group: this.defautGroup,
|
|
503
|
+
refererId: undefined, // 可以关联一个日志
|
|
504
|
+
content: null
|
|
505
|
+
}, data, {
|
|
506
|
+
createTime: formatDate(new Date())
|
|
507
|
+
})
|
|
508
|
+
data.id = unique(data.group)
|
|
509
|
+
if (this.beforeAddCallback && this.beforeAddCallback({ data }) === false) {
|
|
510
|
+
return
|
|
511
|
+
}
|
|
512
|
+
data.size = JSON.stringify(data).length
|
|
513
|
+
this.tempStore.push(data)
|
|
514
|
+
this.checkAndSync().catch(() => {})
|
|
515
|
+
if (this.tempStore.length > 5) {
|
|
516
|
+
this.publishLogData().then(null, err => {
|
|
517
|
+
console.log(err)
|
|
518
|
+
})
|
|
519
|
+
}
|
|
520
|
+
if (this.options.console) {
|
|
521
|
+
console.log(`【${this.name || 'operateLog'}】${JSON.stringify(data) || '--'}`)
|
|
522
|
+
}
|
|
523
|
+
return data
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* 清空本地日志
|
|
528
|
+
*/
|
|
529
|
+
clearLogData () {
|
|
530
|
+
this.tempStore = []
|
|
531
|
+
const task = this._enqueueWrite(() => {
|
|
532
|
+
if (!this.useIndexedDb) {
|
|
533
|
+
removeLegacyStorage(this.storageKey)
|
|
534
|
+
return
|
|
535
|
+
}
|
|
536
|
+
return this.openIndexedDb().then(db => {
|
|
537
|
+
return new Promise((resolve, reject) => {
|
|
538
|
+
const transaction = db.transaction(
|
|
539
|
+
[INDEXED_DB_STORE_NAME, INDEXED_DB_META_STORE_NAME],
|
|
540
|
+
'readwrite'
|
|
541
|
+
)
|
|
542
|
+
transaction.objectStore(INDEXED_DB_STORE_NAME).clear()
|
|
543
|
+
transaction.objectStore(INDEXED_DB_META_STORE_NAME).put({
|
|
544
|
+
key: INDEXED_DB_STATS_KEY,
|
|
545
|
+
totalBytes: 0,
|
|
546
|
+
nextOrder: 0
|
|
547
|
+
})
|
|
548
|
+
transaction.oncomplete = resolve
|
|
549
|
+
transaction.onerror = () => reject(transaction.error || new Error('清理日志失败'))
|
|
550
|
+
transaction.onabort = () => reject(transaction.error || new Error('清理日志失败'))
|
|
235
551
|
})
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
552
|
+
}).then(() => {
|
|
553
|
+
removeLegacyStorage(this.storageKey)
|
|
554
|
+
})
|
|
555
|
+
})
|
|
556
|
+
return task.catch(() => {
|
|
557
|
+
removeLegacyStorage(this.storageKey)
|
|
558
|
+
})
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
loadLogData () {
|
|
562
|
+
return this.checkAndSync().then(() => this._writePromise).then(() => {
|
|
563
|
+
if (this.useIndexedDb) {
|
|
564
|
+
return this._readIndexedDbLogData().catch(() => ({ size: 0, data: [] }))
|
|
565
|
+
}
|
|
566
|
+
return parseLogStoreValue(readLegacyStorage(this.storageKey)) || {
|
|
567
|
+
size: 0,
|
|
568
|
+
data: []
|
|
569
|
+
}
|
|
570
|
+
})
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
publishLogData () {
|
|
574
|
+
return this.checkAndSync().then(() => {
|
|
575
|
+
return this._enqueueWrite(() => {
|
|
576
|
+
if (!this.tempStore.length) {
|
|
577
|
+
return
|
|
578
|
+
}
|
|
579
|
+
const flushingTempStore = this.tempStore.slice()
|
|
580
|
+
this.tempStore = []
|
|
581
|
+
let writeTask
|
|
582
|
+
if (this.useIndexedDb) {
|
|
583
|
+
writeTask = this._writeIndexedDbLogs(flushingTempStore).catch(() => {})
|
|
584
|
+
} else {
|
|
585
|
+
writeTask = Promise.resolve().then(() => this._writeLegacyLogs(flushingTempStore))
|
|
586
|
+
}
|
|
587
|
+
return writeTask.catch(error => {
|
|
588
|
+
this.tempStore = flushingTempStore.concat(this.tempStore)
|
|
589
|
+
throw error
|
|
590
|
+
})
|
|
591
|
+
})
|
|
592
|
+
})
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
exportLogData () {
|
|
596
|
+
return this.checkAndSync().then(() => {
|
|
597
|
+
return this.publishLogData()
|
|
598
|
+
}).then(() => {
|
|
599
|
+
return this.loadLogData()
|
|
600
|
+
})
|
|
601
|
+
}
|
|
602
|
+
}
|