1 |
|
2 |
|
3 |
|
4 |
|
5 | import * as BB from 'botbuilder'
|
6 | import { CLDebug, DebugType } from './CLDebug'
|
7 | import { BotMemory } from './Memory/BotMemory'
|
8 | import { BotState } from './Memory/BotState'
|
9 | import { AppBase } from '@conversationlearner/models'
|
10 |
|
11 | export class CLMemory {
|
12 | private static memoryStorage: BB.Storage | null = null
|
13 | private memCache = {}
|
14 | private userkey: string
|
15 | private turnContext: BB.TurnContext | undefined
|
16 |
|
17 | public static Init(memoryStorage: BB.Storage | null): void {
|
18 | CLMemory.memoryStorage = memoryStorage
|
19 |
|
20 | if (!memoryStorage) {
|
21 | CLDebug.Log('Storage not defined. Defaulting to in-memory storage.')
|
22 | CLMemory.memoryStorage = new BB.MemoryStorage()
|
23 | }
|
24 | }
|
25 |
|
26 | private constructor(userkey: string) {
|
27 | this.userkey = userkey
|
28 | }
|
29 |
|
30 | public static GetMemory(key: string): CLMemory {
|
31 | return new CLMemory(key)
|
32 | }
|
33 |
|
34 |
|
35 | public static async InitMemory(turnContext: BB.TurnContext): Promise<CLMemory> {
|
36 | const user = turnContext.activity.from
|
37 | const conversationReference = BB.TurnContext.getConversationReference(turnContext.activity)
|
38 | if (!user) {
|
39 | throw new Error(`Attempted to initialize memory, but cannot get memory key because current request did not have 'from'/user specified`)
|
40 | }
|
41 | if (!user.id) {
|
42 | throw new Error(`Attempted to initialize memory, but user.id was not provided which is required for use as memory key.`)
|
43 | }
|
44 |
|
45 | let memory = new CLMemory(user.id)
|
46 | memory.turnContext = turnContext
|
47 | await memory.BotState.SetConversationReference(conversationReference)
|
48 | return memory
|
49 | }
|
50 |
|
51 | private Key(datakey: string): string {
|
52 | return `${this.userkey}_${datakey}`
|
53 | }
|
54 |
|
55 | public async GetAsync(datakey: string): Promise<any> {
|
56 | if (!CLMemory.memoryStorage) {
|
57 | throw new Error('Memory storage not found')
|
58 | }
|
59 |
|
60 | let key = this.Key(datakey)
|
61 | let cacheData = this.memCache[key]
|
62 | if (cacheData) {
|
63 | CLDebug.Log(`-< ${key} : ${cacheData}`, DebugType.MemVerbose)
|
64 | return cacheData
|
65 | } else {
|
66 | try {
|
67 | let data = await CLMemory.memoryStorage.read([key])
|
68 | if (data[key]) {
|
69 | this.memCache[key] = data[key].value
|
70 | } else {
|
71 | this.memCache[key] = null
|
72 | }
|
73 | CLDebug.Log(`R< ${key} : ${this.memCache[key]}`, DebugType.Memory)
|
74 | return this.memCache[key]
|
75 | }
|
76 | catch (err) {
|
77 | CLDebug.Error(err);
|
78 | return null;
|
79 | }
|
80 | }
|
81 | }
|
82 |
|
83 | public async SetAsync(datakey: string, jsonString: string): Promise<void> {
|
84 | if (!CLMemory.memoryStorage) {
|
85 | throw new Error('Memory storage not found')
|
86 | }
|
87 |
|
88 | if (jsonString == "null") {
|
89 | await this.DeleteAsync(datakey)
|
90 | return
|
91 | }
|
92 |
|
93 | let key = this.Key(datakey)
|
94 | try {
|
95 |
|
96 | let cacheData = this.memCache[key]
|
97 | if (cacheData == jsonString) {
|
98 | CLDebug.Log(`-> ${key} : ${jsonString}`, DebugType.MemVerbose)
|
99 | } else {
|
100 |
|
101 | await CLMemory.memoryStorage.write({ [key]: { value: jsonString, eTag: '*' } })
|
102 | this.memCache[key] = jsonString
|
103 | CLDebug.Log(`W> ${key} : ${jsonString}`, DebugType.Memory)
|
104 | }
|
105 | } catch (err) {
|
106 | CLDebug.Error(err)
|
107 | }
|
108 | }
|
109 |
|
110 | public async DeleteAsync(datakey: string): Promise<void> {
|
111 | let key = this.Key(datakey)
|
112 |
|
113 | try {
|
114 |
|
115 | if (!CLMemory.memoryStorage) {
|
116 | CLDebug.Error(`You attempted to delete key: ${key} before memoryStorage was defined`)
|
117 | }
|
118 | else {
|
119 |
|
120 | CLMemory.memoryStorage.delete([key])
|
121 | this.memCache[key] = null
|
122 | CLDebug.Log(`D> ${key} : -----`, DebugType.Memory)
|
123 | }
|
124 | } catch (err) {
|
125 | CLDebug.Error(err)
|
126 | }
|
127 | }
|
128 |
|
129 | public async SetAppAsync(app: AppBase | null): Promise<void> {
|
130 | const curApp = await this.BotState.GetApp();
|
131 | await this.BotState._SetAppAsync(app)
|
132 |
|
133 | if (!app || !curApp || curApp.appId !== app.appId) {
|
134 | await this.BotMemory.ClearAsync()
|
135 | }
|
136 | }
|
137 |
|
138 | public get BotMemory(): BotMemory {
|
139 | return BotMemory.Get(this)
|
140 | }
|
141 |
|
142 | public get BotState(): BotState {
|
143 | return BotState.Get(this)
|
144 | }
|
145 |
|
146 | public get TurnContext(): BB.TurnContext | undefined {
|
147 | return this.turnContext
|
148 | }
|
149 | }
|