-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathpayload-store.ts
153 lines (125 loc) · 4.4 KB
/
payload-store.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**
* Wechaty Open Source Software - https://github.com/wechaty
*
* @copyright 2016 Huan LI (李卓桓) <https://github.com/huan>, and
* Wechaty Contributors <https://github.com/wechaty>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import path from 'path'
import os from 'os'
import fs from 'fs'
import semverPkg from 'semver'
import type * as PUPPET from 'wechaty-puppet'
import { FlashStore } from 'flash-store'
import {
VERSION,
log,
} from '../config.js'
const { major, minor } = semverPkg
interface PayloadStoreOptions {
token: string
}
interface StoreRoomMemberPayload {
[roomMemberContactId: string]: PUPPET.payloads.RoomMember
}
class PayloadStore {
// public message? : LRU<string, MessagePayload>
public contact? : FlashStore<string, PUPPET.payloads.Contact>
public roomMember? : FlashStore<string, StoreRoomMemberPayload>
public room? : FlashStore<string, PUPPET.payloads.Room>
protected storeDir: string
protected accountId?: string
constructor (private options: PayloadStoreOptions) {
log.verbose('PayloadStore', 'constructor(%s)', JSON.stringify(options))
this.storeDir = path.join(
os.homedir(),
'.wechaty',
'wechaty-puppet-service',
this.options.token,
`v${major(VERSION)}.${minor(VERSION)}`,
)
log.silly('PayloadStore', 'constructor() storeDir: "%s"', this.storeDir)
}
/**
* When starting the store, we need to know the accountId
* so that we can save the payloads under a specific account folder.
*/
async start (accountId: string): Promise<void> {
log.verbose('PayloadStore', 'start(%s)', accountId)
if (this.accountId) {
throw new Error('PayloadStore should be stop() before start() again.')
}
this.accountId = accountId
const accountDir = path.join(this.storeDir, accountId)
if (!fs.existsSync(accountDir)) {
fs.mkdirSync(accountDir, { recursive: true })
}
this.contact = new FlashStore(path.join(accountDir, 'contact-payload'))
this.roomMember = new FlashStore(path.join(accountDir, 'room-member-payload'))
this.room = new FlashStore(path.join(accountDir, 'room-payload'))
/**
* LRU
*
* Huan(202108): the Wechaty Puppet has LRU cache already,
* there's no need to do it again.
*
* We can focus on providing a persistent store for the performance.
*/
// const lruOptions: LRU.Options<string, MessagePayload> = {
// dispose (key, val) {
// log.silly('PayloadStore', `constructor() lruOptions.dispose(${key}, ${JSON.stringify(val)})`)
// },
// max : 1000, // 1000 messages
// maxAge : 60 * 60 * 1000, // 1 hour
// }
// this.message = new LRU(lruOptions)
}
async stop (): Promise<void> {
log.verbose('PayloadStore', 'stop()')
const contactStore = this.contact
const roomMemberStore = this.roomMember
const roomStore = this.room
/**
* Huan(202108): we must set all the instances of the store to underfined
* in the current event loop as soon as possible
* to prevent the future store calls.
*/
this.contact = undefined
this.roomMember = undefined
this.room = undefined
// LRU
// this.message = undefined
// clear accountId
this.accountId = undefined
await contactStore?.close()
await roomMemberStore?.close()
await roomStore?.close()
}
async destroy (): Promise<void> {
log.verbose('PayloadStore', 'destroy()')
if (this.accountId) {
throw new Error('Can not destroy() a start()-ed store. Call stop() to stop it first')
}
/**
* Huan(202108): `fs.rm` was introduced from Node.js v14.14
* https://nodejs.org/api/fs.html#fs_fspromises_rm_path_options
*/
await fs.promises.rmdir(this.storeDir, {
// force: true,
recursive: true,
})
}
}
export { PayloadStore }