wechaty-puppet-padplus
Version:
Puppet Padplus for Wechaty
380 lines (332 loc) • 10.9 kB
text/typescript
import fs from 'fs-extra'
import os from 'os'
import path from 'path'
import { FlashStore } from 'flash-store'
import { log } from '../config'
import {
PadplusContactPayload,
PadplusRoomPayload,
PadplusRoomInvitationPayload,
PadplusRoomMemberPayload,
PadplusRoomMemberMap,
} from '../schemas'
import { FriendshipPayload } from 'wechaty-puppet'
const PRE = 'CacheManager'
export class CacheManager {
/**
* ************************************************************************
* Static Methods
* ************************************************************************
*/
private static _instance?: CacheManager
public static get Instance () {
if (!this._instance) {
throw new Error(`${PRE} cache manager instance not initialized.`)
}
return this._instance
}
public static async init (userId: string) {
log.verbose(PRE, `init()`)
if (this._instance) {
log.verbose(PRE, `init() CacheManager has been initialized, no need to initialize again.`)
return
}
this._instance = new CacheManager()
await this._instance.initCache(userId)
}
public static async release () {
log.verbose(PRE, `release()`)
if (!this._instance) {
log.verbose(PRE, `release() CacheManager not exist, no need to release it.`)
return
}
await this._instance.releaseCache()
this._instance = undefined
}
/**
* ************************************************************************
* Instance Methods
* ************************************************************************
*/
private cacheWXID? : FlashStore<string, string>
private cacheContactRawPayload? : FlashStore<string, PadplusContactPayload>
private cacheRoomMemberRawPayload? : FlashStore<string, {
[contactId: string]: PadplusRoomMemberPayload,
}>
private cacheRoomRawPayload? : FlashStore<string, PadplusRoomPayload>
private cacheRoomInvitationRawPayload? : FlashStore<string, PadplusRoomInvitationPayload>
private cacheFriendshipRawPayload? : FlashStore<string, FriendshipPayload>
/**
* -------------------------------
* Account-WXID Section
* --------------------------------
*/
public async getAccountWXID (
account: string,
): Promise<string | undefined> {
if (!this.cacheWXID) {
throw new Error(`${PRE} getWXID() has no cache.`)
}
return this.cacheWXID.get(account)
}
public async setAccountWXID (
account: string,
wxid: string,
): Promise<void> {
if (!this.cacheWXID) {
throw new Error(`${PRE} setWXID() has no cache.`)
}
await this.cacheWXID.set(account, wxid)
}
/**
* -------------------------------
* Contact Section
* --------------------------------
*/
public async getContact (
contactId: string,
): Promise<PadplusContactPayload | undefined> {
if (!this.cacheContactRawPayload) {
throw new Error(`${PRE} getContact() has no cache.`)
}
return this.cacheContactRawPayload.get(contactId)
}
public async setContact (
contactId: string,
payload: PadplusContactPayload
): Promise<void> {
if (!this.cacheContactRawPayload || !contactId) {
throw new Error(`${PRE} setContact() has no cache.`)
}
await this.cacheContactRawPayload.set(contactId, payload)
}
public async deleteContact (
contactId: string,
): Promise<void> {
if (!this.cacheContactRawPayload) {
throw new Error(`${PRE} deleteContact() has no cache.`)
}
await this.cacheContactRawPayload.delete(contactId)
}
public async getContactIds (): Promise<string[]> {
if (!this.cacheContactRawPayload) {
throw new Error(`${PRE} getContactIds() has no cache.`)
}
const result: string[] = []
for await (const key of this.cacheContactRawPayload.keys()) {
result.push(key)
}
return result
}
public async getAllContacts (): Promise<PadplusContactPayload[]> {
if (!this.cacheContactRawPayload) {
throw new Error(`${PRE} getAllContacts() has no cache.`)
}
const result: PadplusContactPayload[] = []
for await (const value of this.cacheContactRawPayload.values()) {
result.push(value)
}
return result
}
public async hasContact (contactId: string): Promise<boolean> {
if (!this.cacheContactRawPayload) {
throw new Error(`${PRE} hasContact() has no cache.`)
}
return this.cacheContactRawPayload.has(contactId)
}
public async getContactCount (): Promise<number> {
if (!this.cacheContactRawPayload) {
throw new Error(`${PRE} getContactCount() has no cache.`)
}
return this.cacheContactRawPayload.size
}
/**
* -------------------------------
* Room Section
* --------------------------------
*/
public async getRoom (
roomId: string,
): Promise<PadplusRoomPayload | undefined> {
if (!this.cacheRoomRawPayload) {
throw new Error(`${PRE} getRoom() has no cache.`)
}
return this.cacheRoomRawPayload.get(roomId)
}
public async setRoom (
roomId: string,
payload: PadplusRoomPayload
): Promise<void> {
if (!this.cacheRoomRawPayload) {
throw new Error(`${PRE} setRoom() has no cache.`)
}
await this.cacheRoomRawPayload.set(roomId, payload)
}
public async deleteRoom (
roomId: string,
): Promise<void> {
if (!this.cacheRoomRawPayload) {
throw new Error(`${PRE} setRoom() has no cache.`)
}
await this.cacheRoomRawPayload.delete(roomId)
}
public async getRoomIds (): Promise<string[]> {
if (!this.cacheRoomRawPayload) {
throw new Error(`${PRE} getRoomIds() has no cache.`)
}
const result: string[] = []
for await (const key of this.cacheRoomRawPayload.keys()) {
result.push(key)
}
return result
}
public async getRoomCount (): Promise<number> {
if (!this.cacheRoomRawPayload) {
throw new Error(`${PRE} getRoomCount() has no cache.`)
}
return this.cacheRoomRawPayload.size
}
public async hasRoom (roomId: string): Promise<boolean> {
if (!this.cacheRoomRawPayload) {
throw new Error(`${PRE} hasRoom() has no cache.`)
}
return this.cacheRoomRawPayload.has(roomId)
}
/**
* -------------------------------
* Room Member Section
* --------------------------------
*/
public async getRoomMember (
roomId: string,
): Promise<PadplusRoomMemberMap | undefined> {
if (!this.cacheRoomMemberRawPayload) {
throw new Error(`${PRE} getRoomMember() has no cache.`)
}
return this.cacheRoomMemberRawPayload.get(roomId)
}
public async setRoomMember (
roomId: string,
payload: PadplusRoomMemberMap,
): Promise<void> {
if (!this.cacheRoomMemberRawPayload) {
throw new Error(`${PRE} setRoomMember() has no cache.`)
}
await this.cacheRoomMemberRawPayload.set(roomId, payload)
}
public async deleteRoomMember (
roomId: string,
): Promise<void> {
if (!this.cacheRoomMemberRawPayload) {
throw new Error(`${PRE} deleteRoomMember() has no cache.`)
}
await this.cacheRoomMemberRawPayload.delete(roomId)
}
/**
* -------------------------------
* Room Invitation Section
* -------------------------------
*/
public async getRoomInvitation (
messageId: string,
): Promise<PadplusRoomInvitationPayload | undefined> {
if (!this.cacheRoomInvitationRawPayload) {
throw new Error(`${PRE} getRoomInvitationRawPayload() has no cache.`)
}
return this.cacheRoomInvitationRawPayload.get(messageId)
}
public async setRoomInvitation (
messageId: string,
payload: PadplusRoomInvitationPayload,
): Promise<void> {
if (!this.cacheRoomInvitationRawPayload) {
throw new Error(`${PRE} setRoomInvitationRawPayload() has no cache.`)
}
await this.cacheRoomInvitationRawPayload.set(messageId, payload)
}
public async deleteRoomInvitation (
messageId: string,
): Promise<void> {
if (!this.cacheRoomInvitationRawPayload) {
throw new Error(`${PRE} deleteRoomInvitation() has no cache.`)
}
await this.cacheRoomInvitationRawPayload.delete(messageId)
}
/**
* -------------------------------
* Friendship Cache Section
* --------------------------------
*/
public async getFriendshipRawPayload (id: string) {
if (!this.cacheFriendshipRawPayload) {
throw new Error(`${PRE} getFriendshipRawPayload() has no cache.`)
}
return this.cacheFriendshipRawPayload.get(id)
}
public async setFriendshipRawPayload (
id: string,
payload: FriendshipPayload,
) {
if (!this.cacheFriendshipRawPayload) {
throw new Error(`${PRE} setFriendshipRawPayload() has no cache.`)
}
await this.cacheFriendshipRawPayload.set(id, payload)
}
/**
* -------------------------------
* Private Method Section
* --------------------------------
*/
private async initCache (
userId: string,
): Promise<void> {
log.verbose(PRE, 'initCache(%s)', userId)
if (this.cacheContactRawPayload) {
throw new Error('cache exists')
}
const baseDir = path.join(
os.homedir(),
path.sep,
'.wechaty',
'puppet-padplus-cache',
path.sep,
'flash-store-v0.14',
path.sep,
userId,
)
const baseDirExist = await fs.pathExists(baseDir)
if (!baseDirExist) {
await fs.mkdirp(baseDir)
}
this.cacheWXID = new FlashStore(path.join(baseDir, 'accound-wxid'))
this.cacheContactRawPayload = new FlashStore(path.join(baseDir, 'contact-raw-payload'))
this.cacheRoomMemberRawPayload = new FlashStore(path.join(baseDir, 'room-member-raw-payload'))
this.cacheRoomRawPayload = new FlashStore(path.join(baseDir, 'room-raw-payload'))
this.cacheFriendshipRawPayload = new FlashStore(path.join(baseDir, 'friendship'))
const contactTotal = this.cacheContactRawPayload.size
log.verbose(PRE, `initCache() inited ${contactTotal} Contacts, cachedir="${baseDir}"`)
}
private async releaseCache () {
log.verbose(PRE, 'releaseCache()')
if (this.cacheContactRawPayload
&& this.cacheRoomMemberRawPayload
&& this.cacheRoomRawPayload
&& this.cacheFriendshipRawPayload
) {
log.silly(PRE, 'releaseCache() closing caches ...')
await Promise.all([
this.cacheContactRawPayload.close(),
this.cacheRoomMemberRawPayload.close(),
this.cacheRoomRawPayload.close(),
this.cacheFriendshipRawPayload.close(),
])
this.cacheContactRawPayload = undefined
this.cacheRoomMemberRawPayload = undefined
this.cacheRoomRawPayload = undefined
this.cacheFriendshipRawPayload = undefined
log.silly(PRE, 'releaseCache() cache closed.')
} else {
log.verbose(PRE, 'releaseCache() cache not exist.')
}
}
}