@fluidframework/routerlicious-driver 2.0.0-dev.4.1.0.148229 → 2.0.0-dev.4.3.0.157531
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/contracts.d.ts +15 -0
- package/dist/contracts.d.ts.map +1 -0
- package/dist/contracts.js +7 -0
- package/dist/contracts.js.map +1 -0
- 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 +11 -9
- package/dist/documentService.js.map +1 -1
- package/dist/documentServiceFactory.d.ts +2 -1
- package/dist/documentServiceFactory.d.ts.map +1 -1
- package/dist/documentServiceFactory.js +18 -8
- 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/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/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/r11sSnapshotParser.d.ts +15 -0
- package/dist/r11sSnapshotParser.d.ts.map +1 -0
- package/dist/r11sSnapshotParser.js +75 -0
- package/dist/r11sSnapshotParser.js.map +1 -0
- 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/treeUtils.d.ts +7 -0
- package/dist/treeUtils.d.ts.map +1 -1
- package/dist/treeUtils.js +23 -1
- package/dist/treeUtils.js.map +1 -1
- package/dist/wholeSummaryDocumentStorageService.d.ts +5 -4
- package/dist/wholeSummaryDocumentStorageService.d.ts.map +1 -1
- package/dist/wholeSummaryDocumentStorageService.js +74 -42
- 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/contracts.d.ts +15 -0
- package/lib/contracts.d.ts.map +1 -0
- package/lib/contracts.js +6 -0
- package/lib/contracts.js.map +1 -0
- 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 +9 -7
- package/lib/documentService.js.map +1 -1
- package/lib/documentServiceFactory.d.ts +2 -1
- package/lib/documentServiceFactory.d.ts.map +1 -1
- package/lib/documentServiceFactory.js +18 -8
- 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/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/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/r11sSnapshotParser.d.ts +15 -0
- package/lib/r11sSnapshotParser.d.ts.map +1 -0
- package/lib/r11sSnapshotParser.js +71 -0
- package/lib/r11sSnapshotParser.js.map +1 -0
- 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/treeUtils.d.ts +7 -0
- package/lib/treeUtils.d.ts.map +1 -1
- package/lib/treeUtils.js +20 -0
- package/lib/treeUtils.js.map +1 -1
- package/lib/wholeSummaryDocumentStorageService.d.ts +5 -4
- package/lib/wholeSummaryDocumentStorageService.d.ts.map +1 -1
- package/lib/wholeSummaryDocumentStorageService.js +74 -42
- 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 +9 -10
- package/src/contracts.ts +16 -0
- package/src/deltaStorageService.ts +11 -3
- package/src/documentService.ts +11 -11
- package/src/documentServiceFactory.ts +35 -16
- package/src/documentStorageService.ts +8 -4
- package/src/gitManager.ts +116 -0
- package/src/historian.ts +121 -0
- package/src/packageVersion.ts +1 -1
- package/src/r11sSnapshotParser.ts +83 -0
- 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/treeUtils.ts +30 -0
- package/src/wholeSummaryDocumentStorageService.ts +117 -58
- package/src/wholeSummaryUploadManager.ts +64 -0
package/src/restWrapper.ts
CHANGED
|
@@ -3,19 +3,14 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import type { ParsedUrlQueryInput } from "querystring";
|
|
9
|
-
|
|
10
|
-
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
11
|
-
import { fromUtf8ToBase64 } from "@fluidframework/common-utils";
|
|
6
|
+
import { ITelemetryLogger, ITelemetryProperties } from "@fluidframework/common-definitions";
|
|
7
|
+
import { assert, fromUtf8ToBase64, performance } from "@fluidframework/common-utils";
|
|
12
8
|
import { RateLimiter } from "@fluidframework/driver-utils";
|
|
13
9
|
import {
|
|
14
10
|
getAuthorizationTokenFromCredentials,
|
|
15
11
|
RestLessClient,
|
|
16
|
-
RestWrapper,
|
|
17
12
|
} from "@fluidframework/server-services-client";
|
|
18
|
-
import { PerformanceEvent } from "@fluidframework/telemetry-utils";
|
|
13
|
+
import { PerformanceEvent, TelemetryLogger } from "@fluidframework/telemetry-utils";
|
|
19
14
|
import fetch from "cross-fetch";
|
|
20
15
|
import type { AxiosRequestConfig, AxiosRequestHeaders } from "axios";
|
|
21
16
|
import safeStringify from "json-stringify-safe";
|
|
@@ -23,6 +18,7 @@ import { v4 as uuid } from "uuid";
|
|
|
23
18
|
import { throwR11sNetworkError } from "./errorUtils";
|
|
24
19
|
import { ITokenProvider, ITokenResponse } from "./tokens";
|
|
25
20
|
import { pkgVersion as driverVersion } from "./packageVersion";
|
|
21
|
+
import { QueryStringType, RestWrapper } from "./restWrapperBase";
|
|
26
22
|
|
|
27
23
|
type AuthorizationHeaderGetter = (token: ITokenResponse) => string;
|
|
28
24
|
type TokenFetcher = (refresh?: boolean) => Promise<ITokenResponse>;
|
|
@@ -44,18 +40,75 @@ const axiosRequestConfigToFetchRequestConfig = (
|
|
|
44
40
|
return [requestInfo, requestInit];
|
|
45
41
|
};
|
|
46
42
|
|
|
43
|
+
export interface IR11sResponse<T> {
|
|
44
|
+
content: T;
|
|
45
|
+
headers: Map<string, string>;
|
|
46
|
+
propsToLog: ITelemetryProperties;
|
|
47
|
+
requestUrl: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* A utility function to create a r11s response without any additional props as we might not have them always.
|
|
52
|
+
* @param content - response which is equivalent to content.
|
|
53
|
+
* @returns - a r11s response without any extra props.
|
|
54
|
+
*/
|
|
55
|
+
export function createR11sResponseFromContent<T>(content: T): IR11sResponse<T> {
|
|
56
|
+
return {
|
|
57
|
+
content,
|
|
58
|
+
headers: new Map(),
|
|
59
|
+
propsToLog: {},
|
|
60
|
+
requestUrl: "",
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function headersToMap(headers: Headers) {
|
|
65
|
+
const newHeaders = new Map<string, string>();
|
|
66
|
+
for (const [key, value] of headers.entries()) {
|
|
67
|
+
newHeaders.set(key, value);
|
|
68
|
+
}
|
|
69
|
+
return newHeaders;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function getPropsToLogFromResponse(headers: {
|
|
73
|
+
get: (id: string) => string | undefined | null;
|
|
74
|
+
}) {
|
|
75
|
+
interface LoggingHeader {
|
|
76
|
+
headerName: string;
|
|
77
|
+
logName: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// We rename headers so that otel doesn't scrub them away. Otel doesn't allow
|
|
81
|
+
// certain characters in headers including '-'
|
|
82
|
+
const headersToLog: LoggingHeader[] = [
|
|
83
|
+
{ headerName: "x-correlation-id", logName: "requestCorrelationId" },
|
|
84
|
+
{ headerName: "content-encoding", logName: "contentEncoding" },
|
|
85
|
+
{ headerName: "content-type", logName: "contentType" },
|
|
86
|
+
];
|
|
87
|
+
const additionalProps: ITelemetryProperties = {
|
|
88
|
+
contentsize: TelemetryLogger.numberFromString(headers.get("content-length")),
|
|
89
|
+
};
|
|
90
|
+
headersToLog.forEach((header) => {
|
|
91
|
+
const headerValue = headers.get(header.headerName);
|
|
92
|
+
if (headerValue !== undefined && headerValue !== null) {
|
|
93
|
+
additionalProps[header.logName] = headerValue;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
return additionalProps;
|
|
98
|
+
}
|
|
99
|
+
|
|
47
100
|
export class RouterliciousRestWrapper extends RestWrapper {
|
|
48
101
|
private readonly restLess = new RestLessClient();
|
|
102
|
+
private token: ITokenResponse | undefined;
|
|
49
103
|
|
|
50
104
|
constructor(
|
|
51
105
|
logger: ITelemetryLogger,
|
|
52
106
|
private readonly rateLimiter: RateLimiter,
|
|
53
|
-
private token: ITokenResponse,
|
|
54
107
|
private readonly fetchRefreshedToken: TokenFetcher,
|
|
55
108
|
private readonly getAuthorizationHeader: AuthorizationHeaderGetter,
|
|
56
109
|
private readonly useRestLess: boolean,
|
|
57
110
|
baseurl?: string,
|
|
58
|
-
defaultQueryString:
|
|
111
|
+
defaultQueryString: QueryStringType = {},
|
|
59
112
|
) {
|
|
60
113
|
super(baseurl, defaultQueryString);
|
|
61
114
|
}
|
|
@@ -64,33 +117,59 @@ export class RouterliciousRestWrapper extends RestWrapper {
|
|
|
64
117
|
requestConfig: AxiosRequestConfig,
|
|
65
118
|
statusCode: number,
|
|
66
119
|
canRetry = true,
|
|
67
|
-
): Promise<T
|
|
120
|
+
): Promise<IR11sResponse<T>> {
|
|
68
121
|
const config = {
|
|
69
122
|
...requestConfig,
|
|
70
|
-
headers: this.generateHeaders(requestConfig.headers),
|
|
123
|
+
headers: await this.generateHeaders(requestConfig.headers),
|
|
71
124
|
};
|
|
72
125
|
|
|
73
126
|
const translatedConfig = this.useRestLess ? this.restLess.translate(config) : config;
|
|
74
127
|
const fetchRequestConfig = axiosRequestConfigToFetchRequestConfig(translatedConfig);
|
|
75
128
|
|
|
76
|
-
const
|
|
77
|
-
|
|
129
|
+
const res = await this.rateLimiter.schedule(async () => {
|
|
130
|
+
const perfStart = performance.now();
|
|
131
|
+
const result = await fetch(...fetchRequestConfig).catch(async (error) => {
|
|
78
132
|
// Browser Fetch throws a TypeError on network error, `node-fetch` throws a FetchError
|
|
79
133
|
const isNetworkError = ["TypeError", "FetchError"].includes(error?.name);
|
|
80
134
|
throwR11sNetworkError(
|
|
81
135
|
isNetworkError ? `NetworkError: ${error.message}` : safeStringify(error),
|
|
82
136
|
);
|
|
83
|
-
})
|
|
84
|
-
|
|
137
|
+
});
|
|
138
|
+
return {
|
|
139
|
+
response: result,
|
|
140
|
+
duration: performance.now() - perfStart,
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const response = res.response;
|
|
85
145
|
|
|
146
|
+
let start = performance.now();
|
|
147
|
+
const text = await response.text();
|
|
148
|
+
const receiveContentTime = performance.now() - start;
|
|
149
|
+
|
|
150
|
+
const bodySize = text.length;
|
|
151
|
+
start = performance.now();
|
|
86
152
|
const responseBody: any = response.headers.get("content-type")?.includes("application/json")
|
|
87
|
-
?
|
|
88
|
-
:
|
|
153
|
+
? JSON.parse(text)
|
|
154
|
+
: text;
|
|
155
|
+
const parseTime = performance.now() - start;
|
|
89
156
|
|
|
90
157
|
// Success
|
|
91
158
|
if (response.ok || response.status === statusCode) {
|
|
92
|
-
const result
|
|
93
|
-
|
|
159
|
+
const result = responseBody as T;
|
|
160
|
+
const headers = headersToMap(response.headers);
|
|
161
|
+
return {
|
|
162
|
+
content: result,
|
|
163
|
+
headers,
|
|
164
|
+
requestUrl: fetchRequestConfig[0].toString(),
|
|
165
|
+
propsToLog: {
|
|
166
|
+
...getPropsToLogFromResponse(headers),
|
|
167
|
+
bodySize,
|
|
168
|
+
receiveContentTime,
|
|
169
|
+
parseTime,
|
|
170
|
+
fetchTime: res.duration,
|
|
171
|
+
},
|
|
172
|
+
};
|
|
94
173
|
}
|
|
95
174
|
// Failure
|
|
96
175
|
if (response.status === 401 && canRetry) {
|
|
@@ -100,7 +179,7 @@ export class RouterliciousRestWrapper extends RestWrapper {
|
|
|
100
179
|
}
|
|
101
180
|
if (response.status === 429 && responseBody?.retryAfter > 0) {
|
|
102
181
|
// Retry based on retryAfter[Seconds]
|
|
103
|
-
return new Promise<T
|
|
182
|
+
return new Promise<IR11sResponse<T>>((resolve, reject) =>
|
|
104
183
|
setTimeout(() => {
|
|
105
184
|
this.request<T>(config, statusCode).then(resolve).catch(reject);
|
|
106
185
|
}, responseBody.retryAfter * 1000),
|
|
@@ -120,9 +199,11 @@ export class RouterliciousRestWrapper extends RestWrapper {
|
|
|
120
199
|
);
|
|
121
200
|
}
|
|
122
201
|
|
|
123
|
-
private generateHeaders(
|
|
202
|
+
private async generateHeaders(
|
|
124
203
|
requestHeaders?: AxiosRequestHeaders | undefined,
|
|
125
|
-
): Record<string, string
|
|
204
|
+
): Promise<Record<string, string>> {
|
|
205
|
+
const token = await this.getToken();
|
|
206
|
+
assert(token !== undefined, 0x679 /* token should be present */);
|
|
126
207
|
const correlationId = requestHeaders?.["x-correlation-id"] ?? uuid();
|
|
127
208
|
|
|
128
209
|
return {
|
|
@@ -132,12 +213,17 @@ export class RouterliciousRestWrapper extends RestWrapper {
|
|
|
132
213
|
"x-correlation-id": correlationId as string,
|
|
133
214
|
"x-driver-version": driverVersion,
|
|
134
215
|
// NOTE: If this.authorizationHeader is undefined, should "Authorization" be removed entirely?
|
|
135
|
-
"Authorization": this.getAuthorizationHeader(
|
|
216
|
+
"Authorization": this.getAuthorizationHeader(token),
|
|
136
217
|
};
|
|
137
218
|
}
|
|
138
219
|
|
|
139
|
-
public getToken(): ITokenResponse {
|
|
140
|
-
|
|
220
|
+
public async getToken(): Promise<ITokenResponse> {
|
|
221
|
+
if (this.token !== undefined) {
|
|
222
|
+
return this.token;
|
|
223
|
+
}
|
|
224
|
+
const token = await this.fetchRefreshedToken();
|
|
225
|
+
this.setToken(token);
|
|
226
|
+
return token;
|
|
141
227
|
}
|
|
142
228
|
|
|
143
229
|
public setToken(token: ITokenResponse) {
|
|
@@ -149,17 +235,15 @@ export class RouterliciousStorageRestWrapper extends RouterliciousRestWrapper {
|
|
|
149
235
|
private constructor(
|
|
150
236
|
logger: ITelemetryLogger,
|
|
151
237
|
rateLimiter: RateLimiter,
|
|
152
|
-
token: ITokenResponse,
|
|
153
238
|
fetchToken: TokenFetcher,
|
|
154
239
|
getAuthorizationHeader: AuthorizationHeaderGetter,
|
|
155
240
|
useRestLess: boolean,
|
|
156
241
|
baseurl?: string,
|
|
157
|
-
defaultQueryString:
|
|
242
|
+
defaultQueryString: QueryStringType = {},
|
|
158
243
|
) {
|
|
159
244
|
super(
|
|
160
245
|
logger,
|
|
161
246
|
rateLimiter,
|
|
162
|
-
token,
|
|
163
247
|
fetchToken,
|
|
164
248
|
getAuthorizationHeader,
|
|
165
249
|
useRestLess,
|
|
@@ -211,12 +295,9 @@ export class RouterliciousStorageRestWrapper extends RouterliciousRestWrapper {
|
|
|
211
295
|
return getAuthorizationTokenFromCredentials(credentials);
|
|
212
296
|
};
|
|
213
297
|
|
|
214
|
-
const storagetoken = await fetchStorageToken();
|
|
215
|
-
|
|
216
298
|
const restWrapper = new RouterliciousStorageRestWrapper(
|
|
217
299
|
logger,
|
|
218
300
|
rateLimiter,
|
|
219
|
-
storagetoken,
|
|
220
301
|
fetchStorageToken,
|
|
221
302
|
getAuthorizationHeader,
|
|
222
303
|
useRestLess,
|
|
@@ -232,17 +313,15 @@ export class RouterliciousOrdererRestWrapper extends RouterliciousRestWrapper {
|
|
|
232
313
|
private constructor(
|
|
233
314
|
logger: ITelemetryLogger,
|
|
234
315
|
rateLimiter: RateLimiter,
|
|
235
|
-
token: ITokenResponse,
|
|
236
316
|
fetchToken: TokenFetcher,
|
|
237
317
|
getAuthorizationHeader: AuthorizationHeaderGetter,
|
|
238
318
|
useRestLess: boolean,
|
|
239
319
|
baseurl?: string,
|
|
240
|
-
defaultQueryString:
|
|
320
|
+
defaultQueryString: QueryStringType = {},
|
|
241
321
|
) {
|
|
242
322
|
super(
|
|
243
323
|
logger,
|
|
244
324
|
rateLimiter,
|
|
245
|
-
token,
|
|
246
325
|
fetchToken,
|
|
247
326
|
getAuthorizationHeader,
|
|
248
327
|
useRestLess,
|
|
@@ -285,12 +364,9 @@ export class RouterliciousOrdererRestWrapper extends RouterliciousRestWrapper {
|
|
|
285
364
|
);
|
|
286
365
|
};
|
|
287
366
|
|
|
288
|
-
const newtoken = await fetchOrdererToken();
|
|
289
|
-
|
|
290
367
|
const restWrapper = new RouterliciousOrdererRestWrapper(
|
|
291
368
|
logger,
|
|
292
369
|
rateLimiter,
|
|
293
|
-
newtoken,
|
|
294
370
|
fetchOrdererToken,
|
|
295
371
|
getAuthorizationHeader,
|
|
296
372
|
useRestLess,
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { AxiosRequestConfig, AxiosRequestHeaders } from "axios";
|
|
7
|
+
import { IR11sResponse } from "./restWrapper";
|
|
8
|
+
|
|
9
|
+
export abstract class RestWrapper {
|
|
10
|
+
constructor(
|
|
11
|
+
protected readonly baseurl?: string,
|
|
12
|
+
protected defaultQueryString: QueryStringType = {},
|
|
13
|
+
protected readonly maxBodyLength = 1000 * 1024 * 1024,
|
|
14
|
+
protected readonly maxContentLength = 1000 * 1024 * 1024,
|
|
15
|
+
) {}
|
|
16
|
+
|
|
17
|
+
public async get<T>(
|
|
18
|
+
url: string,
|
|
19
|
+
queryString?: QueryStringType,
|
|
20
|
+
headers?: AxiosRequestHeaders,
|
|
21
|
+
additionalOptions?: Partial<
|
|
22
|
+
Omit<
|
|
23
|
+
AxiosRequestConfig,
|
|
24
|
+
"baseURL" | "headers" | "maxBodyLength" | "maxContentLength" | "method" | "url"
|
|
25
|
+
>
|
|
26
|
+
>,
|
|
27
|
+
): Promise<IR11sResponse<T>> {
|
|
28
|
+
const options: AxiosRequestConfig = {
|
|
29
|
+
...additionalOptions,
|
|
30
|
+
baseURL: this.baseurl,
|
|
31
|
+
headers,
|
|
32
|
+
maxBodyLength: this.maxBodyLength,
|
|
33
|
+
maxContentLength: this.maxContentLength,
|
|
34
|
+
method: "GET",
|
|
35
|
+
url: `${url}${this.generateQueryString(queryString)}`,
|
|
36
|
+
};
|
|
37
|
+
return this.request<T>(options, 200);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public async post<T>(
|
|
41
|
+
url: string,
|
|
42
|
+
requestBody: any,
|
|
43
|
+
queryString?: QueryStringType,
|
|
44
|
+
headers?: AxiosRequestHeaders,
|
|
45
|
+
additionalOptions?: Partial<
|
|
46
|
+
Omit<
|
|
47
|
+
AxiosRequestConfig,
|
|
48
|
+
"baseURL" | "headers" | "maxBodyLength" | "maxContentLength" | "method" | "url"
|
|
49
|
+
>
|
|
50
|
+
>,
|
|
51
|
+
): Promise<IR11sResponse<T>> {
|
|
52
|
+
const options: AxiosRequestConfig = {
|
|
53
|
+
...additionalOptions,
|
|
54
|
+
baseURL: this.baseurl,
|
|
55
|
+
data: requestBody,
|
|
56
|
+
headers,
|
|
57
|
+
maxBodyLength: this.maxBodyLength,
|
|
58
|
+
maxContentLength: this.maxContentLength,
|
|
59
|
+
method: "POST",
|
|
60
|
+
url: `${url}${this.generateQueryString(queryString)}`,
|
|
61
|
+
};
|
|
62
|
+
return this.request<T>(options, 201);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public async delete<T>(
|
|
66
|
+
url: string,
|
|
67
|
+
queryString?: QueryStringType,
|
|
68
|
+
headers?: AxiosRequestHeaders,
|
|
69
|
+
additionalOptions?: Partial<
|
|
70
|
+
Omit<
|
|
71
|
+
AxiosRequestConfig,
|
|
72
|
+
"baseURL" | "headers" | "maxBodyLength" | "maxContentLength" | "method" | "url"
|
|
73
|
+
>
|
|
74
|
+
>,
|
|
75
|
+
): Promise<IR11sResponse<T>> {
|
|
76
|
+
const options: AxiosRequestConfig = {
|
|
77
|
+
...additionalOptions,
|
|
78
|
+
baseURL: this.baseurl,
|
|
79
|
+
headers,
|
|
80
|
+
maxBodyLength: this.maxBodyLength,
|
|
81
|
+
maxContentLength: this.maxContentLength,
|
|
82
|
+
method: "DELETE",
|
|
83
|
+
url: `${url}${this.generateQueryString(queryString)}`,
|
|
84
|
+
};
|
|
85
|
+
return this.request<T>(options, 204);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public async patch<T>(
|
|
89
|
+
url: string,
|
|
90
|
+
requestBody: any,
|
|
91
|
+
queryString?: QueryStringType,
|
|
92
|
+
headers?: AxiosRequestHeaders,
|
|
93
|
+
additionalOptions?: Partial<
|
|
94
|
+
Omit<
|
|
95
|
+
AxiosRequestConfig,
|
|
96
|
+
"baseURL" | "headers" | "maxBodyLength" | "maxContentLength" | "method" | "url"
|
|
97
|
+
>
|
|
98
|
+
>,
|
|
99
|
+
): Promise<IR11sResponse<T>> {
|
|
100
|
+
const options: AxiosRequestConfig = {
|
|
101
|
+
...additionalOptions,
|
|
102
|
+
baseURL: this.baseurl,
|
|
103
|
+
data: requestBody,
|
|
104
|
+
headers,
|
|
105
|
+
maxBodyLength: this.maxBodyLength,
|
|
106
|
+
maxContentLength: this.maxContentLength,
|
|
107
|
+
method: "PATCH",
|
|
108
|
+
url: `${url}${this.generateQueryString(queryString)}`,
|
|
109
|
+
};
|
|
110
|
+
return this.request<T>(options, 200);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
protected abstract request<T>(
|
|
114
|
+
options: AxiosRequestConfig,
|
|
115
|
+
statusCode: number,
|
|
116
|
+
addNetworkCallProps?: boolean,
|
|
117
|
+
): Promise<IR11sResponse<T>>;
|
|
118
|
+
|
|
119
|
+
protected generateQueryString(queryStringValues?: QueryStringType) {
|
|
120
|
+
if (this.defaultQueryString || queryStringValues) {
|
|
121
|
+
const queryStringMap = { ...this.defaultQueryString, ...queryStringValues };
|
|
122
|
+
|
|
123
|
+
return getQueryString(queryStringMap);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return "";
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Generates query string from the given query parameters.
|
|
132
|
+
* @param queryParams - Query parameters from which to create a query.
|
|
133
|
+
*/
|
|
134
|
+
export function getQueryString(queryParams: QueryStringType): string {
|
|
135
|
+
let queryString = "";
|
|
136
|
+
for (const key of Object.keys(queryParams)) {
|
|
137
|
+
if (queryParams[key] !== undefined) {
|
|
138
|
+
const startChar = queryString === "" ? "?" : "&";
|
|
139
|
+
queryString += `${startChar}${key}=${encodeURIComponent(queryParams[key])}`;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return queryString;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export type QueryStringType = Record<string, string | number | boolean>;
|
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type * as git from "@fluidframework/gitresources";
|
|
7
|
-
import type * as protocol from "@fluidframework/protocol-definitions";
|
|
8
7
|
import {
|
|
9
|
-
IGitManager,
|
|
10
8
|
IWholeFlatSummary,
|
|
11
9
|
IWholeSummaryPayload,
|
|
12
10
|
IWriteSummaryResponse,
|
|
13
11
|
} from "@fluidframework/server-services-client";
|
|
14
12
|
import { runWithRetry } from "@fluidframework/driver-utils";
|
|
15
13
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
14
|
+
import { IGitManager } from "./storageContracts";
|
|
15
|
+
import { IR11sResponse } from "./restWrapper";
|
|
16
16
|
|
|
17
17
|
export class RetriableGitManager implements IGitManager {
|
|
18
18
|
constructor(
|
|
@@ -20,135 +20,57 @@ export class RetriableGitManager implements IGitManager {
|
|
|
20
20
|
private readonly logger: ITelemetryLogger,
|
|
21
21
|
) {}
|
|
22
22
|
|
|
23
|
-
public async
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
public async getFullTree(sha: string): Promise<any> {
|
|
31
|
-
return this.runWithRetry(
|
|
32
|
-
async () => this.internalGitManager.getFullTree(sha),
|
|
33
|
-
"gitManager_getFullTree",
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
public async getCommit(sha: string): Promise<git.ICommit> {
|
|
38
|
-
return this.runWithRetry(
|
|
39
|
-
async () => this.internalGitManager.getCommit(sha),
|
|
40
|
-
"gitManager_getCommit",
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
public async getCommits(sha: string, count: number): Promise<git.ICommitDetails[]> {
|
|
23
|
+
public async getCommits(
|
|
24
|
+
sha: string,
|
|
25
|
+
count: number,
|
|
26
|
+
): Promise<IR11sResponse<git.ICommitDetails[]>> {
|
|
45
27
|
return this.runWithRetry(
|
|
46
28
|
async () => this.internalGitManager.getCommits(sha, count),
|
|
47
29
|
"gitManager_getCommits",
|
|
48
30
|
);
|
|
49
31
|
}
|
|
50
32
|
|
|
51
|
-
public async getTree(root: string, recursive: boolean): Promise<git.ITree
|
|
33
|
+
public async getTree(root: string, recursive: boolean): Promise<IR11sResponse<git.ITree>> {
|
|
52
34
|
return this.runWithRetry(
|
|
53
35
|
async () => this.internalGitManager.getTree(root, recursive),
|
|
54
36
|
"gitManager_getTree",
|
|
55
37
|
);
|
|
56
38
|
}
|
|
57
39
|
|
|
58
|
-
public async getBlob(sha: string): Promise<git.IBlob
|
|
40
|
+
public async getBlob(sha: string): Promise<IR11sResponse<git.IBlob>> {
|
|
59
41
|
return this.runWithRetry(
|
|
60
42
|
async () => this.internalGitManager.getBlob(sha),
|
|
61
43
|
"gitManager_getBlob",
|
|
62
44
|
);
|
|
63
45
|
}
|
|
64
46
|
|
|
65
|
-
public
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
public async getContent(commit: string, path: string): Promise<git.IBlob> {
|
|
70
|
-
return this.runWithRetry(
|
|
71
|
-
async () => this.internalGitManager.getContent(commit, path),
|
|
72
|
-
"gitManager_getContent",
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
public async createBlob(content: string, encoding: string): Promise<git.ICreateBlobResponse> {
|
|
47
|
+
public async createBlob(
|
|
48
|
+
content: string,
|
|
49
|
+
encoding: string,
|
|
50
|
+
): Promise<IR11sResponse<git.ICreateBlobResponse>> {
|
|
77
51
|
return this.runWithRetry(
|
|
78
52
|
async () => this.internalGitManager.createBlob(content, encoding),
|
|
79
53
|
"gitManager_createBlob",
|
|
80
54
|
);
|
|
81
55
|
}
|
|
82
56
|
|
|
83
|
-
public async createGitTree(params: git.ICreateTreeParams): Promise<git.ITree
|
|
57
|
+
public async createGitTree(params: git.ICreateTreeParams): Promise<IR11sResponse<git.ITree>> {
|
|
84
58
|
return this.runWithRetry(
|
|
85
59
|
async () => this.internalGitManager.createGitTree(params),
|
|
86
60
|
"gitManager_createGitTree",
|
|
87
61
|
);
|
|
88
62
|
}
|
|
89
63
|
|
|
90
|
-
public async
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
"gitManager_createTree",
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
public async createCommit(commit: git.ICreateCommitParams): Promise<git.ICommit> {
|
|
98
|
-
return this.runWithRetry(
|
|
99
|
-
async () => this.internalGitManager.createCommit(commit),
|
|
100
|
-
"gitManager_createCommit",
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
public async getRef(ref: string): Promise<git.IRef> {
|
|
105
|
-
return this.runWithRetry(
|
|
106
|
-
async () => this.internalGitManager.getRef(ref),
|
|
107
|
-
"gitManager_getRef",
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
public async createRef(branch: string, sha: string): Promise<git.IRef> {
|
|
112
|
-
return this.runWithRetry(
|
|
113
|
-
async () => this.internalGitManager.createRef(branch, sha),
|
|
114
|
-
"gitManager_createRef",
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
public async upsertRef(branch: string, commitSha: string): Promise<git.IRef> {
|
|
119
|
-
return this.runWithRetry(
|
|
120
|
-
async () => this.internalGitManager.upsertRef(branch, commitSha),
|
|
121
|
-
"gitManager_upsertRef",
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
public async write(
|
|
126
|
-
branch: string,
|
|
127
|
-
inputTree: protocol.ITree,
|
|
128
|
-
parents: string[],
|
|
129
|
-
message: string,
|
|
130
|
-
): Promise<git.ICommit> {
|
|
131
|
-
return this.runWithRetry(
|
|
132
|
-
async () => this.internalGitManager.write(branch, inputTree, parents, message),
|
|
133
|
-
"gitManager_write",
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
public async createSummary(summary: IWholeSummaryPayload): Promise<IWriteSummaryResponse> {
|
|
64
|
+
public async createSummary(
|
|
65
|
+
summary: IWholeSummaryPayload,
|
|
66
|
+
): Promise<IR11sResponse<IWriteSummaryResponse>> {
|
|
138
67
|
return this.runWithRetry(
|
|
139
68
|
async () => this.internalGitManager.createSummary(summary),
|
|
140
69
|
"gitManager_createSummary",
|
|
141
70
|
);
|
|
142
71
|
}
|
|
143
72
|
|
|
144
|
-
public async
|
|
145
|
-
return this.runWithRetry(
|
|
146
|
-
async () => this.internalGitManager.deleteSummary(softDelete),
|
|
147
|
-
"gitManager_deleteSummary",
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
public async getSummary(sha: string): Promise<IWholeFlatSummary> {
|
|
73
|
+
public async getSummary(sha: string): Promise<IR11sResponse<IWholeFlatSummary>> {
|
|
152
74
|
return this.runWithRetry(
|
|
153
75
|
async () => this.internalGitManager.getSummary(sha),
|
|
154
76
|
"gitManager_getSummary",
|
|
@@ -18,16 +18,14 @@ import {
|
|
|
18
18
|
ISummaryTree,
|
|
19
19
|
IVersion,
|
|
20
20
|
} from "@fluidframework/protocol-definitions";
|
|
21
|
-
import {
|
|
22
|
-
GitManager,
|
|
23
|
-
ISummaryUploadManager,
|
|
24
|
-
SummaryTreeUploadManager,
|
|
25
|
-
} from "@fluidframework/server-services-client";
|
|
26
21
|
import { PerformanceEvent } from "@fluidframework/telemetry-utils";
|
|
27
22
|
import { IRouterliciousDriverPolicies } from "./policies";
|
|
28
23
|
import { ICache, InMemoryCache } from "./cache";
|
|
29
24
|
import { RetriableGitManager } from "./retriableGitManager";
|
|
30
25
|
import { ISnapshotTreeVersion } from "./definitions";
|
|
26
|
+
import { GitManager } from "./gitManager";
|
|
27
|
+
import { ISummaryUploadManager } from "./storageContracts";
|
|
28
|
+
import { SummaryTreeUploadManager } from "./summaryTreeUploadManager";
|
|
31
29
|
|
|
32
30
|
const isNode = typeof window === "undefined";
|
|
33
31
|
|
|
@@ -85,7 +83,7 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
|
|
|
85
83
|
},
|
|
86
84
|
async () => {
|
|
87
85
|
const manager = await this.getStorageManager();
|
|
88
|
-
return manager.getCommits(id, count);
|
|
86
|
+
return (await manager.getCommits(id, count)).content;
|
|
89
87
|
},
|
|
90
88
|
);
|
|
91
89
|
return commits.map((commit) => ({
|
|
@@ -121,7 +119,7 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
|
|
|
121
119
|
},
|
|
122
120
|
async (event) => {
|
|
123
121
|
const manager = await this.getStorageManager();
|
|
124
|
-
const response = await manager.getTree(requestVersion!.treeId);
|
|
122
|
+
const response = (await manager.getTree(requestVersion!.treeId)).content;
|
|
125
123
|
event.end({
|
|
126
124
|
size: response.tree.length,
|
|
127
125
|
});
|
|
@@ -150,7 +148,7 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
|
|
|
150
148
|
},
|
|
151
149
|
async (event) => {
|
|
152
150
|
const manager = await this.getStorageManager();
|
|
153
|
-
const response = await manager.getBlob(blobId);
|
|
151
|
+
const response = (await manager.getBlob(blobId)).content;
|
|
154
152
|
event.end({
|
|
155
153
|
size: response.size,
|
|
156
154
|
});
|
|
@@ -203,7 +201,7 @@ export class ShreddedSummaryDocumentStorageService implements IDocumentStorageSe
|
|
|
203
201
|
const manager = await this.getStorageManager();
|
|
204
202
|
const response = await manager
|
|
205
203
|
.createBlob(Uint8ArrayToString(uint8ArrayFile, "base64"), "base64")
|
|
206
|
-
.then((r) => ({ id: r.sha, url: r.url }));
|
|
204
|
+
.then((r) => ({ id: r.content.sha, url: r.content.url }));
|
|
207
205
|
event.end({
|
|
208
206
|
blobId: response.id,
|
|
209
207
|
});
|