@fluidframework/routerlicious-driver 1.2.2 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/deltaStorageService.d.ts +5 -3
- package/dist/deltaStorageService.d.ts.map +1 -1
- package/dist/deltaStorageService.js +9 -5
- package/dist/deltaStorageService.js.map +1 -1
- package/dist/documentService.d.ts +21 -5
- package/dist/documentService.d.ts.map +1 -1
- package/dist/documentService.js +92 -19
- package/dist/documentService.js.map +1 -1
- package/dist/documentServiceFactory.d.ts +3 -2
- package/dist/documentServiceFactory.d.ts.map +1 -1
- package/dist/documentServiceFactory.js +18 -23
- package/dist/documentServiceFactory.js.map +1 -1
- package/dist/documentStorageService.d.ts +1 -1
- package/dist/documentStorageService.d.ts.map +1 -1
- package/dist/documentStorageService.js +5 -5
- package/dist/documentStorageService.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/shreddedSummaryDocumentStorageService.d.ts +3 -2
- package/dist/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
- package/dist/shreddedSummaryDocumentStorageService.js +21 -7
- package/dist/shreddedSummaryDocumentStorageService.js.map +1 -1
- package/dist/wholeSummaryDocumentStorageService.d.ts +4 -3
- package/dist/wholeSummaryDocumentStorageService.d.ts.map +1 -1
- package/dist/wholeSummaryDocumentStorageService.js +23 -10
- package/dist/wholeSummaryDocumentStorageService.js.map +1 -1
- package/lib/deltaStorageService.d.ts +5 -3
- package/lib/deltaStorageService.d.ts.map +1 -1
- package/lib/deltaStorageService.js +9 -5
- package/lib/deltaStorageService.js.map +1 -1
- package/lib/documentService.d.ts +21 -5
- package/lib/documentService.d.ts.map +1 -1
- package/lib/documentService.js +92 -19
- package/lib/documentService.js.map +1 -1
- package/lib/documentServiceFactory.d.ts +3 -2
- package/lib/documentServiceFactory.d.ts.map +1 -1
- package/lib/documentServiceFactory.js +18 -23
- package/lib/documentServiceFactory.js.map +1 -1
- package/lib/documentStorageService.d.ts +1 -1
- package/lib/documentStorageService.d.ts.map +1 -1
- package/lib/documentStorageService.js +5 -5
- package/lib/documentStorageService.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/shreddedSummaryDocumentStorageService.d.ts +3 -2
- package/lib/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
- package/lib/shreddedSummaryDocumentStorageService.js +21 -7
- package/lib/shreddedSummaryDocumentStorageService.js.map +1 -1
- package/lib/wholeSummaryDocumentStorageService.d.ts +4 -3
- package/lib/wholeSummaryDocumentStorageService.d.ts.map +1 -1
- package/lib/wholeSummaryDocumentStorageService.js +23 -10
- package/lib/wholeSummaryDocumentStorageService.js.map +1 -1
- package/package.json +6 -6
- package/src/deltaStorageService.ts +10 -5
- package/src/documentService.ts +142 -42
- package/src/documentServiceFactory.ts +23 -25
- package/src/documentStorageService.ts +10 -3
- package/src/packageVersion.ts +1 -1
- package/src/shreddedSummaryDocumentStorageService.ts +27 -13
- package/src/wholeSummaryDocumentStorageService.ts +26 -12
package/src/documentService.ts
CHANGED
|
@@ -7,8 +7,9 @@ import { assert } from "@fluidframework/common-utils";
|
|
|
7
7
|
import * as api from "@fluidframework/driver-definitions";
|
|
8
8
|
import { RateLimiter } from "@fluidframework/driver-utils";
|
|
9
9
|
import { IClient } from "@fluidframework/protocol-definitions";
|
|
10
|
-
import { GitManager, Historian } from "@fluidframework/server-services-client";
|
|
10
|
+
import { GitManager, Historian, RestWrapper } from "@fluidframework/server-services-client";
|
|
11
11
|
import io from "socket.io-client";
|
|
12
|
+
import { PerformanceEvent } from "@fluidframework/telemetry-utils";
|
|
12
13
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
13
14
|
import { DeltaStorageService, DocumentDeltaStorageService } from "./deltaStorageService";
|
|
14
15
|
import { DocumentStorageService } from "./documentStorageService";
|
|
@@ -20,16 +21,35 @@ import { IRouterliciousDriverPolicies } from "./policies";
|
|
|
20
21
|
import { ICache } from "./cache";
|
|
21
22
|
import { ISnapshotTreeVersion } from "./definitions";
|
|
22
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Amount of time between discoveries within which we don't need to rediscover on re-connect.
|
|
26
|
+
* Currently, R11s defines session length at 10 minutes. To avoid any weird unknown edge-cases though,
|
|
27
|
+
* we set the limit to 5 minutes here.
|
|
28
|
+
* In the future, we likely want to retrieve this information from service's "inactive session" definition.
|
|
29
|
+
*/
|
|
30
|
+
const RediscoverAfterTimeSinceDiscoveryMs = 5 * 60000; // 5 minute
|
|
31
|
+
|
|
23
32
|
/**
|
|
24
33
|
* The DocumentService manages the Socket.IO connection and manages routing requests to connected
|
|
25
|
-
* clients
|
|
34
|
+
* clients.
|
|
26
35
|
*/
|
|
27
36
|
export class DocumentService implements api.IDocumentService {
|
|
37
|
+
private lastDiscoveredAt: number = Date.now();
|
|
38
|
+
private discoverP: Promise<void> | undefined;
|
|
39
|
+
|
|
40
|
+
private storageManager: GitManager | undefined;
|
|
41
|
+
private noCacheStorageManager: GitManager | undefined;
|
|
42
|
+
private ordererRestWrapper: RestWrapper | undefined;
|
|
43
|
+
|
|
44
|
+
public get resolvedUrl() {
|
|
45
|
+
return this._resolvedUrl;
|
|
46
|
+
}
|
|
47
|
+
|
|
28
48
|
constructor(
|
|
29
|
-
|
|
49
|
+
private _resolvedUrl: api.IResolvedUrl,
|
|
30
50
|
protected ordererUrl: string,
|
|
31
|
-
private
|
|
32
|
-
private
|
|
51
|
+
private deltaStorageUrl: string,
|
|
52
|
+
private storageUrl: string,
|
|
33
53
|
private readonly logger: ITelemetryLogger,
|
|
34
54
|
protected tokenProvider: ITokenProvider,
|
|
35
55
|
protected tenantId: string,
|
|
@@ -37,6 +57,7 @@ export class DocumentService implements api.IDocumentService {
|
|
|
37
57
|
private readonly driverPolicies: IRouterliciousDriverPolicies,
|
|
38
58
|
private readonly blobCache: ICache<ArrayBufferLike>,
|
|
39
59
|
private readonly snapshotTreeCache: ICache<ISnapshotTreeVersion>,
|
|
60
|
+
private readonly discoverFluidResolvedUrl: () => Promise<api.IFluidResolvedUrl>,
|
|
40
61
|
) {
|
|
41
62
|
}
|
|
42
63
|
|
|
@@ -54,32 +75,45 @@ export class DocumentService implements api.IDocumentService {
|
|
|
54
75
|
return this.documentStorageService;
|
|
55
76
|
}
|
|
56
77
|
|
|
57
|
-
if (this.
|
|
78
|
+
if (this.storageUrl === undefined) {
|
|
58
79
|
return new NullBlobStorageService();
|
|
59
80
|
}
|
|
60
81
|
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
this.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
const getStorageManager = async (disableCache?: boolean): Promise<GitManager> => {
|
|
83
|
+
const shouldUpdateDiscoveredSessionInfo = this.shouldUpdateDiscoveredSessionInfo();
|
|
84
|
+
if (shouldUpdateDiscoveredSessionInfo) {
|
|
85
|
+
await this.refreshDiscovery();
|
|
86
|
+
}
|
|
87
|
+
if (!this.storageManager || !this.noCacheStorageManager || shouldUpdateDiscoveredSessionInfo) {
|
|
88
|
+
const rateLimiter = new RateLimiter(this.driverPolicies.maxConcurrentStorageRequests);
|
|
89
|
+
const storageRestWrapper = await RouterliciousStorageRestWrapper.load(
|
|
90
|
+
this.tenantId,
|
|
91
|
+
this.documentId,
|
|
92
|
+
this.tokenProvider,
|
|
93
|
+
this.logger,
|
|
94
|
+
rateLimiter,
|
|
95
|
+
this.driverPolicies.enableRestLess,
|
|
96
|
+
this.storageUrl,
|
|
97
|
+
);
|
|
98
|
+
const historian = new Historian(
|
|
99
|
+
this.storageUrl,
|
|
100
|
+
true,
|
|
101
|
+
false,
|
|
102
|
+
storageRestWrapper);
|
|
103
|
+
this.storageManager = new GitManager(historian);
|
|
104
|
+
const noCacheHistorian = new Historian(
|
|
105
|
+
this.storageUrl,
|
|
106
|
+
true,
|
|
107
|
+
true,
|
|
108
|
+
storageRestWrapper);
|
|
109
|
+
this.noCacheStorageManager = new GitManager(noCacheHistorian);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return disableCache ? this.noCacheStorageManager : this.storageManager;
|
|
113
|
+
};
|
|
114
|
+
// Initialize storageManager and noCacheStorageManager
|
|
115
|
+
const storageManager = await getStorageManager();
|
|
116
|
+
const noCacheStorageManager = await getStorageManager(true);
|
|
83
117
|
const documentStorageServicePolicies: api.IDocumentStorageServicePolicies = {
|
|
84
118
|
caching: this.driverPolicies.enablePrefetch
|
|
85
119
|
? api.LoaderCachingPolicy.Prefetch
|
|
@@ -89,13 +123,14 @@ export class DocumentService implements api.IDocumentService {
|
|
|
89
123
|
|
|
90
124
|
this.documentStorageService = new DocumentStorageService(
|
|
91
125
|
this.documentId,
|
|
92
|
-
|
|
126
|
+
storageManager,
|
|
93
127
|
this.logger,
|
|
94
128
|
documentStorageServicePolicies,
|
|
95
129
|
this.driverPolicies,
|
|
96
130
|
this.blobCache,
|
|
97
131
|
this.snapshotTreeCache,
|
|
98
|
-
|
|
132
|
+
noCacheStorageManager,
|
|
133
|
+
getStorageManager);
|
|
99
134
|
return this.documentStorageService;
|
|
100
135
|
}
|
|
101
136
|
|
|
@@ -108,18 +143,38 @@ export class DocumentService implements api.IDocumentService {
|
|
|
108
143
|
await this.connectToStorage();
|
|
109
144
|
assert(!!this.documentStorageService, 0x0b1 /* "Storage service not initialized" */);
|
|
110
145
|
|
|
111
|
-
const
|
|
112
|
-
|
|
146
|
+
const getRestWrapper = async (): Promise<RestWrapper> => {
|
|
147
|
+
const shouldUpdateDiscoveredSessionInfo = this.shouldUpdateDiscoveredSessionInfo();
|
|
148
|
+
if (shouldUpdateDiscoveredSessionInfo) {
|
|
149
|
+
await this.refreshDiscovery();
|
|
150
|
+
}
|
|
151
|
+
if (!this.ordererRestWrapper || shouldUpdateDiscoveredSessionInfo) {
|
|
152
|
+
const rateLimiter = new RateLimiter(this.driverPolicies.maxConcurrentOrdererRequests);
|
|
153
|
+
this.ordererRestWrapper = await RouterliciousOrdererRestWrapper.load(
|
|
154
|
+
this.tenantId,
|
|
155
|
+
this.documentId,
|
|
156
|
+
this.tokenProvider,
|
|
157
|
+
this.logger,
|
|
158
|
+
rateLimiter,
|
|
159
|
+
this.driverPolicies.enableRestLess,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
return this.ordererRestWrapper;
|
|
163
|
+
};
|
|
164
|
+
const restWrapper = await getRestWrapper();
|
|
165
|
+
const deltaStorageService = new DeltaStorageService(
|
|
166
|
+
this.deltaStorageUrl,
|
|
167
|
+
restWrapper,
|
|
168
|
+
this.logger,
|
|
169
|
+
getRestWrapper,
|
|
170
|
+
() => this.deltaStorageUrl,
|
|
171
|
+
);
|
|
172
|
+
return new DocumentDeltaStorageService(
|
|
113
173
|
this.tenantId,
|
|
114
174
|
this.documentId,
|
|
115
|
-
|
|
116
|
-
this.
|
|
117
|
-
rateLimiter,
|
|
118
|
-
this.driverPolicies.enableRestLess,
|
|
175
|
+
deltaStorageService,
|
|
176
|
+
this.documentStorageService,
|
|
119
177
|
);
|
|
120
|
-
const deltaStorage = new DeltaStorageService(this.deltaStorageUrl, ordererRestWrapper, this.logger);
|
|
121
|
-
return new DocumentDeltaStorageService(this.tenantId, this.documentId,
|
|
122
|
-
deltaStorage, this.documentStorageService);
|
|
123
178
|
}
|
|
124
179
|
|
|
125
180
|
/**
|
|
@@ -129,6 +184,9 @@ export class DocumentService implements api.IDocumentService {
|
|
|
129
184
|
*/
|
|
130
185
|
public async connectToDeltaStream(client: IClient): Promise<api.IDocumentDeltaConnection> {
|
|
131
186
|
const connect = async (refreshToken?: boolean) => {
|
|
187
|
+
if (this.shouldUpdateDiscoveredSessionInfo()) {
|
|
188
|
+
await this.refreshDiscovery();
|
|
189
|
+
}
|
|
132
190
|
const ordererToken = await this.tokenProvider.fetchOrdererToken(
|
|
133
191
|
this.tenantId,
|
|
134
192
|
this.documentId,
|
|
@@ -147,16 +205,58 @@ export class DocumentService implements api.IDocumentService {
|
|
|
147
205
|
|
|
148
206
|
// Attempt to establish connection.
|
|
149
207
|
// Retry with new token on authorization error; otherwise, allow container layer to handle.
|
|
208
|
+
let connection: api.IDocumentDeltaConnection;
|
|
150
209
|
try {
|
|
151
|
-
|
|
152
|
-
return connection;
|
|
210
|
+
connection = await connect();
|
|
153
211
|
} catch (error: any) {
|
|
154
212
|
if (error?.statusCode === 401) {
|
|
155
213
|
// Fetch new token and retry once,
|
|
156
214
|
// otherwise 401 will be bubbled up as non-retriable AuthorizationError.
|
|
157
|
-
|
|
215
|
+
connection = await connect(true /* refreshToken */);
|
|
158
216
|
}
|
|
159
217
|
throw error;
|
|
160
218
|
}
|
|
219
|
+
return connection;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Re-discover session URLs if necessary.
|
|
224
|
+
*/
|
|
225
|
+
private async refreshDiscovery(): Promise<void> {
|
|
226
|
+
if (!this.discoverP) {
|
|
227
|
+
this.discoverP = PerformanceEvent.timedExecAsync(
|
|
228
|
+
this.logger,
|
|
229
|
+
{
|
|
230
|
+
eventName: "refreshSessionDiscovery",
|
|
231
|
+
},
|
|
232
|
+
async () => this.refreshDiscoveryCore(),
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
return this.discoverP;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private async refreshDiscoveryCore(): Promise<void> {
|
|
239
|
+
const fluidResolvedUrl = await this.discoverFluidResolvedUrl();
|
|
240
|
+
this._resolvedUrl = fluidResolvedUrl;
|
|
241
|
+
this.storageUrl = fluidResolvedUrl.endpoints.storageUrl;
|
|
242
|
+
this.ordererUrl = fluidResolvedUrl.endpoints.ordererUrl;
|
|
243
|
+
this.deltaStorageUrl = fluidResolvedUrl.endpoints.deltaStorageUrl;
|
|
244
|
+
this.lastDiscoveredAt = Date.now();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Whether enough time has passed since last disconnect to warrant a new discovery call on reconnect.
|
|
249
|
+
*/
|
|
250
|
+
private shouldUpdateDiscoveredSessionInfo(): boolean {
|
|
251
|
+
if (!this.driverPolicies.enableDiscovery) {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
const now = Date.now();
|
|
255
|
+
// When connection is disconnected, we cannot know if session has moved or document has been deleted
|
|
256
|
+
// without re-doing discovery on the next attempt to connect.
|
|
257
|
+
// Disconnect event is not so reliable in local testing. To ensure re-discovery when necessary,
|
|
258
|
+
// re-discover if enough time has passed since last discovery.
|
|
259
|
+
const pastLastDiscoveryTimeThreshold = (now - this.lastDiscoveredAt) > RediscoverAfterTimeSinceDiscoveryMs;
|
|
260
|
+
return pastLastDiscoveryTimeThreshold;
|
|
161
261
|
}
|
|
162
262
|
}
|
|
@@ -7,6 +7,7 @@ import { assert } from "@fluidframework/common-utils";
|
|
|
7
7
|
import {
|
|
8
8
|
IDocumentService,
|
|
9
9
|
IDocumentServiceFactory,
|
|
10
|
+
IFluidResolvedUrl,
|
|
10
11
|
IResolvedUrl,
|
|
11
12
|
} from "@fluidframework/driver-definitions";
|
|
12
13
|
import { ITelemetryBaseLogger } from "@fluidframework/common-definitions";
|
|
@@ -121,20 +122,14 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
|
|
|
121
122
|
let documentId: string;
|
|
122
123
|
let token: string | undefined;
|
|
123
124
|
let session: ISession | undefined;
|
|
124
|
-
let fluidResolvedUrl: IResolvedUrl;
|
|
125
125
|
if (typeof res === "string") {
|
|
126
126
|
documentId = res;
|
|
127
127
|
} else {
|
|
128
128
|
documentId = res.id;
|
|
129
129
|
token = res.token;
|
|
130
|
-
session = res.session;
|
|
130
|
+
session = this.driverPolicies.enableDiscovery ? res.session : undefined;
|
|
131
131
|
}
|
|
132
|
-
|
|
133
|
-
fluidResolvedUrl = getDiscoveredFluidResolvedUrl(resolvedUrl, session);
|
|
134
|
-
} else {
|
|
135
|
-
fluidResolvedUrl = resolvedUrl;
|
|
136
|
-
}
|
|
137
|
-
parsedUrl = parseFluidUrl(fluidResolvedUrl.url);
|
|
132
|
+
parsedUrl = parseFluidUrl(resolvedUrl.url);
|
|
138
133
|
|
|
139
134
|
// @TODO: Remove token from the condition, checking the documentPostCreateCallback !== undefined
|
|
140
135
|
// is sufficient to determine if the token will be undefined or not.
|
|
@@ -147,7 +142,7 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
|
|
|
147
142
|
}
|
|
148
143
|
|
|
149
144
|
parsedUrl.set("pathname", replaceDocumentIdInPath(parsedUrl.pathname, documentId));
|
|
150
|
-
const deltaStorageUrl =
|
|
145
|
+
const deltaStorageUrl = resolvedUrl.endpoints.deltaStorageUrl;
|
|
151
146
|
if (!deltaStorageUrl) {
|
|
152
147
|
throw new Error(
|
|
153
148
|
`All endpoints urls must be provided. [deltaStorageUrl:${deltaStorageUrl}]`);
|
|
@@ -157,22 +152,22 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
|
|
|
157
152
|
|
|
158
153
|
return this.createDocumentService(
|
|
159
154
|
{
|
|
160
|
-
...
|
|
155
|
+
...resolvedUrl,
|
|
161
156
|
url: parsedUrl.toString(),
|
|
162
157
|
id: documentId,
|
|
163
158
|
endpoints: {
|
|
164
|
-
...
|
|
159
|
+
...resolvedUrl.endpoints,
|
|
165
160
|
deltaStorageUrl: parsedDeltaStorageUrl.toString(),
|
|
166
161
|
},
|
|
167
162
|
},
|
|
168
163
|
logger,
|
|
169
164
|
clientIsSummarizer,
|
|
170
|
-
|
|
165
|
+
session,
|
|
171
166
|
);
|
|
172
167
|
}
|
|
173
168
|
|
|
174
169
|
/**
|
|
175
|
-
* {@inheritDoc @fluidframework/driver-definitions#IDocumentServiceFactory.
|
|
170
|
+
* {@inheritDoc @fluidframework/driver-definitions#IDocumentServiceFactory.createDocumentService}
|
|
176
171
|
*
|
|
177
172
|
* @returns Routerlicious document service.
|
|
178
173
|
*/
|
|
@@ -180,7 +175,7 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
|
|
|
180
175
|
resolvedUrl: IResolvedUrl,
|
|
181
176
|
logger?: ITelemetryBaseLogger,
|
|
182
177
|
clientIsSummarizer?: boolean,
|
|
183
|
-
|
|
178
|
+
session?: ISession,
|
|
184
179
|
): Promise<IDocumentService> {
|
|
185
180
|
ensureFluidResolvedUrl(resolvedUrl);
|
|
186
181
|
|
|
@@ -192,8 +187,10 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
|
|
|
192
187
|
}
|
|
193
188
|
const logger2 = ChildLogger.create(logger, "RouterliciousDriver", { all: { driverVersion } });
|
|
194
189
|
|
|
195
|
-
|
|
196
|
-
|
|
190
|
+
const discoverFluidResolvedUrl = async (): Promise<IFluidResolvedUrl> => {
|
|
191
|
+
if (!this.driverPolicies.enableDiscovery) {
|
|
192
|
+
return resolvedUrl;
|
|
193
|
+
}
|
|
197
194
|
const rateLimiter = new RateLimiter(this.driverPolicies.maxConcurrentOrdererRequests);
|
|
198
195
|
const ordererRestWrapper = await RouterliciousOrdererRestWrapper.load(
|
|
199
196
|
tenantId,
|
|
@@ -204,15 +201,15 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
|
|
|
204
201
|
this.driverPolicies.enableRestLess,
|
|
205
202
|
resolvedUrl.endpoints.ordererUrl,
|
|
206
203
|
);
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const session: ISession = await ordererRestWrapper.get<ISession>(
|
|
204
|
+
// The service responds with the current document session associated with the container.
|
|
205
|
+
const discoveredSession = await ordererRestWrapper.get<ISession>(
|
|
210
206
|
`/documents/${tenantId}/session/${documentId}`,
|
|
211
207
|
);
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
|
|
208
|
+
return getDiscoveredFluidResolvedUrl(resolvedUrl, discoveredSession);
|
|
209
|
+
};
|
|
210
|
+
const fluidResolvedUrl: IFluidResolvedUrl = session !== undefined
|
|
211
|
+
? getDiscoveredFluidResolvedUrl(resolvedUrl, session)
|
|
212
|
+
: await discoverFluidResolvedUrl();
|
|
216
213
|
|
|
217
214
|
const storageUrl = fluidResolvedUrl.endpoints.storageUrl;
|
|
218
215
|
const ordererUrl = fluidResolvedUrl.endpoints.ordererUrl;
|
|
@@ -233,7 +230,8 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
|
|
|
233
230
|
documentId,
|
|
234
231
|
this.driverPolicies,
|
|
235
232
|
this.blobCache,
|
|
236
|
-
this.snapshotTreeCache
|
|
233
|
+
this.snapshotTreeCache,
|
|
234
|
+
discoverFluidResolvedUrl);
|
|
237
235
|
}
|
|
238
236
|
}
|
|
239
237
|
|
|
@@ -248,7 +246,7 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
|
|
|
248
246
|
* - How would a user delete the created document?
|
|
249
247
|
* - What would a retry pattern look like here?
|
|
250
248
|
*/
|
|
251
|
-
|
|
249
|
+
export class DocumentPostCreateError extends Error {
|
|
252
250
|
public constructor(
|
|
253
251
|
/**
|
|
254
252
|
* Inner error being wrapped.
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
IDocumentStorageService,
|
|
9
9
|
IDocumentStorageServicePolicies,
|
|
10
10
|
LoaderCachingPolicy,
|
|
11
|
-
|
|
11
|
+
} from "@fluidframework/driver-definitions";
|
|
12
12
|
import {
|
|
13
13
|
ISnapshotTree,
|
|
14
14
|
IVersion,
|
|
@@ -38,7 +38,9 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
|
|
|
38
38
|
driverPolicies?: IRouterliciousDriverPolicies,
|
|
39
39
|
blobCache?: ICache<ArrayBufferLike>,
|
|
40
40
|
snapshotTreeCache?: ICache<ISnapshotTreeVersion>,
|
|
41
|
-
noCacheGitManager?: GitManager
|
|
41
|
+
noCacheGitManager?: GitManager,
|
|
42
|
+
getStorageManager?: (disableCache?: boolean) => Promise<GitManager>,
|
|
43
|
+
): IDocumentStorageService {
|
|
42
44
|
const storageService = driverPolicies?.enableWholeSummaryUpload ?
|
|
43
45
|
new WholeSummaryDocumentStorageService(
|
|
44
46
|
id,
|
|
@@ -49,6 +51,7 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
|
|
|
49
51
|
blobCache,
|
|
50
52
|
snapshotTreeCache,
|
|
51
53
|
noCacheGitManager,
|
|
54
|
+
getStorageManager,
|
|
52
55
|
) :
|
|
53
56
|
new ShreddedSummaryDocumentStorageService(
|
|
54
57
|
id,
|
|
@@ -58,6 +61,7 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
|
|
|
58
61
|
driverPolicies,
|
|
59
62
|
blobCache,
|
|
60
63
|
snapshotTreeCache,
|
|
64
|
+
getStorageManager,
|
|
61
65
|
);
|
|
62
66
|
// TODO: worth prefetching latest summary making version + snapshot call with WholeSummary storage?
|
|
63
67
|
if (!driverPolicies?.enableWholeSummaryUpload && policies.caching === LoaderCachingPolicy.Prefetch) {
|
|
@@ -74,7 +78,9 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
|
|
|
74
78
|
driverPolicies?: IRouterliciousDriverPolicies,
|
|
75
79
|
blobCache?: ICache<ArrayBufferLike>,
|
|
76
80
|
snapshotTreeCache?: ICache<ISnapshotTreeVersion>,
|
|
77
|
-
public noCacheGitManager?: GitManager
|
|
81
|
+
public noCacheGitManager?: GitManager,
|
|
82
|
+
getStorageManager?: (disableCache?: boolean) => Promise<GitManager>,
|
|
83
|
+
) {
|
|
78
84
|
super(DocumentStorageService.loadInternalDocumentStorageService(
|
|
79
85
|
id,
|
|
80
86
|
manager,
|
|
@@ -84,6 +90,7 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
|
|
|
84
90
|
blobCache,
|
|
85
91
|
snapshotTreeCache,
|
|
86
92
|
noCacheGitManager,
|
|
93
|
+
getStorageManager,
|
|
87
94
|
));
|
|
88
95
|
}
|
|
89
96
|
|
package/src/packageVersion.ts
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
IDocumentStorageService,
|
|
13
13
|
ISummaryContext,
|
|
14
14
|
IDocumentStorageServicePolicies,
|
|
15
|
-
|
|
15
|
+
} from "@fluidframework/driver-definitions";
|
|
16
16
|
import { buildHierarchy } from "@fluidframework/protocol-base";
|
|
17
17
|
import {
|
|
18
18
|
ICreateBlobResponse,
|
|
@@ -45,12 +45,20 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
|
|
|
45
45
|
protected readonly blobsShaCache = new Map<string, string>();
|
|
46
46
|
private readonly blobCache: ICache<ArrayBufferLike> | undefined;
|
|
47
47
|
private readonly snapshotTreeCache: ICache<ISnapshotTreeVersion> | undefined;
|
|
48
|
-
private readonly summaryUploadManager: ISummaryUploadManager;
|
|
49
48
|
|
|
50
49
|
public get repositoryUrl(): string {
|
|
51
50
|
return "";
|
|
52
51
|
}
|
|
53
52
|
|
|
53
|
+
private async getSummaryUploadManager(): Promise<ISummaryUploadManager> {
|
|
54
|
+
const manager = await this.getStorageManager();
|
|
55
|
+
return new SummaryTreeUploadManager(
|
|
56
|
+
new RetriableGitManager(manager, this.logger),
|
|
57
|
+
this.blobsShaCache,
|
|
58
|
+
this.getPreviousFullSnapshot.bind(this),
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
54
62
|
constructor(
|
|
55
63
|
protected readonly id: string,
|
|
56
64
|
protected readonly manager: GitManager,
|
|
@@ -58,12 +66,9 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
|
|
|
58
66
|
public readonly policies: IDocumentStorageServicePolicies = {},
|
|
59
67
|
driverPolicies?: IRouterliciousDriverPolicies,
|
|
60
68
|
blobCache?: ICache<ArrayBufferLike>,
|
|
61
|
-
snapshotTreeCache?: ICache<ISnapshotTreeVersion
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
this.blobsShaCache,
|
|
65
|
-
this.getPreviousFullSnapshot.bind(this),
|
|
66
|
-
);
|
|
69
|
+
snapshotTreeCache?: ICache<ISnapshotTreeVersion>,
|
|
70
|
+
private readonly getStorageManager: (disableCache?: boolean) => Promise<GitManager> = async () => this.manager,
|
|
71
|
+
) {
|
|
67
72
|
if (driverPolicies?.enableRestLess === true || isNode) {
|
|
68
73
|
this.blobCache = blobCache ?? new InMemoryCache();
|
|
69
74
|
this.snapshotTreeCache = snapshotTreeCache ?? new InMemoryCache();
|
|
@@ -79,7 +84,10 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
|
|
|
79
84
|
versionId: id,
|
|
80
85
|
count,
|
|
81
86
|
},
|
|
82
|
-
async () =>
|
|
87
|
+
async () => {
|
|
88
|
+
const manager = await this.getStorageManager();
|
|
89
|
+
return manager.getCommits(id, count);
|
|
90
|
+
},
|
|
83
91
|
);
|
|
84
92
|
return commits.map((commit) => ({
|
|
85
93
|
date: commit.commit.author.date,
|
|
@@ -111,7 +119,8 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
|
|
|
111
119
|
treeId: requestVersion.treeId,
|
|
112
120
|
},
|
|
113
121
|
async (event) => {
|
|
114
|
-
const
|
|
122
|
+
const manager = await this.getStorageManager();
|
|
123
|
+
const response = await manager.getTree(requestVersion!.treeId);
|
|
115
124
|
event.end({
|
|
116
125
|
size: response.tree.length,
|
|
117
126
|
});
|
|
@@ -136,7 +145,8 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
|
|
|
136
145
|
blobId,
|
|
137
146
|
},
|
|
138
147
|
async (event) => {
|
|
139
|
-
const
|
|
148
|
+
const manager = await this.getStorageManager();
|
|
149
|
+
const response = await manager.getBlob(blobId);
|
|
140
150
|
event.end({
|
|
141
151
|
size: response.size,
|
|
142
152
|
});
|
|
@@ -155,7 +165,10 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
|
|
|
155
165
|
{
|
|
156
166
|
eventName: "uploadSummaryWithContext",
|
|
157
167
|
},
|
|
158
|
-
async () =>
|
|
168
|
+
async () => {
|
|
169
|
+
const summaryUploadManager = await this.getSummaryUploadManager();
|
|
170
|
+
return summaryUploadManager.writeSummaryTree(summary, context.ackHandle ?? "", "channel");
|
|
171
|
+
},
|
|
159
172
|
);
|
|
160
173
|
return summaryHandle;
|
|
161
174
|
}
|
|
@@ -173,7 +186,8 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
|
|
|
173
186
|
size: uint8ArrayFile.length,
|
|
174
187
|
},
|
|
175
188
|
async (event) => {
|
|
176
|
-
const
|
|
189
|
+
const manager = await this.getStorageManager();
|
|
190
|
+
const response = await manager.createBlob(
|
|
177
191
|
Uint8ArrayToString(
|
|
178
192
|
uint8ArrayFile, "base64"),
|
|
179
193
|
"base64").then((r) => ({ id: r.sha, url: r.url }));
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "@fluidframework/driver-definitions";
|
|
17
17
|
import {
|
|
18
18
|
convertSnapshotAndBlobsToSummaryTree,
|
|
19
|
-
|
|
19
|
+
} from "@fluidframework/driver-utils";
|
|
20
20
|
import {
|
|
21
21
|
ICreateBlobResponse,
|
|
22
22
|
ISnapshotTree,
|
|
@@ -38,13 +38,17 @@ import { IRouterliciousDriverPolicies } from "./policies";
|
|
|
38
38
|
const latestSnapshotId: string = "latest";
|
|
39
39
|
|
|
40
40
|
export class WholeSummaryDocumentStorageService implements IDocumentStorageService {
|
|
41
|
-
private readonly summaryUploadManager: ISummaryUploadManager;
|
|
42
41
|
private firstVersionsCall: boolean = true;
|
|
43
42
|
|
|
44
43
|
public get repositoryUrl(): string {
|
|
45
44
|
return "";
|
|
46
45
|
}
|
|
47
46
|
|
|
47
|
+
private async getSummaryUploadManager(): Promise<ISummaryUploadManager> {
|
|
48
|
+
const manager = await this.getStorageManager();
|
|
49
|
+
return new WholeSummaryUploadManager(manager);
|
|
50
|
+
}
|
|
51
|
+
|
|
48
52
|
constructor(
|
|
49
53
|
protected readonly id: string,
|
|
50
54
|
protected readonly manager: GitManager,
|
|
@@ -53,8 +57,10 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
|
|
|
53
57
|
private readonly driverPolicies?: IRouterliciousDriverPolicies,
|
|
54
58
|
private readonly blobCache: ICache<ArrayBufferLike> = new InMemoryCache(),
|
|
55
59
|
private readonly snapshotTreeCache: ICache<ISnapshotTreeVersion> = new InMemoryCache(),
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
private readonly noCacheGitManager?: GitManager,
|
|
61
|
+
private readonly getStorageManager: (disableCache?: boolean) => Promise<GitManager> = async (disableCache) =>
|
|
62
|
+
disableCache && this.noCacheGitManager !== undefined ? this.noCacheGitManager : this.manager,
|
|
63
|
+
) {
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
public async getVersions(versionId: string | null, count: number): Promise<IVersion[]> {
|
|
@@ -87,7 +93,10 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
|
|
|
87
93
|
versionId: id,
|
|
88
94
|
count,
|
|
89
95
|
},
|
|
90
|
-
async () =>
|
|
96
|
+
async () => {
|
|
97
|
+
const manager = await this.getStorageManager();
|
|
98
|
+
return manager.getCommits(id, count);
|
|
99
|
+
},
|
|
91
100
|
);
|
|
92
101
|
return commits.map((commit) => ({
|
|
93
102
|
date: commit.commit.author.date,
|
|
@@ -123,7 +132,8 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
|
|
|
123
132
|
blobId,
|
|
124
133
|
},
|
|
125
134
|
async (event) => {
|
|
126
|
-
const
|
|
135
|
+
const manager = await this.getStorageManager();
|
|
136
|
+
const response = await manager.getBlob(blobId);
|
|
127
137
|
event.end({
|
|
128
138
|
size: response.size,
|
|
129
139
|
});
|
|
@@ -143,7 +153,10 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
|
|
|
143
153
|
{
|
|
144
154
|
eventName: "uploadSummaryWithContext",
|
|
145
155
|
},
|
|
146
|
-
async () =>
|
|
156
|
+
async () => {
|
|
157
|
+
const summaryUploadManager = await this.getSummaryUploadManager();
|
|
158
|
+
return summaryUploadManager.writeSummaryTree(summary, context.ackHandle ?? "", "channel");
|
|
159
|
+
},
|
|
147
160
|
);
|
|
148
161
|
return summaryHandle;
|
|
149
162
|
}
|
|
@@ -156,7 +169,8 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
|
|
|
156
169
|
treeId: summaryHandle.handle,
|
|
157
170
|
},
|
|
158
171
|
async (event) => {
|
|
159
|
-
const
|
|
172
|
+
const manager = await this.getStorageManager();
|
|
173
|
+
const response = await manager.getSummary(summaryHandle.handle);
|
|
160
174
|
event.end({
|
|
161
175
|
size: response.trees[0]?.entries.length,
|
|
162
176
|
});
|
|
@@ -177,7 +191,8 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
|
|
|
177
191
|
size: uint8ArrayFile.length,
|
|
178
192
|
},
|
|
179
193
|
async (event) => {
|
|
180
|
-
const
|
|
194
|
+
const manager = await this.getStorageManager();
|
|
195
|
+
const response = await manager.createBlob(
|
|
181
196
|
Uint8ArrayToString(
|
|
182
197
|
uint8ArrayFile, "base64"),
|
|
183
198
|
"base64").then((r) => ({ id: r.sha, url: r.url }));
|
|
@@ -202,9 +217,8 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
|
|
|
202
217
|
treeId: versionId,
|
|
203
218
|
},
|
|
204
219
|
async (event) => {
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
await this.manager.getSummary(versionId);
|
|
220
|
+
const manager = await this.getStorageManager(disableCache);
|
|
221
|
+
const response = await manager.getSummary(versionId);
|
|
208
222
|
event.end({
|
|
209
223
|
size: response.trees[0]?.entries.length,
|
|
210
224
|
});
|