1 | "use strict";
|
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3 | return new (P || (P = Promise))(function (resolve, reject) {
|
4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
7 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8 | });
|
9 | };
|
10 | Object.defineProperty(exports, "__esModule", { value: true });
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | const path_1 = require("path");
|
19 | const fs_extra_1 = require("fs-extra");
|
20 |
|
21 | const filenamify = require('filenamify');
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | const epochTicks = 621355968000000000;
|
27 |
|
28 |
|
29 |
|
30 |
|
31 | const ticksPerMillisecond = 10000;
|
32 |
|
33 |
|
34 |
|
35 |
|
36 | function getTicks(timestamp) {
|
37 | const ticks = epochTicks + (timestamp.getTime() * ticksPerMillisecond);
|
38 | return ticks.toString(16);
|
39 | }
|
40 |
|
41 |
|
42 |
|
43 |
|
44 | function readDate(ticks) {
|
45 | const t = Math.round((parseInt(ticks, 16) - epochTicks) / ticksPerMillisecond);
|
46 | return new Date(t);
|
47 | }
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 | function withDateFilter(date, fileName) {
|
54 | if (!date) {
|
55 | return true;
|
56 | }
|
57 | const ticks = fileName.split('-')[0];
|
58 | return readDate(ticks) >= date;
|
59 | }
|
60 |
|
61 |
|
62 |
|
63 |
|
64 | function includeWhen(expression) {
|
65 | let shouldInclude = false;
|
66 | return (item) => {
|
67 | return shouldInclude || (shouldInclude = expression(item));
|
68 | };
|
69 | }
|
70 |
|
71 |
|
72 |
|
73 |
|
74 | function parseActivity(json) {
|
75 | const activity = JSON.parse(json);
|
76 | activity.timestamp = new Date(activity.timestamp);
|
77 | return activity;
|
78 | }
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 | class FileTranscriptStore {
|
95 | |
96 |
|
97 |
|
98 |
|
99 | constructor(folder) {
|
100 | if (!folder) {
|
101 | throw new Error('Missing folder.');
|
102 | }
|
103 | this.rootFolder = folder;
|
104 | }
|
105 | |
106 |
|
107 |
|
108 |
|
109 | logActivity(activity) {
|
110 | return __awaiter(this, void 0, void 0, function* () {
|
111 | if (!activity) {
|
112 | throw new Error('activity cannot be null for logActivity()');
|
113 | }
|
114 | const conversationFolder = this.getTranscriptFolder(activity.channelId, activity.conversation.id);
|
115 | const activityFileName = this.getActivityFilename(activity);
|
116 | return this.saveActivity(activity, conversationFolder, activityFileName);
|
117 | });
|
118 | }
|
119 | |
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 | getTranscriptActivities(channelId, conversationId, continuationToken, startDate) {
|
127 | return __awaiter(this, void 0, void 0, function* () {
|
128 | if (!channelId) {
|
129 | throw new Error('Missing channelId');
|
130 | }
|
131 | if (!conversationId) {
|
132 | throw new Error('Missing conversationId');
|
133 | }
|
134 | const pagedResult = { items: [], continuationToken: undefined };
|
135 | const transcriptFolder = this.getTranscriptFolder(channelId, conversationId);
|
136 | const exists = yield fs_extra_1.pathExists(transcriptFolder);
|
137 | if (!exists) {
|
138 | return pagedResult;
|
139 | }
|
140 | let transcriptFolderContents = yield fs_extra_1.readdir(transcriptFolder);
|
141 | const include = includeWhen(fileName => !continuationToken || path_1.parse(fileName).name === continuationToken);
|
142 | const items = transcriptFolderContents.filter(transcript => transcript.endsWith('.json') &&
|
143 | withDateFilter(startDate, transcript) &&
|
144 | include(transcript));
|
145 | pagedResult.items = yield Promise.all(items
|
146 | .slice(0, FileTranscriptStore.PageSize)
|
147 | .sort()
|
148 | .map((activityFilename) => __awaiter(this, void 0, void 0, function* () {
|
149 | const json = yield fs_extra_1.readFile(path_1.join(transcriptFolder, activityFilename), 'utf8');
|
150 | return parseActivity(json);
|
151 | })));
|
152 | const { length } = pagedResult.items;
|
153 | if (length === FileTranscriptStore.PageSize && items[length]) {
|
154 | pagedResult.continuationToken = path_1.parse(items[length]).name;
|
155 | }
|
156 | return pagedResult;
|
157 | });
|
158 | }
|
159 | |
160 |
|
161 |
|
162 |
|
163 |
|
164 | listTranscripts(channelId, continuationToken) {
|
165 | return __awaiter(this, void 0, void 0, function* () {
|
166 | if (!channelId) {
|
167 | throw new Error('Missing channelId');
|
168 | }
|
169 | const pagedResult = { items: [], continuationToken: undefined };
|
170 | const channelFolder = this.getChannelFolder(channelId);
|
171 | const exists = yield fs_extra_1.pathExists(channelFolder);
|
172 | if (!exists) {
|
173 | return pagedResult;
|
174 | }
|
175 | const channels = yield fs_extra_1.readdir(channelFolder);
|
176 | const items = channels.filter(includeWhen(di => !continuationToken || di === continuationToken));
|
177 | pagedResult.items = items
|
178 | .slice(0, FileTranscriptStore.PageSize)
|
179 | .map(i => ({ channelId: channelId, id: i, created: null }));
|
180 | const { length } = pagedResult.items;
|
181 | if (length === FileTranscriptStore.PageSize && items[length]) {
|
182 | pagedResult.continuationToken = items[length];
|
183 | }
|
184 | return pagedResult;
|
185 | });
|
186 | }
|
187 | |
188 |
|
189 |
|
190 |
|
191 |
|
192 | deleteTranscript(channelId, conversationId) {
|
193 | return __awaiter(this, void 0, void 0, function* () {
|
194 | if (!channelId) {
|
195 | throw new Error('Missing channelId');
|
196 | }
|
197 | if (!conversationId) {
|
198 | throw new Error('Missing conversationId');
|
199 | }
|
200 | const transcriptFolder = this.getTranscriptFolder(channelId, conversationId);
|
201 | return fs_extra_1.remove(transcriptFolder);
|
202 | });
|
203 | }
|
204 | saveActivity(activity, transcriptPath, activityFilename) {
|
205 | return __awaiter(this, void 0, void 0, function* () {
|
206 | const json = JSON.stringify(activity, null, '\t');
|
207 | const exists = yield fs_extra_1.pathExists(transcriptPath);
|
208 | if (!exists) {
|
209 | yield fs_extra_1.mkdirp(transcriptPath);
|
210 | }
|
211 | return fs_extra_1.writeFile(path_1.join(transcriptPath, activityFilename), json, 'utf8');
|
212 | });
|
213 | }
|
214 | getActivityFilename(activity) {
|
215 | return `${getTicks(activity.timestamp)}-${this.sanitizeKey(activity.id)}.json`;
|
216 | }
|
217 | getChannelFolder(channelId) {
|
218 | return path_1.join(this.rootFolder, this.sanitizeKey(channelId));
|
219 | }
|
220 | getTranscriptFolder(channelId, conversationId) {
|
221 | return path_1.join(this.rootFolder, this.sanitizeKey(channelId), this.sanitizeKey(conversationId));
|
222 | }
|
223 | sanitizeKey(key) {
|
224 | return filenamify(key);
|
225 | }
|
226 | }
|
227 | FileTranscriptStore.PageSize = 20;
|
228 | exports.FileTranscriptStore = FileTranscriptStore;
|
229 |
|
\ | No newline at end of file |