UNPKG

5.01 kBPlain TextView Raw
1/**
2 * Copyright (c) Microsoft Corporation. All rights reserved.
3 * Licensed under the MIT License.
4 */
5import * as BB from 'botbuilder'
6import { CLDebug, DebugType } from './CLDebug'
7import { BotMemory } from './Memory/BotMemory'
8import { BotState } from './Memory/BotState'
9import { AppBase } from '@conversationlearner/models'
10
11export 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 // If memory storage not defined use disk storage
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 // Generate memory key from session
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 // First check mem cache to see if anything has changed, if not, can skip write
96 let cacheData = this.memCache[key]
97 if (cacheData == jsonString) {
98 CLDebug.Log(`-> ${key} : ${jsonString}`, DebugType.MemVerbose)
99 } else {
100 // Write to memory storage (use * for etag)
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 // TODO: Remove possibility of being null
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}