@fluidframework/routerlicious-driver 2.0.0-dev.3.1.0.125672 → 2.0.0-dev.4.2.0.153917
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/CHANGELOG.md +5 -0
- package/README.md +38 -0
- package/dist/cache.js +2 -2
- package/dist/cache.js.map +1 -1
- package/dist/deltaStorageService.d.ts +1 -1
- package/dist/deltaStorageService.d.ts.map +1 -1
- package/dist/deltaStorageService.js +7 -4
- package/dist/deltaStorageService.js.map +1 -1
- package/dist/documentService.d.ts +4 -2
- package/dist/documentService.d.ts.map +1 -1
- package/dist/documentService.js +20 -12
- package/dist/documentService.js.map +1 -1
- package/dist/documentServiceFactory.d.ts +2 -2
- package/dist/documentServiceFactory.d.ts.map +1 -1
- package/dist/documentServiceFactory.js +21 -12
- package/dist/documentServiceFactory.js.map +1 -1
- package/dist/documentStorageService.d.ts +3 -2
- package/dist/documentStorageService.d.ts.map +1 -1
- package/dist/documentStorageService.js +4 -4
- package/dist/documentStorageService.js.map +1 -1
- package/dist/errorUtils.d.ts +9 -2
- package/dist/errorUtils.d.ts.map +1 -1
- package/dist/errorUtils.js +15 -8
- package/dist/errorUtils.js.map +1 -1
- package/dist/gitManager.d.ts +30 -0
- package/dist/gitManager.d.ts.map +1 -0
- package/dist/gitManager.js +89 -0
- package/dist/gitManager.js.map +1 -0
- package/dist/historian.d.ts +33 -0
- package/dist/historian.d.ts.map +1 -0
- package/dist/historian.js +65 -0
- package/dist/historian.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/mapWithExpiration.d.ts +34 -0
- package/dist/mapWithExpiration.d.ts.map +1 -0
- package/dist/mapWithExpiration.js +105 -0
- package/dist/mapWithExpiration.js.map +1 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/restWrapper.d.ts +21 -8
- package/dist/restWrapper.d.ts.map +1 -1
- package/dist/restWrapper.js +93 -25
- package/dist/restWrapper.js.map +1 -1
- package/dist/restWrapperBase.d.ts +26 -0
- package/dist/restWrapperBase.d.ts.map +1 -0
- package/dist/restWrapperBase.js +55 -0
- package/dist/restWrapperBase.js.map +1 -0
- package/dist/retriableGitManager.d.ts +10 -21
- package/dist/retriableGitManager.d.ts.map +1 -1
- package/dist/retriableGitManager.js +0 -36
- package/dist/retriableGitManager.js.map +1 -1
- package/dist/shreddedSummaryDocumentStorageService.d.ts +1 -1
- package/dist/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
- package/dist/shreddedSummaryDocumentStorageService.js +6 -6
- package/dist/shreddedSummaryDocumentStorageService.js.map +1 -1
- package/dist/storageContracts.d.ts +44 -0
- package/dist/storageContracts.d.ts.map +1 -0
- package/dist/storageContracts.js +7 -0
- package/dist/storageContracts.js.map +1 -0
- package/dist/summaryTreeUploadManager.d.ts +23 -0
- package/dist/summaryTreeUploadManager.d.ts.map +1 -0
- package/dist/summaryTreeUploadManager.js +110 -0
- package/dist/summaryTreeUploadManager.js.map +1 -0
- package/dist/tokens.d.ts +24 -7
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js.map +1 -1
- package/dist/treeUtils.d.ts +58 -0
- package/dist/treeUtils.d.ts.map +1 -0
- package/dist/treeUtils.js +107 -0
- package/dist/treeUtils.js.map +1 -0
- package/dist/wholeSummaryDocumentStorageService.d.ts +5 -4
- package/dist/wholeSummaryDocumentStorageService.d.ts.map +1 -1
- package/dist/wholeSummaryDocumentStorageService.js +70 -38
- package/dist/wholeSummaryDocumentStorageService.js.map +1 -1
- package/dist/wholeSummaryUploadManager.d.ts +16 -0
- package/dist/wholeSummaryUploadManager.d.ts.map +1 -0
- package/dist/wholeSummaryUploadManager.js +38 -0
- package/dist/wholeSummaryUploadManager.js.map +1 -0
- package/lib/cache.js +1 -1
- package/lib/cache.js.map +1 -1
- package/lib/deltaStorageService.d.ts +1 -1
- package/lib/deltaStorageService.d.ts.map +1 -1
- package/lib/deltaStorageService.js +7 -4
- package/lib/deltaStorageService.js.map +1 -1
- package/lib/documentService.d.ts +4 -2
- package/lib/documentService.d.ts.map +1 -1
- package/lib/documentService.js +20 -12
- package/lib/documentService.js.map +1 -1
- package/lib/documentServiceFactory.d.ts +2 -2
- package/lib/documentServiceFactory.d.ts.map +1 -1
- package/lib/documentServiceFactory.js +22 -13
- package/lib/documentServiceFactory.js.map +1 -1
- package/lib/documentStorageService.d.ts +3 -2
- package/lib/documentStorageService.d.ts.map +1 -1
- package/lib/documentStorageService.js +4 -4
- package/lib/documentStorageService.js.map +1 -1
- package/lib/errorUtils.d.ts +9 -2
- package/lib/errorUtils.d.ts.map +1 -1
- package/lib/errorUtils.js +14 -7
- package/lib/errorUtils.js.map +1 -1
- package/lib/gitManager.d.ts +30 -0
- package/lib/gitManager.d.ts.map +1 -0
- package/lib/gitManager.js +85 -0
- package/lib/gitManager.js.map +1 -0
- package/lib/historian.d.ts +33 -0
- package/lib/historian.d.ts.map +1 -0
- package/lib/historian.js +60 -0
- package/lib/historian.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/mapWithExpiration.d.ts +34 -0
- package/lib/mapWithExpiration.d.ts.map +1 -0
- package/lib/mapWithExpiration.js +101 -0
- package/lib/mapWithExpiration.js.map +1 -0
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/restWrapper.d.ts +21 -8
- package/lib/restWrapper.d.ts.map +1 -1
- package/lib/restWrapper.js +92 -26
- package/lib/restWrapper.js.map +1 -1
- package/lib/restWrapperBase.d.ts +26 -0
- package/lib/restWrapperBase.d.ts.map +1 -0
- package/lib/restWrapperBase.js +50 -0
- package/lib/restWrapperBase.js.map +1 -0
- package/lib/retriableGitManager.d.ts +10 -21
- package/lib/retriableGitManager.d.ts.map +1 -1
- package/lib/retriableGitManager.js +0 -36
- package/lib/retriableGitManager.js.map +1 -1
- package/lib/shreddedSummaryDocumentStorageService.d.ts +1 -1
- package/lib/shreddedSummaryDocumentStorageService.d.ts.map +1 -1
- package/lib/shreddedSummaryDocumentStorageService.js +5 -5
- package/lib/shreddedSummaryDocumentStorageService.js.map +1 -1
- package/lib/storageContracts.d.ts +44 -0
- package/lib/storageContracts.d.ts.map +1 -0
- package/lib/storageContracts.js +6 -0
- package/lib/storageContracts.js.map +1 -0
- package/lib/summaryTreeUploadManager.d.ts +23 -0
- package/lib/summaryTreeUploadManager.d.ts.map +1 -0
- package/lib/summaryTreeUploadManager.js +106 -0
- package/lib/summaryTreeUploadManager.js.map +1 -0
- package/lib/tokens.d.ts +24 -7
- package/lib/tokens.d.ts.map +1 -1
- package/lib/tokens.js.map +1 -1
- package/lib/treeUtils.d.ts +58 -0
- package/lib/treeUtils.d.ts.map +1 -0
- package/lib/treeUtils.js +100 -0
- package/lib/treeUtils.js.map +1 -0
- package/lib/wholeSummaryDocumentStorageService.d.ts +5 -4
- package/lib/wholeSummaryDocumentStorageService.d.ts.map +1 -1
- package/lib/wholeSummaryDocumentStorageService.js +70 -38
- package/lib/wholeSummaryDocumentStorageService.js.map +1 -1
- package/lib/wholeSummaryUploadManager.d.ts +16 -0
- package/lib/wholeSummaryUploadManager.d.ts.map +1 -0
- package/lib/wholeSummaryUploadManager.js +34 -0
- package/lib/wholeSummaryUploadManager.js.map +1 -0
- package/package.json +52 -54
- package/src/cache.ts +1 -1
- package/src/deltaStorageService.ts +11 -3
- package/src/documentService.ts +37 -22
- package/src/documentServiceFactory.ts +40 -21
- package/src/documentStorageService.ts +8 -4
- package/src/errorUtils.ts +16 -4
- package/src/gitManager.ts +116 -0
- package/src/historian.ts +121 -0
- package/src/index.ts +3 -0
- package/src/mapWithExpiration.ts +124 -0
- package/src/packageVersion.ts +1 -1
- package/src/restWrapper.ts +114 -38
- package/src/restWrapperBase.ts +146 -0
- package/src/retriableGitManager.ts +17 -95
- package/src/shreddedSummaryDocumentStorageService.ts +7 -9
- package/src/storageContracts.ts +63 -0
- package/src/summaryTreeUploadManager.ts +160 -0
- package/src/tokens.ts +24 -7
- package/src/treeUtils.ts +137 -0
- package/src/wholeSummaryDocumentStorageService.ts +118 -46
- package/src/wholeSummaryUploadManager.ts +64 -0
package/src/documentService.ts
CHANGED
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
|
|
6
6
|
import { assert } from "@fluidframework/common-utils";
|
|
7
7
|
import * as api from "@fluidframework/driver-definitions";
|
|
8
|
-
import {
|
|
8
|
+
import { DriverErrorType } from "@fluidframework/driver-definitions";
|
|
9
|
+
import { RateLimiter, NetworkErrorBasic, canRetryOnError } from "@fluidframework/driver-utils";
|
|
9
10
|
import { IClient } from "@fluidframework/protocol-definitions";
|
|
10
|
-
import {
|
|
11
|
+
import { INormalizedWholeSummary } from "@fluidframework/server-services-client";
|
|
11
12
|
import io from "socket.io-client";
|
|
12
|
-
import { PerformanceEvent } from "@fluidframework/telemetry-utils";
|
|
13
|
+
import { PerformanceEvent, wrapError } from "@fluidframework/telemetry-utils";
|
|
13
14
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
14
15
|
import { DeltaStorageService, DocumentDeltaStorageService } from "./deltaStorageService";
|
|
15
16
|
import { DocumentStorageService } from "./documentStorageService";
|
|
@@ -20,6 +21,10 @@ import { RouterliciousOrdererRestWrapper, RouterliciousStorageRestWrapper } from
|
|
|
20
21
|
import { IRouterliciousDriverPolicies } from "./policies";
|
|
21
22
|
import { ICache } from "./cache";
|
|
22
23
|
import { ISnapshotTreeVersion } from "./definitions";
|
|
24
|
+
import { pkgVersion as driverVersion } from "./packageVersion";
|
|
25
|
+
import { GitManager } from "./gitManager";
|
|
26
|
+
import { Historian } from "./historian";
|
|
27
|
+
import { RestWrapper } from "./restWrapperBase";
|
|
23
28
|
|
|
24
29
|
/**
|
|
25
30
|
* Amount of time between discoveries within which we don't need to rediscover on re-connect.
|
|
@@ -59,7 +64,8 @@ export class DocumentService implements api.IDocumentService {
|
|
|
59
64
|
private readonly documentStorageServicePolicies: api.IDocumentStorageServicePolicies,
|
|
60
65
|
private readonly driverPolicies: IRouterliciousDriverPolicies,
|
|
61
66
|
private readonly blobCache: ICache<ArrayBufferLike>,
|
|
62
|
-
private readonly
|
|
67
|
+
private readonly wholeSnapshotTreeCache: ICache<INormalizedWholeSummary>,
|
|
68
|
+
private readonly shreddedSummaryTreeCache: ICache<ISnapshotTreeVersion>,
|
|
63
69
|
private readonly discoverFluidResolvedUrl: () => Promise<api.IFluidResolvedUrl>,
|
|
64
70
|
) {}
|
|
65
71
|
|
|
@@ -103,14 +109,9 @@ export class DocumentService implements api.IDocumentService {
|
|
|
103
109
|
this.driverPolicies.enableRestLess,
|
|
104
110
|
this.storageUrl,
|
|
105
111
|
);
|
|
106
|
-
const historian = new Historian(
|
|
112
|
+
const historian = new Historian(true, false, storageRestWrapper);
|
|
107
113
|
this.storageManager = new GitManager(historian);
|
|
108
|
-
const noCacheHistorian = new Historian(
|
|
109
|
-
this.storageUrl,
|
|
110
|
-
true,
|
|
111
|
-
true,
|
|
112
|
-
storageRestWrapper,
|
|
113
|
-
);
|
|
114
|
+
const noCacheHistorian = new Historian(true, true, storageRestWrapper);
|
|
114
115
|
this.noCacheStorageManager = new GitManager(noCacheHistorian);
|
|
115
116
|
}
|
|
116
117
|
|
|
@@ -126,7 +127,8 @@ export class DocumentService implements api.IDocumentService {
|
|
|
126
127
|
this.documentStorageServicePolicies,
|
|
127
128
|
this.driverPolicies,
|
|
128
129
|
this.blobCache,
|
|
129
|
-
this.
|
|
130
|
+
this.wholeSnapshotTreeCache,
|
|
131
|
+
this.shreddedSummaryTreeCache,
|
|
130
132
|
noCacheStorageManager,
|
|
131
133
|
getStorageManager,
|
|
132
134
|
);
|
|
@@ -185,7 +187,7 @@ export class DocumentService implements api.IDocumentService {
|
|
|
185
187
|
*/
|
|
186
188
|
public async connectToDeltaStream(client: IClient): Promise<api.IDocumentDeltaConnection> {
|
|
187
189
|
const connect = async (refreshToken?: boolean) => {
|
|
188
|
-
let ordererToken = this.ordererRestWrapper.getToken();
|
|
190
|
+
let ordererToken = await this.ordererRestWrapper.getToken();
|
|
189
191
|
if (this.shouldUpdateDiscoveredSessionInfo()) {
|
|
190
192
|
await this.refreshDiscovery();
|
|
191
193
|
}
|
|
@@ -200,15 +202,28 @@ export class DocumentService implements api.IDocumentService {
|
|
|
200
202
|
refreshToken,
|
|
201
203
|
}),
|
|
202
204
|
},
|
|
203
|
-
async () =>
|
|
204
|
-
|
|
205
|
-
this.tenantId,
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
205
|
+
async () =>
|
|
206
|
+
this.tokenProvider
|
|
207
|
+
.fetchOrdererToken(this.tenantId, this.documentId, refreshToken)
|
|
208
|
+
.then(
|
|
209
|
+
(newOrdererToken) => {
|
|
210
|
+
this.ordererRestWrapper.setToken(newOrdererToken);
|
|
211
|
+
return newOrdererToken;
|
|
212
|
+
},
|
|
213
|
+
(error) => {
|
|
214
|
+
const tokenError = wrapError(
|
|
215
|
+
error,
|
|
216
|
+
(errorMessage) =>
|
|
217
|
+
new NetworkErrorBasic(
|
|
218
|
+
`The Host-provided token fetcher threw an error`,
|
|
219
|
+
DriverErrorType.fetchTokenError,
|
|
220
|
+
canRetryOnError(error),
|
|
221
|
+
{ errorMessage, driverVersion },
|
|
222
|
+
),
|
|
223
|
+
);
|
|
224
|
+
throw tokenError;
|
|
225
|
+
},
|
|
226
|
+
),
|
|
212
227
|
);
|
|
213
228
|
}
|
|
214
229
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { assert } from "@fluidframework/common-utils";
|
|
7
|
+
import { getW3CData } from "@fluidframework/driver-base";
|
|
7
8
|
import {
|
|
8
9
|
FiveDaysMs,
|
|
9
10
|
IDocumentService,
|
|
@@ -19,10 +20,11 @@ import {
|
|
|
19
20
|
ensureFluidResolvedUrl,
|
|
20
21
|
getDocAttributesFromProtocolSummary,
|
|
21
22
|
getQuorumValuesFromProtocolSummary,
|
|
23
|
+
isCombinedAppAndProtocolSummary,
|
|
22
24
|
RateLimiter,
|
|
23
25
|
} from "@fluidframework/driver-utils";
|
|
24
26
|
import { ChildLogger, PerformanceEvent } from "@fluidframework/telemetry-utils";
|
|
25
|
-
import { ISession } from "@fluidframework/server-services-client";
|
|
27
|
+
import { INormalizedWholeSummary, ISession } from "@fluidframework/server-services-client";
|
|
26
28
|
import { DocumentService } from "./documentService";
|
|
27
29
|
import { IRouterliciousDriverPolicies } from "./policies";
|
|
28
30
|
import { ITokenProvider } from "./tokens";
|
|
@@ -51,10 +53,10 @@ const defaultRouterliciousDriverPolicies: IRouterliciousDriverPolicies = {
|
|
|
51
53
|
* use the routerlicious implementation.
|
|
52
54
|
*/
|
|
53
55
|
export class RouterliciousDocumentServiceFactory implements IDocumentServiceFactory {
|
|
54
|
-
public readonly protocolName = "fluid:";
|
|
55
56
|
private readonly driverPolicies: IRouterliciousDriverPolicies;
|
|
56
57
|
private readonly blobCache: ICache<ArrayBufferLike>;
|
|
57
|
-
private readonly
|
|
58
|
+
private readonly wholeSnapshotTreeCache: ICache<INormalizedWholeSummary> = new NullCache();
|
|
59
|
+
private readonly shreddedSummaryTreeCache: ICache<ISnapshotTreeVersion> = new NullCache();
|
|
58
60
|
|
|
59
61
|
constructor(
|
|
60
62
|
private readonly tokenProvider: ITokenProvider,
|
|
@@ -68,9 +70,17 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
|
|
|
68
70
|
...driverPolicies,
|
|
69
71
|
};
|
|
70
72
|
this.blobCache = new InMemoryCache<ArrayBufferLike>();
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
if (this.driverPolicies.enableInternalSummaryCaching) {
|
|
74
|
+
if (this.driverPolicies.enableWholeSummaryUpload) {
|
|
75
|
+
this.wholeSnapshotTreeCache = new InMemoryCache<INormalizedWholeSummary>(
|
|
76
|
+
snapshotCacheExpiryMs,
|
|
77
|
+
);
|
|
78
|
+
} else {
|
|
79
|
+
this.shreddedSummaryTreeCache = new InMemoryCache<ISnapshotTreeVersion>(
|
|
80
|
+
snapshotCacheExpiryMs,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
74
84
|
}
|
|
75
85
|
|
|
76
86
|
/**
|
|
@@ -96,11 +106,12 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
|
|
|
96
106
|
}
|
|
97
107
|
const [, tenantId] = parsedUrl.pathname.split("/");
|
|
98
108
|
|
|
99
|
-
|
|
100
|
-
const appSummary = createNewSummary.tree[".app"] as ISummaryTree;
|
|
101
|
-
if (!(protocolSummary && appSummary)) {
|
|
109
|
+
if (!isCombinedAppAndProtocolSummary(createNewSummary)) {
|
|
102
110
|
throw new Error("Protocol and App Summary required in the full summary");
|
|
103
111
|
}
|
|
112
|
+
const protocolSummary = createNewSummary.tree[".protocol"];
|
|
113
|
+
const appSummary = createNewSummary.tree[".app"];
|
|
114
|
+
|
|
104
115
|
const documentAttributes = getDocAttributesFromProtocolSummary(protocolSummary);
|
|
105
116
|
const quorumValues = getQuorumValuesFromProtocolSummary(protocolSummary);
|
|
106
117
|
|
|
@@ -127,15 +138,17 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
|
|
|
127
138
|
},
|
|
128
139
|
async (event) => {
|
|
129
140
|
// @TODO: Remove returned "string" type when removing back-compat code
|
|
130
|
-
const postRes =
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
141
|
+
const postRes = (
|
|
142
|
+
await ordererRestWrapper.post<
|
|
143
|
+
{ id: string; token?: string; session?: ISession } | string
|
|
144
|
+
>(`/documents/${tenantId}`, {
|
|
145
|
+
summary: convertSummaryToCreateNewSummary(appSummary),
|
|
146
|
+
sequenceNumber: documentAttributes.sequenceNumber,
|
|
147
|
+
values: quorumValues,
|
|
148
|
+
enableDiscovery: this.driverPolicies.enableDiscovery,
|
|
149
|
+
generateToken: this.tokenProvider.documentPostCreateCallback !== undefined,
|
|
150
|
+
})
|
|
151
|
+
).content;
|
|
139
152
|
|
|
140
153
|
event.end({
|
|
141
154
|
docId: typeof postRes === "string" ? postRes : postRes.id,
|
|
@@ -252,11 +265,16 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
|
|
|
252
265
|
eventName: "DiscoverSession",
|
|
253
266
|
docId: documentId,
|
|
254
267
|
},
|
|
255
|
-
async () => {
|
|
268
|
+
async (event) => {
|
|
256
269
|
// The service responds with the current document session associated with the container.
|
|
257
|
-
|
|
270
|
+
const response = await ordererRestWrapper.get<ISession>(
|
|
258
271
|
`${resolvedUrl.endpoints.ordererUrl}/documents/${tenantId}/session/${documentId}`,
|
|
259
272
|
);
|
|
273
|
+
event.end({
|
|
274
|
+
...response.propsToLog,
|
|
275
|
+
...getW3CData(response.requestUrl, "xmlhttprequest"),
|
|
276
|
+
});
|
|
277
|
+
return response.content;
|
|
260
278
|
},
|
|
261
279
|
);
|
|
262
280
|
return getDiscoveredFluidResolvedUrl(resolvedUrl, discoveredSession);
|
|
@@ -298,7 +316,8 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
|
|
|
298
316
|
documentStorageServicePolicies,
|
|
299
317
|
this.driverPolicies,
|
|
300
318
|
this.blobCache,
|
|
301
|
-
this.
|
|
319
|
+
this.wholeSnapshotTreeCache,
|
|
320
|
+
this.shreddedSummaryTreeCache,
|
|
302
321
|
discoverFluidResolvedUrl,
|
|
303
322
|
);
|
|
304
323
|
}
|
|
@@ -10,15 +10,16 @@ import {
|
|
|
10
10
|
LoaderCachingPolicy,
|
|
11
11
|
} from "@fluidframework/driver-definitions";
|
|
12
12
|
import { ISnapshotTree, IVersion } from "@fluidframework/protocol-definitions";
|
|
13
|
-
import { GitManager } from "@fluidframework/server-services-client";
|
|
14
13
|
import {
|
|
15
14
|
DocumentStorageServiceProxy,
|
|
16
15
|
PrefetchDocumentStorageService,
|
|
17
16
|
} from "@fluidframework/driver-utils";
|
|
17
|
+
import { INormalizedWholeSummary } from "@fluidframework/server-services-client";
|
|
18
18
|
import { IRouterliciousDriverPolicies } from "./policies";
|
|
19
19
|
import { ICache } from "./cache";
|
|
20
20
|
import { WholeSummaryDocumentStorageService } from "./wholeSummaryDocumentStorageService";
|
|
21
21
|
import { ShreddedSummaryDocumentStorageService } from "./shreddedSummaryDocumentStorageService";
|
|
22
|
+
import { GitManager } from "./gitManager";
|
|
22
23
|
import { ISnapshotTreeVersion } from "./definitions";
|
|
23
24
|
|
|
24
25
|
export class DocumentStorageService extends DocumentStorageServiceProxy {
|
|
@@ -35,7 +36,8 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
|
|
|
35
36
|
policies: IDocumentStorageServicePolicies,
|
|
36
37
|
driverPolicies?: IRouterliciousDriverPolicies,
|
|
37
38
|
blobCache?: ICache<ArrayBufferLike>,
|
|
38
|
-
snapshotTreeCache?: ICache<
|
|
39
|
+
snapshotTreeCache?: ICache<INormalizedWholeSummary>,
|
|
40
|
+
shreddedSummaryTreeCache?: ICache<ISnapshotTreeVersion>,
|
|
39
41
|
noCacheGitManager?: GitManager,
|
|
40
42
|
getStorageManager?: (disableCache?: boolean) => Promise<GitManager>,
|
|
41
43
|
): IDocumentStorageService {
|
|
@@ -58,7 +60,7 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
|
|
|
58
60
|
policies,
|
|
59
61
|
driverPolicies,
|
|
60
62
|
blobCache,
|
|
61
|
-
|
|
63
|
+
shreddedSummaryTreeCache,
|
|
62
64
|
getStorageManager,
|
|
63
65
|
);
|
|
64
66
|
// TODO: worth prefetching latest summary making version + snapshot call with WholeSummary storage?
|
|
@@ -78,7 +80,8 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
|
|
|
78
80
|
policies: IDocumentStorageServicePolicies,
|
|
79
81
|
driverPolicies?: IRouterliciousDriverPolicies,
|
|
80
82
|
blobCache?: ICache<ArrayBufferLike>,
|
|
81
|
-
snapshotTreeCache?: ICache<
|
|
83
|
+
snapshotTreeCache?: ICache<INormalizedWholeSummary>,
|
|
84
|
+
shreddedSummaryTreeCache?: ICache<ISnapshotTreeVersion>,
|
|
82
85
|
public noCacheGitManager?: GitManager,
|
|
83
86
|
getStorageManager?: (disableCache?: boolean) => Promise<GitManager>,
|
|
84
87
|
) {
|
|
@@ -91,6 +94,7 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
|
|
|
91
94
|
driverPolicies,
|
|
92
95
|
blobCache,
|
|
93
96
|
snapshotTreeCache,
|
|
97
|
+
shreddedSummaryTreeCache,
|
|
94
98
|
noCacheGitManager,
|
|
95
99
|
getStorageManager,
|
|
96
100
|
),
|
package/src/errorUtils.ts
CHANGED
|
@@ -12,8 +12,16 @@ import {
|
|
|
12
12
|
} from "@fluidframework/driver-utils";
|
|
13
13
|
import { pkgVersion as driverVersion } from "./packageVersion";
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Routerlicious Error types
|
|
17
|
+
* Different error types that may be thrown by the routerlicious driver
|
|
18
|
+
*/
|
|
19
|
+
export enum RouterliciousErrorType {
|
|
20
|
+
/**
|
|
21
|
+
* File not found, or file deleted during session
|
|
22
|
+
*/
|
|
16
23
|
fileNotFoundOrAccessDeniedError = "fileNotFoundOrAccessDeniedError",
|
|
24
|
+
|
|
17
25
|
sslCertError = "sslCertError",
|
|
18
26
|
}
|
|
19
27
|
|
|
@@ -48,7 +56,7 @@ export interface IR11sSocketError {
|
|
|
48
56
|
}
|
|
49
57
|
|
|
50
58
|
export interface IR11sError {
|
|
51
|
-
readonly errorType:
|
|
59
|
+
readonly errorType: RouterliciousErrorType;
|
|
52
60
|
readonly message: string;
|
|
53
61
|
canRetry: boolean;
|
|
54
62
|
}
|
|
@@ -69,7 +77,11 @@ export function createR11sNetworkError(
|
|
|
69
77
|
// If there exists a self-signed SSL certificates error, throw a NonRetryableError
|
|
70
78
|
// TODO: instead of relying on string matching, filter error based on the error code like we do for websocket connections
|
|
71
79
|
if (errorMessage.includes("failed, reason: self signed certificate")) {
|
|
72
|
-
return new NonRetryableError(
|
|
80
|
+
return new NonRetryableError(
|
|
81
|
+
errorMessage,
|
|
82
|
+
RouterliciousErrorType.sslCertError,
|
|
83
|
+
props,
|
|
84
|
+
);
|
|
73
85
|
}
|
|
74
86
|
return new GenericNetworkError(
|
|
75
87
|
errorMessage,
|
|
@@ -82,7 +94,7 @@ export function createR11sNetworkError(
|
|
|
82
94
|
case 403:
|
|
83
95
|
return new AuthorizationError(errorMessage, undefined, undefined, props);
|
|
84
96
|
case 404:
|
|
85
|
-
const errorType =
|
|
97
|
+
const errorType = RouterliciousErrorType.fileNotFoundOrAccessDeniedError;
|
|
86
98
|
return new NonRetryableError(errorMessage, errorType, props);
|
|
87
99
|
case 429:
|
|
88
100
|
return createGenericNetworkError(errorMessage, { canRetry: true, retryAfterMs }, props);
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as resources from "@fluidframework/gitresources";
|
|
7
|
+
import {
|
|
8
|
+
IWholeFlatSummary,
|
|
9
|
+
IWholeSummaryPayload,
|
|
10
|
+
IWriteSummaryResponse,
|
|
11
|
+
} from "@fluidframework/server-services-client";
|
|
12
|
+
import { IGitManager, IHistorian } from "./storageContracts";
|
|
13
|
+
import { IR11sResponse, createR11sResponseFromContent } from "./restWrapper";
|
|
14
|
+
|
|
15
|
+
export class GitManager implements IGitManager {
|
|
16
|
+
private readonly blobCache = new Map<string, resources.IBlob>();
|
|
17
|
+
private readonly commitCache = new Map<string, resources.ICommit>();
|
|
18
|
+
private readonly treeCache = new Map<string, resources.ITree>();
|
|
19
|
+
private readonly refCache = new Map<string, string>();
|
|
20
|
+
|
|
21
|
+
constructor(private readonly historian: IHistorian) {}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Reads the object with the given ID. We defer to the client implementation to do the actual read.
|
|
25
|
+
*/
|
|
26
|
+
public async getCommits(
|
|
27
|
+
shaOrRef: string,
|
|
28
|
+
count: number,
|
|
29
|
+
): Promise<IR11sResponse<resources.ICommitDetails[]>> {
|
|
30
|
+
let sha: string | undefined = shaOrRef;
|
|
31
|
+
|
|
32
|
+
// See if the sha is really a ref and convert
|
|
33
|
+
if (this.refCache.has(shaOrRef)) {
|
|
34
|
+
sha = this.refCache.get(shaOrRef);
|
|
35
|
+
|
|
36
|
+
// Delete refcache after first use
|
|
37
|
+
this.refCache.delete(shaOrRef);
|
|
38
|
+
|
|
39
|
+
// If null is stored for the ref then there are no commits - return an empty array
|
|
40
|
+
if (!sha) {
|
|
41
|
+
return createR11sResponseFromContent([]);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// See if the commit sha is hashed and return it if so
|
|
46
|
+
const commit = this.commitCache.get(sha);
|
|
47
|
+
if (commit !== undefined) {
|
|
48
|
+
return createR11sResponseFromContent([
|
|
49
|
+
{
|
|
50
|
+
commit: {
|
|
51
|
+
author: commit.author,
|
|
52
|
+
committer: commit.committer,
|
|
53
|
+
message: commit.message,
|
|
54
|
+
tree: commit.tree,
|
|
55
|
+
url: commit.url,
|
|
56
|
+
},
|
|
57
|
+
parents: commit.parents,
|
|
58
|
+
sha: commit.sha,
|
|
59
|
+
url: commit.url,
|
|
60
|
+
},
|
|
61
|
+
]);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Otherwise fall back to the historian
|
|
65
|
+
return this.historian.getCommits(sha, count);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Reads the object with the given ID. We defer to the client implementation to do the actual read.
|
|
70
|
+
*/
|
|
71
|
+
public async getTree(root: string, recursive = true): Promise<IR11sResponse<resources.ITree>> {
|
|
72
|
+
const tree = this.treeCache.get(root);
|
|
73
|
+
if (tree !== undefined) {
|
|
74
|
+
return createR11sResponseFromContent(tree);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return this.historian.getTree(root, recursive);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public async getBlob(sha: string): Promise<IR11sResponse<resources.IBlob>> {
|
|
81
|
+
const blob = this.blobCache.get(sha);
|
|
82
|
+
if (blob !== undefined) {
|
|
83
|
+
return createR11sResponseFromContent(blob);
|
|
84
|
+
}
|
|
85
|
+
return this.historian.getBlob(sha);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public async createBlob(
|
|
89
|
+
content: string,
|
|
90
|
+
encoding: "utf-8" | "base64",
|
|
91
|
+
): Promise<IR11sResponse<resources.ICreateBlobResponse>> {
|
|
92
|
+
const blob: resources.ICreateBlobParams = {
|
|
93
|
+
content,
|
|
94
|
+
encoding,
|
|
95
|
+
};
|
|
96
|
+
return this.historian.createBlob(blob);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public async createGitTree(
|
|
100
|
+
params: resources.ICreateTreeParams,
|
|
101
|
+
): Promise<IR11sResponse<resources.ITree>> {
|
|
102
|
+
const treeP = this.historian.createTree(params);
|
|
103
|
+
return treeP;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public async createSummary(
|
|
107
|
+
summary: IWholeSummaryPayload,
|
|
108
|
+
initial: boolean = false,
|
|
109
|
+
): Promise<IR11sResponse<IWriteSummaryResponse>> {
|
|
110
|
+
return this.historian.createSummary(summary, initial);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public async getSummary(sha: string): Promise<IR11sResponse<IWholeFlatSummary>> {
|
|
114
|
+
return this.historian.getSummary(sha);
|
|
115
|
+
}
|
|
116
|
+
}
|
package/src/historian.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { fromUtf8ToBase64 } from "@fluidframework/common-utils";
|
|
7
|
+
import * as git from "@fluidframework/gitresources";
|
|
8
|
+
import {
|
|
9
|
+
IWholeFlatSummary,
|
|
10
|
+
IWholeSummaryPayload,
|
|
11
|
+
IWriteSummaryResponse,
|
|
12
|
+
} from "@fluidframework/server-services-client";
|
|
13
|
+
import { QueryStringType, RestWrapper } from "./restWrapperBase";
|
|
14
|
+
import { IR11sResponse } from "./restWrapper";
|
|
15
|
+
import { IHistorian } from "./storageContracts";
|
|
16
|
+
|
|
17
|
+
export interface ICredentials {
|
|
18
|
+
user: string;
|
|
19
|
+
password: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const getAuthorizationTokenFromCredentials = (credentials: ICredentials): string =>
|
|
23
|
+
`Basic ${fromUtf8ToBase64(`${credentials.user}:${credentials.password}`)}`;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Implementation of the IHistorian interface that calls out to a REST interface
|
|
27
|
+
*/
|
|
28
|
+
export class Historian implements IHistorian {
|
|
29
|
+
private readonly defaultQueryString: QueryStringType = {};
|
|
30
|
+
private readonly cacheBust: boolean;
|
|
31
|
+
|
|
32
|
+
constructor(
|
|
33
|
+
private readonly historianApi: boolean,
|
|
34
|
+
disableCache: boolean,
|
|
35
|
+
private readonly restWrapper: RestWrapper,
|
|
36
|
+
) {
|
|
37
|
+
if (disableCache && this.historianApi) {
|
|
38
|
+
this.defaultQueryString.disableCache = disableCache;
|
|
39
|
+
this.cacheBust = false;
|
|
40
|
+
} else {
|
|
41
|
+
this.cacheBust = disableCache;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public async getBlob(sha: string): Promise<IR11sResponse<git.IBlob>> {
|
|
46
|
+
return this.restWrapper.get<git.IBlob>(
|
|
47
|
+
`/git/blobs/${encodeURIComponent(sha)}`,
|
|
48
|
+
this.getQueryString(),
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public async createBlob(
|
|
53
|
+
blob: git.ICreateBlobParams,
|
|
54
|
+
): Promise<IR11sResponse<git.ICreateBlobResponse>> {
|
|
55
|
+
return this.restWrapper.post<git.ICreateBlobResponse>(
|
|
56
|
+
`/git/blobs`,
|
|
57
|
+
blob,
|
|
58
|
+
this.getQueryString(),
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public async getCommits(
|
|
63
|
+
sha: string,
|
|
64
|
+
count: number,
|
|
65
|
+
): Promise<IR11sResponse<git.ICommitDetails[]>> {
|
|
66
|
+
return this.restWrapper
|
|
67
|
+
.get<git.ICommitDetails[]>(`/commits`, this.getQueryString({ count, sha }))
|
|
68
|
+
.catch((error) =>
|
|
69
|
+
error.statusCode === 400 || error.statusCode === 404
|
|
70
|
+
? {
|
|
71
|
+
content: [],
|
|
72
|
+
headers: new Map(),
|
|
73
|
+
propsToLog: {},
|
|
74
|
+
requestUrl: "",
|
|
75
|
+
}
|
|
76
|
+
: Promise.reject<IR11sResponse<git.ICommitDetails[]>>(error),
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public async createTree(tree: git.ICreateTreeParams): Promise<IR11sResponse<git.ITree>> {
|
|
81
|
+
return this.restWrapper.post<git.ITree>(`/git/trees`, tree, this.getQueryString());
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public async getTree(sha: string, recursive: boolean): Promise<IR11sResponse<git.ITree>> {
|
|
85
|
+
return this.restWrapper.get<git.ITree>(
|
|
86
|
+
`/git/trees/${encodeURIComponent(sha)}`,
|
|
87
|
+
this.getQueryString({ recursive: recursive ? 1 : 0 }),
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
public async createSummary(
|
|
91
|
+
summary: IWholeSummaryPayload,
|
|
92
|
+
initial?: boolean,
|
|
93
|
+
): Promise<IR11sResponse<IWriteSummaryResponse>> {
|
|
94
|
+
return this.restWrapper.post<IWriteSummaryResponse>(
|
|
95
|
+
`/git/summaries`,
|
|
96
|
+
summary,
|
|
97
|
+
this.getQueryString(initial !== undefined ? { initial } : undefined),
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public async getSummary(sha: string): Promise<IR11sResponse<IWholeFlatSummary>> {
|
|
102
|
+
return this.restWrapper.get<IWholeFlatSummary>(
|
|
103
|
+
`/git/summaries/${sha}`,
|
|
104
|
+
this.getQueryString(),
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private getQueryString(queryString?: QueryStringType): QueryStringType {
|
|
109
|
+
if (this.cacheBust) {
|
|
110
|
+
return {
|
|
111
|
+
cacheBust: Date.now(),
|
|
112
|
+
...this.defaultQueryString,
|
|
113
|
+
...queryString,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
...this.defaultQueryString,
|
|
118
|
+
...queryString,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
export { DefaultTokenProvider } from "./defaultTokenProvider";
|
|
8
8
|
export { ITokenProvider, ITokenResponse, ITokenService } from "./tokens";
|
|
9
9
|
|
|
10
|
+
// Errors
|
|
11
|
+
export { RouterliciousErrorType } from "./errorUtils";
|
|
12
|
+
|
|
10
13
|
// Factory
|
|
11
14
|
export {
|
|
12
15
|
DocumentPostCreateError,
|