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