@fluidframework/odsp-driver 1.2.7 → 2.0.0-dev.1.3.0.96595
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/.mocharc.js +12 -0
- package/README.md +19 -0
- package/dist/ReadBufferUtils.d.ts.map +1 -1
- package/dist/ReadBufferUtils.js +1 -0
- package/dist/ReadBufferUtils.js.map +1 -1
- package/dist/WriteBufferUtils.d.ts +3 -5
- package/dist/WriteBufferUtils.d.ts.map +1 -1
- package/dist/WriteBufferUtils.js +59 -55
- package/dist/WriteBufferUtils.js.map +1 -1
- package/dist/compactSnapshotParser.d.ts +2 -2
- package/dist/compactSnapshotParser.d.ts.map +1 -1
- package/dist/compactSnapshotParser.js +91 -34
- package/dist/compactSnapshotParser.js.map +1 -1
- package/dist/compactSnapshotWriter.d.ts +1 -2
- package/dist/compactSnapshotWriter.d.ts.map +1 -1
- package/dist/compactSnapshotWriter.js +17 -14
- package/dist/compactSnapshotWriter.js.map +1 -1
- package/dist/contracts.d.ts +1 -18
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/createFile.d.ts +1 -1
- package/dist/createFile.d.ts.map +1 -1
- package/dist/createFile.js +53 -16
- package/dist/createFile.js.map +1 -1
- package/dist/createNewUtils.d.ts.map +1 -1
- package/dist/createNewUtils.js +0 -1
- package/dist/createNewUtils.js.map +1 -1
- package/dist/createOdspCreateContainerRequest.d.ts +4 -3
- package/dist/createOdspCreateContainerRequest.d.ts.map +1 -1
- package/dist/createOdspCreateContainerRequest.js +6 -3
- package/dist/createOdspCreateContainerRequest.js.map +1 -1
- package/dist/epochTracker.d.ts +1 -0
- package/dist/epochTracker.d.ts.map +1 -1
- package/dist/epochTracker.js +24 -5
- package/dist/epochTracker.js.map +1 -1
- package/dist/fetchSnapshot.d.ts +1 -2
- package/dist/fetchSnapshot.d.ts.map +1 -1
- package/dist/fetchSnapshot.js +22 -27
- package/dist/fetchSnapshot.js.map +1 -1
- package/dist/getFileLink.d.ts +3 -6
- package/dist/getFileLink.d.ts.map +1 -1
- package/dist/getFileLink.js +22 -33
- package/dist/getFileLink.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/localOdspDriver/localOdspDocumentStorageManager.d.ts.map +1 -1
- package/dist/localOdspDriver/localOdspDocumentStorageManager.js +1 -2
- package/dist/localOdspDriver/localOdspDocumentStorageManager.js.map +1 -1
- package/dist/odspDeltaStorageService.d.ts +3 -2
- package/dist/odspDeltaStorageService.d.ts.map +1 -1
- package/dist/odspDeltaStorageService.js +9 -12
- package/dist/odspDeltaStorageService.js.map +1 -1
- package/dist/odspDocumentDeltaConnection.d.ts.map +1 -1
- package/dist/odspDocumentDeltaConnection.js +3 -6
- package/dist/odspDocumentDeltaConnection.js.map +1 -1
- package/dist/odspDocumentService.d.ts +1 -0
- package/dist/odspDocumentService.d.ts.map +1 -1
- package/dist/odspDocumentService.js +12 -6
- package/dist/odspDocumentService.js.map +1 -1
- package/dist/odspDocumentServiceFactoryCore.d.ts.map +1 -1
- package/dist/odspDocumentServiceFactoryCore.js +29 -6
- package/dist/odspDocumentServiceFactoryCore.js.map +1 -1
- package/dist/odspDocumentStorageManager.d.ts +4 -4
- package/dist/odspDocumentStorageManager.d.ts.map +1 -1
- package/dist/odspDocumentStorageManager.js +82 -64
- package/dist/odspDocumentStorageManager.js.map +1 -1
- package/dist/odspDocumentStorageServiceBase.d.ts +1 -1
- package/dist/odspDocumentStorageServiceBase.d.ts.map +1 -1
- package/dist/odspDocumentStorageServiceBase.js +4 -2
- package/dist/odspDocumentStorageServiceBase.js.map +1 -1
- package/dist/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
- package/dist/odspDriverUrlResolverForShareLink.js +4 -4
- package/dist/odspDriverUrlResolverForShareLink.js.map +1 -1
- package/dist/odspFluidFileLink.js +1 -1
- package/dist/odspFluidFileLink.js.map +1 -1
- package/dist/odspLocationRedirection.d.ts +14 -0
- package/dist/odspLocationRedirection.d.ts.map +1 -0
- package/dist/odspLocationRedirection.js +24 -0
- package/dist/odspLocationRedirection.js.map +1 -0
- package/dist/odspSnapshotParser.d.ts.map +1 -1
- package/dist/odspSnapshotParser.js +1 -2
- package/dist/odspSnapshotParser.js.map +1 -1
- package/dist/odspSummaryUploadManager.d.ts +6 -3
- package/dist/odspSummaryUploadManager.d.ts.map +1 -1
- package/dist/odspSummaryUploadManager.js +14 -17
- package/dist/odspSummaryUploadManager.js.map +1 -1
- package/dist/odspUrlHelper.js +2 -1
- package/dist/odspUrlHelper.js.map +1 -1
- package/dist/odspUtils.d.ts +11 -2
- package/dist/odspUtils.d.ts.map +1 -1
- package/dist/odspUtils.js +32 -5
- package/dist/odspUtils.js.map +1 -1
- package/dist/opsCaching.d.ts.map +1 -1
- package/dist/opsCaching.js +3 -2
- package/dist/opsCaching.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/prefetchLatestSnapshot.d.ts +6 -4
- package/dist/prefetchLatestSnapshot.d.ts.map +1 -1
- package/dist/prefetchLatestSnapshot.js +6 -4
- package/dist/prefetchLatestSnapshot.js.map +1 -1
- package/dist/retryUtils.d.ts.map +1 -1
- package/dist/retryUtils.js +8 -4
- package/dist/retryUtils.js.map +1 -1
- package/dist/zipItDataRepresentationUtils.d.ts +30 -18
- package/dist/zipItDataRepresentationUtils.d.ts.map +1 -1
- package/dist/zipItDataRepresentationUtils.js +170 -76
- package/dist/zipItDataRepresentationUtils.js.map +1 -1
- package/lib/ReadBufferUtils.d.ts.map +1 -1
- package/lib/ReadBufferUtils.js +1 -0
- package/lib/ReadBufferUtils.js.map +1 -1
- package/lib/WriteBufferUtils.d.ts +3 -5
- package/lib/WriteBufferUtils.d.ts.map +1 -1
- package/lib/WriteBufferUtils.js +61 -57
- package/lib/WriteBufferUtils.js.map +1 -1
- package/lib/compactSnapshotParser.d.ts +2 -2
- package/lib/compactSnapshotParser.d.ts.map +1 -1
- package/lib/compactSnapshotParser.js +92 -35
- package/lib/compactSnapshotParser.js.map +1 -1
- package/lib/compactSnapshotWriter.d.ts +1 -2
- package/lib/compactSnapshotWriter.d.ts.map +1 -1
- package/lib/compactSnapshotWriter.js +18 -15
- package/lib/compactSnapshotWriter.js.map +1 -1
- package/lib/contracts.d.ts +1 -18
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/createFile.d.ts +1 -1
- package/lib/createFile.d.ts.map +1 -1
- package/lib/createFile.js +54 -17
- package/lib/createFile.js.map +1 -1
- package/lib/createNewUtils.d.ts.map +1 -1
- package/lib/createNewUtils.js +0 -1
- package/lib/createNewUtils.js.map +1 -1
- package/lib/createOdspCreateContainerRequest.d.ts +4 -3
- package/lib/createOdspCreateContainerRequest.d.ts.map +1 -1
- package/lib/createOdspCreateContainerRequest.js +6 -3
- package/lib/createOdspCreateContainerRequest.js.map +1 -1
- package/lib/epochTracker.d.ts +1 -0
- package/lib/epochTracker.d.ts.map +1 -1
- package/lib/epochTracker.js +26 -7
- package/lib/epochTracker.js.map +1 -1
- package/lib/fetchSnapshot.d.ts +1 -2
- package/lib/fetchSnapshot.d.ts.map +1 -1
- package/lib/fetchSnapshot.js +22 -27
- package/lib/fetchSnapshot.js.map +1 -1
- package/lib/getFileLink.d.ts +3 -6
- package/lib/getFileLink.d.ts.map +1 -1
- package/lib/getFileLink.js +24 -35
- package/lib/getFileLink.js.map +1 -1
- package/lib/index.d.ts +1 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -3
- package/lib/index.js.map +1 -1
- package/lib/localOdspDriver/localOdspDocumentStorageManager.d.ts.map +1 -1
- package/lib/localOdspDriver/localOdspDocumentStorageManager.js +1 -2
- package/lib/localOdspDriver/localOdspDocumentStorageManager.js.map +1 -1
- package/lib/odspDeltaStorageService.d.ts +3 -2
- package/lib/odspDeltaStorageService.d.ts.map +1 -1
- package/lib/odspDeltaStorageService.js +9 -12
- package/lib/odspDeltaStorageService.js.map +1 -1
- package/lib/odspDocumentDeltaConnection.d.ts.map +1 -1
- package/lib/odspDocumentDeltaConnection.js +3 -6
- package/lib/odspDocumentDeltaConnection.js.map +1 -1
- package/lib/odspDocumentService.d.ts +1 -0
- package/lib/odspDocumentService.d.ts.map +1 -1
- package/lib/odspDocumentService.js +14 -8
- package/lib/odspDocumentService.js.map +1 -1
- package/lib/odspDocumentServiceFactoryCore.d.ts.map +1 -1
- package/lib/odspDocumentServiceFactoryCore.js +29 -6
- package/lib/odspDocumentServiceFactoryCore.js.map +1 -1
- package/lib/odspDocumentStorageManager.d.ts +4 -4
- package/lib/odspDocumentStorageManager.d.ts.map +1 -1
- package/lib/odspDocumentStorageManager.js +83 -65
- package/lib/odspDocumentStorageManager.js.map +1 -1
- package/lib/odspDocumentStorageServiceBase.d.ts +1 -1
- package/lib/odspDocumentStorageServiceBase.d.ts.map +1 -1
- package/lib/odspDocumentStorageServiceBase.js +4 -2
- package/lib/odspDocumentStorageServiceBase.js.map +1 -1
- package/lib/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
- package/lib/odspDriverUrlResolverForShareLink.js +4 -4
- package/lib/odspDriverUrlResolverForShareLink.js.map +1 -1
- package/lib/odspFluidFileLink.js +1 -1
- package/lib/odspFluidFileLink.js.map +1 -1
- package/lib/odspLocationRedirection.d.ts +14 -0
- package/lib/odspLocationRedirection.d.ts.map +1 -0
- package/lib/odspLocationRedirection.js +20 -0
- package/lib/odspLocationRedirection.js.map +1 -0
- package/lib/odspSnapshotParser.d.ts.map +1 -1
- package/lib/odspSnapshotParser.js +1 -2
- package/lib/odspSnapshotParser.js.map +1 -1
- package/lib/odspSummaryUploadManager.d.ts +6 -3
- package/lib/odspSummaryUploadManager.d.ts.map +1 -1
- package/lib/odspSummaryUploadManager.js +14 -17
- package/lib/odspSummaryUploadManager.js.map +1 -1
- package/lib/odspUrlHelper.js +2 -1
- package/lib/odspUrlHelper.js.map +1 -1
- package/lib/odspUtils.d.ts +11 -2
- package/lib/odspUtils.d.ts.map +1 -1
- package/lib/odspUtils.js +31 -5
- package/lib/odspUtils.js.map +1 -1
- package/lib/opsCaching.d.ts.map +1 -1
- package/lib/opsCaching.js +3 -2
- package/lib/opsCaching.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/prefetchLatestSnapshot.d.ts +6 -4
- package/lib/prefetchLatestSnapshot.d.ts.map +1 -1
- package/lib/prefetchLatestSnapshot.js +6 -4
- package/lib/prefetchLatestSnapshot.js.map +1 -1
- package/lib/retryUtils.d.ts.map +1 -1
- package/lib/retryUtils.js +9 -5
- package/lib/retryUtils.js.map +1 -1
- package/lib/zipItDataRepresentationUtils.d.ts +30 -18
- package/lib/zipItDataRepresentationUtils.d.ts.map +1 -1
- package/lib/zipItDataRepresentationUtils.js +166 -75
- package/lib/zipItDataRepresentationUtils.js.map +1 -1
- package/package.json +33 -20
- package/src/ReadBufferUtils.ts +1 -0
- package/src/WriteBufferUtils.ts +67 -58
- package/src/compactSnapshotParser.ts +102 -40
- package/src/compactSnapshotWriter.ts +25 -17
- package/src/contracts.ts +2 -14
- package/src/createFile.ts +75 -15
- package/src/createNewUtils.ts +2 -4
- package/src/createOdspCreateContainerRequest.ts +7 -4
- package/src/epochTracker.ts +47 -7
- package/src/fetchSnapshot.ts +35 -31
- package/src/getFileLink.ts +26 -39
- package/src/index.ts +1 -3
- package/src/localOdspDriver/localOdspDocumentStorageManager.ts +2 -2
- package/src/odspDeltaStorageService.ts +8 -9
- package/src/odspDocumentDeltaConnection.ts +3 -5
- package/src/odspDocumentService.ts +16 -13
- package/src/odspDocumentServiceFactoryCore.ts +40 -4
- package/src/odspDocumentStorageManager.ts +64 -50
- package/src/odspDocumentStorageServiceBase.ts +4 -2
- package/src/odspDriverUrlResolverForShareLink.ts +2 -5
- package/src/odspFluidFileLink.ts +1 -1
- package/src/odspLocationRedirection.ts +23 -0
- package/src/odspSnapshotParser.ts +3 -4
- package/src/odspSummaryUploadManager.ts +10 -11
- package/src/odspUrlHelper.ts +1 -1
- package/src/odspUtils.ts +40 -7
- package/src/opsCaching.ts +3 -2
- package/src/packageVersion.ts +1 -1
- package/src/prefetchLatestSnapshot.ts +6 -4
- package/src/retryUtils.ts +8 -5
- package/src/zipItDataRepresentationUtils.ts +198 -75
package/src/createFile.ts
CHANGED
|
@@ -15,6 +15,9 @@ import {
|
|
|
15
15
|
InstrumentedStorageTokenFetcher,
|
|
16
16
|
IOdspResolvedUrl,
|
|
17
17
|
OdspErrorType,
|
|
18
|
+
ShareLinkInfoType,
|
|
19
|
+
ISharingLinkKind,
|
|
20
|
+
ShareLinkTypes,
|
|
18
21
|
} from "@fluidframework/odsp-driver-definitions";
|
|
19
22
|
import { DriverErrorType } from "@fluidframework/driver-definitions";
|
|
20
23
|
import {
|
|
@@ -26,6 +29,7 @@ import {
|
|
|
26
29
|
} from "./contracts";
|
|
27
30
|
import { getUrlAndHeadersWithAuth } from "./getUrlAndHeadersWithAuth";
|
|
28
31
|
import {
|
|
32
|
+
buildOdspShareLinkReqParams,
|
|
29
33
|
createCacheSnapshotKey,
|
|
30
34
|
getWithRetryForTokenRefresh,
|
|
31
35
|
INewFileInfo,
|
|
@@ -61,6 +65,8 @@ export async function createNewFluidFile(
|
|
|
61
65
|
createNewCaching: boolean,
|
|
62
66
|
forceAccessTokenViaAuthorizationHeader: boolean,
|
|
63
67
|
isClpCompliantApp?: boolean,
|
|
68
|
+
enableSingleRequestForShareLinkWithCreate?: boolean,
|
|
69
|
+
enableShareLinkWithCreate?: boolean,
|
|
64
70
|
): Promise<IOdspResolvedUrl> {
|
|
65
71
|
// Check for valid filename before the request to create file is actually made.
|
|
66
72
|
if (isInvalidFileName(newFileInfo.filename)) {
|
|
@@ -71,8 +77,7 @@ export async function createNewFluidFile(
|
|
|
71
77
|
|
|
72
78
|
let itemId: string;
|
|
73
79
|
let summaryHandle: string = "";
|
|
74
|
-
let
|
|
75
|
-
let sharingLinkErrorReason: string | undefined;
|
|
80
|
+
let shareLinkInfo: ShareLinkInfoType | undefined;
|
|
76
81
|
if (createNewSummary === undefined) {
|
|
77
82
|
itemId = await createNewEmptyFluidFile(
|
|
78
83
|
getStorageToken, newFileInfo, logger, epochTracker, forceAccessTokenViaAuthorizationHeader);
|
|
@@ -87,8 +92,12 @@ export async function createNewFluidFile(
|
|
|
87
92
|
);
|
|
88
93
|
itemId = content.itemId;
|
|
89
94
|
summaryHandle = content.id;
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
|
|
96
|
+
shareLinkInfo = extractShareLinkData(
|
|
97
|
+
newFileInfo.createLinkType,
|
|
98
|
+
content,
|
|
99
|
+
enableSingleRequestForShareLinkWithCreate,
|
|
100
|
+
enableShareLinkWithCreate);
|
|
92
101
|
}
|
|
93
102
|
|
|
94
103
|
const odspUrl = createOdspUrl({ ...newFileInfo, itemId, dataStorePath: "/" });
|
|
@@ -100,15 +109,7 @@ export async function createNewFluidFile(
|
|
|
100
109
|
fileEntry.docId = odspResolvedUrl.hashedDocumentId;
|
|
101
110
|
fileEntry.resolvedUrl = odspResolvedUrl;
|
|
102
111
|
|
|
103
|
-
|
|
104
|
-
odspResolvedUrl.shareLinkInfo = {
|
|
105
|
-
createLink: {
|
|
106
|
-
type: newFileInfo.createLinkType,
|
|
107
|
-
link: sharingLink,
|
|
108
|
-
error: sharingLinkErrorReason,
|
|
109
|
-
},
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
+
odspResolvedUrl.shareLinkInfo = shareLinkInfo;
|
|
112
113
|
|
|
113
114
|
if (createNewSummary !== undefined && createNewCaching) {
|
|
114
115
|
assert(summaryHandle !== undefined, 0x203 /* "Summary handle is undefined" */);
|
|
@@ -120,6 +121,61 @@ export async function createNewFluidFile(
|
|
|
120
121
|
return odspResolvedUrl;
|
|
121
122
|
}
|
|
122
123
|
|
|
124
|
+
/**
|
|
125
|
+
* If user requested creation of a sharing link along with the creation of the file by providing either
|
|
126
|
+
* createLinkType (now deprecated) or createLinkScope in the request parameters, extract and save
|
|
127
|
+
* sharing link information from the response if it is available.
|
|
128
|
+
* In case there was an error in creation of the sharing link, error is provided back in the response,
|
|
129
|
+
* and does not impact the creation of file in ODSP.
|
|
130
|
+
* @param requestedSharingLinkKind - Kind of sharing link requested to be created along with the creation of file.
|
|
131
|
+
* @param response - Response object received from the /snapshot api call
|
|
132
|
+
* @returns Sharing link information received in the response from a successful creation of a file.
|
|
133
|
+
*/
|
|
134
|
+
function extractShareLinkData(
|
|
135
|
+
requestedSharingLinkKind: ShareLinkTypes | ISharingLinkKind | undefined,
|
|
136
|
+
response: ICreateFileResponse,
|
|
137
|
+
enableSingleRequestForShareLinkWithCreate?: boolean,
|
|
138
|
+
enableShareLinkWithCreate?: boolean,
|
|
139
|
+
): ShareLinkInfoType | undefined {
|
|
140
|
+
if (!requestedSharingLinkKind) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
let shareLinkInfo: ShareLinkInfoType | undefined;
|
|
144
|
+
if (enableSingleRequestForShareLinkWithCreate) {
|
|
145
|
+
const { sharing } = response;
|
|
146
|
+
if (!sharing) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
shareLinkInfo = {
|
|
150
|
+
createLink: {
|
|
151
|
+
type: requestedSharingLinkKind,
|
|
152
|
+
link: sharing.sharingLink ? {
|
|
153
|
+
scope: sharing.sharingLink.scope,
|
|
154
|
+
role: sharing.sharingLink.type,
|
|
155
|
+
webUrl: sharing.sharingLink.webUrl,
|
|
156
|
+
...sharing.sharingLink,
|
|
157
|
+
} : undefined,
|
|
158
|
+
error: sharing.error,
|
|
159
|
+
shareId: sharing.shareId,
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
} else if (enableShareLinkWithCreate) {
|
|
163
|
+
const { sharing, sharingLink, sharingLinkErrorReason } = response;
|
|
164
|
+
if (!sharingLink && !sharingLinkErrorReason) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
shareLinkInfo = {
|
|
168
|
+
createLink: {
|
|
169
|
+
type: requestedSharingLinkKind,
|
|
170
|
+
link: sharingLink,
|
|
171
|
+
error: sharingLinkErrorReason,
|
|
172
|
+
shareId: sharing?.shareId,
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
return shareLinkInfo;
|
|
177
|
+
}
|
|
178
|
+
|
|
123
179
|
export async function createNewEmptyFluidFile(
|
|
124
180
|
getStorageToken: InstrumentedStorageTokenFetcher,
|
|
125
181
|
newFileInfo: INewFileInfo,
|
|
@@ -192,8 +248,12 @@ export async function createNewFluidFileFromSummary(
|
|
|
192
248
|
`${filePath}/${encodedFilename}`;
|
|
193
249
|
|
|
194
250
|
const containerSnapshot = convertSummaryIntoContainerSnapshot(createNewSummary);
|
|
195
|
-
|
|
196
|
-
|
|
251
|
+
|
|
252
|
+
// Build share link parameter based on the createLinkType provided so that the
|
|
253
|
+
// snapshot api can create and return the share link along with creation of file in the response.
|
|
254
|
+
const createShareLinkParam = buildOdspShareLinkReqParams(newFileInfo.createLinkType);
|
|
255
|
+
const initialUrl =
|
|
256
|
+
`${baseUrl}:/opStream/snapshots/snapshot${createShareLinkParam ? `?${createShareLinkParam}` : ""}`;
|
|
197
257
|
|
|
198
258
|
return getWithRetryForTokenRefresh(async (options) => {
|
|
199
259
|
const storageToken = await getStorageToken(options, "CreateNewFile");
|
package/src/createNewUtils.ts
CHANGED
|
@@ -4,11 +4,10 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { v4 as uuid } from "uuid";
|
|
7
|
-
import { ISummaryTree, SummaryType } from "@fluidframework/protocol-definitions";
|
|
7
|
+
import { ISummaryTree, SummaryType, ISnapshotTree } from "@fluidframework/protocol-definitions";
|
|
8
8
|
import { getDocAttributesFromProtocolSummary } from "@fluidframework/driver-utils";
|
|
9
9
|
import { stringToBuffer, unreachableCase } from "@fluidframework/common-utils";
|
|
10
10
|
import { ISnapshotContents } from "./odspPublicUtils";
|
|
11
|
-
import { ISnapshotTreeEx } from "./contracts";
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
13
|
* Converts a summary(ISummaryTree) taken in detached container to snapshot tree and blobs
|
|
@@ -35,10 +34,9 @@ function convertCreateNewSummaryTreeToTreeAndBlobsCore(
|
|
|
35
34
|
summary: ISummaryTree,
|
|
36
35
|
blobs: Map<string, ArrayBuffer>,
|
|
37
36
|
) {
|
|
38
|
-
const treeNode:
|
|
37
|
+
const treeNode: ISnapshotTree = {
|
|
39
38
|
blobs: {},
|
|
40
39
|
trees: {},
|
|
41
|
-
commits: {},
|
|
42
40
|
unreferenced: summary.unreferenced,
|
|
43
41
|
};
|
|
44
42
|
const keys = Object.keys(summary.tree);
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { IRequest } from "@fluidframework/core-interfaces";
|
|
6
6
|
import { DriverHeader } from "@fluidframework/driver-definitions";
|
|
7
|
-
import { ShareLinkTypes } from "@fluidframework/odsp-driver-definitions";
|
|
7
|
+
import { ShareLinkTypes, ISharingLinkKind } from "@fluidframework/odsp-driver-definitions";
|
|
8
|
+
import { buildOdspShareLinkReqParams } from "./odspUtils";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Create the request object with url and headers for creating a new file on OneDrive Sharepoint
|
|
@@ -12,19 +13,21 @@ import { ShareLinkTypes } from "@fluidframework/odsp-driver-definitions";
|
|
|
12
13
|
* @param driveId - drive identifier
|
|
13
14
|
* @param filePath - path where file needs to be created
|
|
14
15
|
* @param fileName - name of the new file to be created
|
|
15
|
-
* @param
|
|
16
|
+
* @param createShareLinkType - type of sharing link you would like to create for this file. ShareLinkTypes
|
|
17
|
+
* will be deprecated soon, so for any new implementation please provide createShareLinkType of type ShareLink
|
|
16
18
|
*/
|
|
17
19
|
export function createOdspCreateContainerRequest(
|
|
18
20
|
siteUrl: string,
|
|
19
21
|
driveId: string,
|
|
20
22
|
filePath: string,
|
|
21
23
|
fileName: string,
|
|
22
|
-
|
|
24
|
+
createShareLinkType?: ShareLinkTypes | ISharingLinkKind,
|
|
23
25
|
): IRequest {
|
|
26
|
+
const shareLinkRequestParams = buildOdspShareLinkReqParams(createShareLinkType);
|
|
24
27
|
const createNewRequest: IRequest = {
|
|
25
28
|
url: `${siteUrl}?driveId=${encodeURIComponent(
|
|
26
29
|
driveId,
|
|
27
|
-
)}&path=${encodeURIComponent(filePath)}${
|
|
30
|
+
)}&path=${encodeURIComponent(filePath)}${shareLinkRequestParams ? `&${shareLinkRequestParams}` : ""}`,
|
|
28
31
|
headers: {
|
|
29
32
|
[DriverHeader.createNew]: {
|
|
30
33
|
fileName,
|
package/src/epochTracker.ts
CHANGED
|
@@ -6,7 +6,12 @@
|
|
|
6
6
|
import { v4 as uuid } from "uuid";
|
|
7
7
|
import { assert, Deferred } from "@fluidframework/common-utils";
|
|
8
8
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
ThrottlingError,
|
|
11
|
+
RateLimiter,
|
|
12
|
+
NonRetryableError,
|
|
13
|
+
LocationRedirectionError,
|
|
14
|
+
} from "@fluidframework/driver-utils";
|
|
10
15
|
import { IConnected } from "@fluidframework/protocol-definitions";
|
|
11
16
|
import {
|
|
12
17
|
snapshotKey,
|
|
@@ -15,9 +20,16 @@ import {
|
|
|
15
20
|
IFileEntry,
|
|
16
21
|
IPersistedCache,
|
|
17
22
|
IOdspError,
|
|
23
|
+
IOdspErrorAugmentations,
|
|
24
|
+
IOdspResolvedUrl,
|
|
18
25
|
} from "@fluidframework/odsp-driver-definitions";
|
|
19
26
|
import { DriverErrorType } from "@fluidframework/driver-definitions";
|
|
20
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
PerformanceEvent,
|
|
29
|
+
isFluidError,
|
|
30
|
+
normalizeError,
|
|
31
|
+
loggerToMonitoringContext,
|
|
32
|
+
} from "@fluidframework/telemetry-utils";
|
|
21
33
|
import { fetchAndParseAsJSONHelper, fetchArray, fetchHelper, getOdspResolvedUrl, IOdspResponse } from "./odspUtils";
|
|
22
34
|
import {
|
|
23
35
|
IOdspCache,
|
|
@@ -27,6 +39,7 @@ import {
|
|
|
27
39
|
import { IVersionedValueWithEpoch, persistedCacheValueVersion } from "./contracts";
|
|
28
40
|
import { ClpCompliantAppHeader } from "./contractsPublic";
|
|
29
41
|
import { pkgVersion as driverVersion } from "./packageVersion";
|
|
42
|
+
import { patchOdspResolvedUrl } from "./odspLocationRedirection";
|
|
30
43
|
|
|
31
44
|
export type FetchType = "blob" | "createBlob" | "createFile" | "joinSession" | "ops" | "test" | "snapshotTree" |
|
|
32
45
|
"treesLatest" | "uploadSummary" | "push" | "versions";
|
|
@@ -47,6 +60,7 @@ export const defaultCacheExpiryTimeoutMs: number = 2 * 24 * 60 * 60 * 1000;
|
|
|
47
60
|
export class EpochTracker implements IPersistedFileCache {
|
|
48
61
|
private _fluidEpoch: string | undefined;
|
|
49
62
|
|
|
63
|
+
private readonly snapshotCacheExpiryTimeoutMs: number;
|
|
50
64
|
public readonly rateLimiter: RateLimiter;
|
|
51
65
|
private readonly driverId = uuid();
|
|
52
66
|
// This tracks the request number made by the driver instance.
|
|
@@ -59,6 +73,12 @@ export class EpochTracker implements IPersistedFileCache {
|
|
|
59
73
|
) {
|
|
60
74
|
// Limits the max number of concurrent requests to 24.
|
|
61
75
|
this.rateLimiter = new RateLimiter(24);
|
|
76
|
+
|
|
77
|
+
// We need this for GC testing until we properly plumb through the snapshot expiration policy (see PR #11168)
|
|
78
|
+
this.snapshotCacheExpiryTimeoutMs =
|
|
79
|
+
loggerToMonitoringContext(logger).config.getBoolean("Fluid.Driver.Odsp.TestOverride.DisableSnapshotCache")
|
|
80
|
+
? 0
|
|
81
|
+
: defaultCacheExpiryTimeoutMs;
|
|
62
82
|
}
|
|
63
83
|
|
|
64
84
|
// public for UT purposes only!
|
|
@@ -95,17 +115,17 @@ export class EpochTracker implements IPersistedFileCache {
|
|
|
95
115
|
} else if (this._fluidEpoch !== value.fluidEpoch) {
|
|
96
116
|
return undefined;
|
|
97
117
|
}
|
|
98
|
-
// Expire the cached snapshot if it's older than
|
|
118
|
+
// Expire the cached snapshot if it's older than snapshotCacheExpiryTimeoutMs and immediately
|
|
99
119
|
// expire all old caches that do not have cacheEntryTime
|
|
100
120
|
if (entry.type === snapshotKey) {
|
|
101
121
|
const cacheTime = value.value?.cacheEntryTime;
|
|
102
122
|
const currentTime = Date.now();
|
|
103
|
-
if (cacheTime === undefined || currentTime - cacheTime >=
|
|
123
|
+
if (cacheTime === undefined || currentTime - cacheTime >= this.snapshotCacheExpiryTimeoutMs) {
|
|
104
124
|
this.logger.sendTelemetryEvent(
|
|
105
125
|
{
|
|
106
126
|
eventName: "odspVersionsCacheExpired",
|
|
107
127
|
duration: currentTime - cacheTime,
|
|
108
|
-
maxCacheAgeMs:
|
|
128
|
+
maxCacheAgeMs: this.snapshotCacheExpiryTimeoutMs,
|
|
109
129
|
});
|
|
110
130
|
await this.removeEntries();
|
|
111
131
|
return undefined;
|
|
@@ -121,8 +141,8 @@ export class EpochTracker implements IPersistedFileCache {
|
|
|
121
141
|
|
|
122
142
|
public async put(entry: IEntry, value: any) {
|
|
123
143
|
assert(this._fluidEpoch !== undefined, 0x1dd /* "no epoch" */);
|
|
124
|
-
// For snapshots, the value should have the cacheEntryTime.
|
|
125
|
-
// than
|
|
144
|
+
// For snapshots, the value should have the cacheEntryTime.
|
|
145
|
+
// This will be used to expire snapshots older than snapshotCacheExpiryTimeoutMs.
|
|
126
146
|
if (entry.type === snapshotKey) {
|
|
127
147
|
value.cacheEntryTime = value.cacheEntryTime ?? Date.now();
|
|
128
148
|
}
|
|
@@ -224,6 +244,26 @@ export class EpochTracker implements IPersistedFileCache {
|
|
|
224
244
|
}
|
|
225
245
|
await this.checkForEpochError(error, epochFromResponse, fetchType);
|
|
226
246
|
throw error;
|
|
247
|
+
}).catch((error) => {
|
|
248
|
+
// If the error is about location redirection, then we need to generate new resolved url with correct
|
|
249
|
+
// location info.
|
|
250
|
+
if (isFluidError(error) && error.errorType === DriverErrorType.fileNotFoundOrAccessDeniedError) {
|
|
251
|
+
const redirectLocation = (error as IOdspErrorAugmentations).redirectLocation;
|
|
252
|
+
if (redirectLocation !== undefined) {
|
|
253
|
+
const redirectUrl: IOdspResolvedUrl = patchOdspResolvedUrl(
|
|
254
|
+
this.fileEntry.resolvedUrl,
|
|
255
|
+
redirectLocation,
|
|
256
|
+
);
|
|
257
|
+
const locationRedirectionError = new LocationRedirectionError(
|
|
258
|
+
error.message,
|
|
259
|
+
redirectUrl,
|
|
260
|
+
{ driverVersion, redirectLocation },
|
|
261
|
+
);
|
|
262
|
+
locationRedirectionError.addTelemetryProperties(error.getTelemetryProperties());
|
|
263
|
+
throw locationRedirectionError;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
throw error;
|
|
227
267
|
}).catch((error) => {
|
|
228
268
|
const fluidError = normalizeError(error, { props: { XRequestStatsHeader: clientCorrelationId } });
|
|
229
269
|
throw fluidError;
|
package/src/fetchSnapshot.ts
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
InstrumentedStorageTokenFetcher,
|
|
17
17
|
} from "@fluidframework/odsp-driver-definitions";
|
|
18
18
|
import { ISnapshotTree } from "@fluidframework/protocol-definitions";
|
|
19
|
-
import { isRuntimeMessage, NonRetryableError } from "@fluidframework/driver-utils";
|
|
19
|
+
import { DriverErrorTelemetryProps, isRuntimeMessage, NonRetryableError } from "@fluidframework/driver-utils";
|
|
20
20
|
import { IOdspSnapshot, ISnapshotCachedEntry, IVersionedValueWithEpoch, persistedCacheValueVersion } from "./contracts";
|
|
21
21
|
import { getQueryString } from "./getQueryString";
|
|
22
22
|
import { getUrlAndHeadersWithAuth } from "./getUrlAndHeadersWithAuth";
|
|
@@ -30,7 +30,6 @@ import {
|
|
|
30
30
|
import { ISnapshotContents } from "./odspPublicUtils";
|
|
31
31
|
import { convertOdspSnapshotToSnapshotTreeAndBlobs } from "./odspSnapshotParser";
|
|
32
32
|
import { currentReadVersion, parseCompactSnapshotResponse } from "./compactSnapshotParser";
|
|
33
|
-
import { ReadBuffer } from "./ReadBufferUtils";
|
|
34
33
|
import { EpochTracker } from "./epochTracker";
|
|
35
34
|
import { pkgVersion } from "./packageVersion";
|
|
36
35
|
|
|
@@ -49,7 +48,6 @@ export enum SnapshotFormatSupportType {
|
|
|
49
48
|
* @param token - token used for authorization in the request
|
|
50
49
|
* @param storageFetchWrapper - Implementation of the get/post methods used to fetch the snapshot
|
|
51
50
|
* @param versionId - id of specific snapshot to be fetched
|
|
52
|
-
* @param fetchFullSnapshot - whether we want to fetch full snapshot(with blobs)
|
|
53
51
|
* @param forceAccessTokenViaAuthorizationHeader - whether to force passing given token via authorization header
|
|
54
52
|
* @returns A promise of the snapshot and the status code of the response
|
|
55
53
|
*/
|
|
@@ -57,22 +55,14 @@ export async function fetchSnapshot(
|
|
|
57
55
|
snapshotUrl: string,
|
|
58
56
|
token: string | null,
|
|
59
57
|
versionId: string,
|
|
60
|
-
fetchFullSnapshot: boolean,
|
|
61
58
|
forceAccessTokenViaAuthorizationHeader: boolean,
|
|
62
59
|
logger: ITelemetryLogger,
|
|
63
60
|
snapshotDownloader: (url: string, fetchOptions: { [index: string]: any; }) => Promise<IOdspResponse<unknown>>,
|
|
64
61
|
): Promise<ISnapshotContents> {
|
|
65
62
|
const path = `/trees/${versionId}`;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (versionId !== "latest") {
|
|
70
|
-
queryParams = { channels: 1, blobs: 2 };
|
|
71
|
-
} else {
|
|
72
|
-
queryParams = { deltas: 1, channels: 1, blobs: 2 };
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
63
|
+
// We just want to fetch tree here. So explicitly set to not fetch blobs and deltas
|
|
64
|
+
// as by default server will send that.
|
|
65
|
+
const queryParams: ISnapshotOptions = { deltas: 0, blobs: 0 };
|
|
76
66
|
const queryString = getQueryString(queryParams);
|
|
77
67
|
const { url, headers } = getUrlAndHeadersWithAuth(
|
|
78
68
|
`${snapshotUrl}${path}${queryString}`, token, forceAccessTokenViaAuthorizationHeader);
|
|
@@ -234,18 +224,28 @@ async function fetchLatestSnapshotCore(
|
|
|
234
224
|
snapshotOptions,
|
|
235
225
|
controller,
|
|
236
226
|
);
|
|
227
|
+
|
|
237
228
|
const odspResponse = response.odspResponse;
|
|
238
229
|
const contentType = odspResponse.headers.get("content-type");
|
|
239
|
-
|
|
230
|
+
|
|
231
|
+
const propsToLog: DriverErrorTelemetryProps = {
|
|
240
232
|
...odspResponse.propsToLog,
|
|
241
233
|
contentType,
|
|
242
234
|
accept: response.requestHeaders.accept,
|
|
235
|
+
driverVersion: pkgVersion,
|
|
243
236
|
};
|
|
237
|
+
|
|
238
|
+
// Measure how much time we spend processing payload
|
|
239
|
+
const snapshotParseEvent = PerformanceEvent.start(logger, {
|
|
240
|
+
eventName: "SnapshotParse",
|
|
241
|
+
...propsToLog,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
244
|
let parsedSnapshotContents: IOdspResponse<ISnapshotContents> | undefined;
|
|
245
245
|
let contentTypeToRead: string | undefined;
|
|
246
|
-
if (contentType?.
|
|
246
|
+
if (contentType?.includes("application/ms-fluid")) {
|
|
247
247
|
contentTypeToRead = "application/ms-fluid";
|
|
248
|
-
} else if (contentType?.
|
|
248
|
+
} else if (contentType?.includes("application/json")) {
|
|
249
249
|
contentTypeToRead = "application/json";
|
|
250
250
|
}
|
|
251
251
|
|
|
@@ -253,7 +253,7 @@ async function fetchLatestSnapshotCore(
|
|
|
253
253
|
switch (contentTypeToRead) {
|
|
254
254
|
case "application/json": {
|
|
255
255
|
const text = await odspResponse.content.text();
|
|
256
|
-
|
|
256
|
+
propsToLog.bodySize = text.length;
|
|
257
257
|
const content: IOdspSnapshot = JSON.parse(text);
|
|
258
258
|
validateBlobsAndTrees(content);
|
|
259
259
|
const snapshotContents: ISnapshotContents =
|
|
@@ -263,15 +263,16 @@ async function fetchLatestSnapshotCore(
|
|
|
263
263
|
}
|
|
264
264
|
case "application/ms-fluid": {
|
|
265
265
|
const content = await odspResponse.content.arrayBuffer();
|
|
266
|
-
|
|
266
|
+
propsToLog.bodySize = content.byteLength;
|
|
267
267
|
const snapshotContents: ISnapshotContents = parseCompactSnapshotResponse(
|
|
268
|
-
new
|
|
268
|
+
new Uint8Array(content),
|
|
269
|
+
logger);
|
|
269
270
|
if (snapshotContents.snapshotTree.trees === undefined ||
|
|
270
271
|
snapshotContents.snapshotTree.blobs === undefined) {
|
|
271
272
|
throw new NonRetryableError(
|
|
272
273
|
"Returned odsp snapshot is malformed. No trees or blobs!",
|
|
273
274
|
DriverErrorType.incorrectServerResponse,
|
|
274
|
-
|
|
275
|
+
propsToLog,
|
|
275
276
|
);
|
|
276
277
|
}
|
|
277
278
|
parsedSnapshotContents = { ...odspResponse, content: snapshotContents };
|
|
@@ -281,12 +282,12 @@ async function fetchLatestSnapshotCore(
|
|
|
281
282
|
throw new NonRetryableError(
|
|
282
283
|
"Unknown snapshot content type",
|
|
283
284
|
DriverErrorType.incorrectServerResponse,
|
|
284
|
-
|
|
285
|
+
propsToLog,
|
|
285
286
|
);
|
|
286
287
|
}
|
|
287
288
|
} catch (error) {
|
|
288
289
|
if (isFluidError(error)) {
|
|
289
|
-
error.addTelemetryProperties(
|
|
290
|
+
error.addTelemetryProperties(propsToLog);
|
|
290
291
|
throw error;
|
|
291
292
|
}
|
|
292
293
|
const enhancedError = wrapError(
|
|
@@ -294,11 +295,14 @@ async function fetchLatestSnapshotCore(
|
|
|
294
295
|
(errorMessage) => new NonRetryableError(
|
|
295
296
|
`Error parsing snapshot response: ${errorMessage}`,
|
|
296
297
|
DriverErrorType.genericError,
|
|
297
|
-
|
|
298
|
+
propsToLog));
|
|
298
299
|
throw enhancedError;
|
|
299
300
|
}
|
|
301
|
+
|
|
300
302
|
assert(parsedSnapshotContents !== undefined, 0x312 /* snapshot should be parsed */);
|
|
301
303
|
const snapshot = parsedSnapshotContents.content;
|
|
304
|
+
const { trees, numBlobs, encodedBlobsSize } = evalBlobsAndTrees(snapshot);
|
|
305
|
+
|
|
302
306
|
// From: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming
|
|
303
307
|
// fetchStart: immediately before the browser starts to fetch the resource.
|
|
304
308
|
// requestStart: immediately before the browser starts requesting the resource from the server
|
|
@@ -351,9 +355,6 @@ async function fetchLatestSnapshotCore(
|
|
|
351
355
|
}
|
|
352
356
|
}
|
|
353
357
|
|
|
354
|
-
const { numTrees, numBlobs, encodedBlobsSize } =
|
|
355
|
-
evalBlobsAndTrees(parsedSnapshotContents.content);
|
|
356
|
-
|
|
357
358
|
// There are some scenarios in ODSP where we cannot cache, trees/latest will explicitly tell us when we
|
|
358
359
|
// cannot cache using an HTTP response header.
|
|
359
360
|
const canCache =
|
|
@@ -382,8 +383,11 @@ async function fetchLatestSnapshotCore(
|
|
|
382
383
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
383
384
|
putInCache(valueWithEpoch);
|
|
384
385
|
}
|
|
386
|
+
|
|
387
|
+
snapshotParseEvent.end();
|
|
388
|
+
|
|
385
389
|
event.end({
|
|
386
|
-
trees
|
|
390
|
+
trees,
|
|
387
391
|
blobs: snapshot.blobs?.size ?? 0,
|
|
388
392
|
leafNodes: numBlobs,
|
|
389
393
|
encodedBlobsSize,
|
|
@@ -413,7 +417,7 @@ async function fetchLatestSnapshotCore(
|
|
|
413
417
|
// Azure Fluid Relay service is the redeem status (S means success), and FRP is a flag to indicate
|
|
414
418
|
// if the permission has changed.
|
|
415
419
|
sltelemetry: odspResponse.headers.get("x-fluid-sltelemetry"),
|
|
416
|
-
...
|
|
420
|
+
...propsToLog,
|
|
417
421
|
});
|
|
418
422
|
return snapshot;
|
|
419
423
|
},
|
|
@@ -473,13 +477,13 @@ function getFormBodyAndHeaders(
|
|
|
473
477
|
}
|
|
474
478
|
|
|
475
479
|
function evalBlobsAndTrees(snapshot: ISnapshotContents) {
|
|
476
|
-
const
|
|
480
|
+
const trees = countTreesInSnapshotTree(snapshot.snapshotTree);
|
|
477
481
|
const numBlobs = snapshot.blobs.size;
|
|
478
482
|
let encodedBlobsSize = 0;
|
|
479
483
|
for (const [_, blobContent] of snapshot.blobs) {
|
|
480
484
|
encodedBlobsSize += blobContent.byteLength;
|
|
481
485
|
}
|
|
482
|
-
return {
|
|
486
|
+
return { trees, numBlobs, encodedBlobsSize };
|
|
483
487
|
}
|
|
484
488
|
|
|
485
489
|
export function validateBlobsAndTrees(snapshot: IOdspSnapshot) {
|
package/src/getFileLink.ts
CHANGED
|
@@ -4,19 +4,15 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
7
|
-
import { assert
|
|
8
|
-
import { canRetryOnError,
|
|
7
|
+
import { assert } from "@fluidframework/common-utils";
|
|
8
|
+
import { canRetryOnError, NonRetryableError } from "@fluidframework/driver-utils";
|
|
9
9
|
import { PerformanceEvent } from "@fluidframework/telemetry-utils";
|
|
10
10
|
import { DriverErrorType } from "@fluidframework/driver-definitions";
|
|
11
|
-
import {
|
|
12
|
-
IOdspUrlParts,
|
|
13
|
-
OdspResourceTokenFetchOptions,
|
|
14
|
-
IdentityType,
|
|
15
|
-
TokenFetcher,
|
|
16
|
-
} from "@fluidframework/odsp-driver-definitions";
|
|
11
|
+
import { IOdspUrlParts, OdspResourceTokenFetchOptions, TokenFetcher } from "@fluidframework/odsp-driver-definitions";
|
|
17
12
|
import { getUrlAndHeadersWithAuth } from "./getUrlAndHeadersWithAuth";
|
|
18
13
|
import { fetchHelper, getWithRetryForTokenRefresh, toInstrumentedOdspTokenFetcher } from "./odspUtils";
|
|
19
14
|
import { pkgVersion as driverVersion } from "./packageVersion";
|
|
15
|
+
import { runWithRetry } from "./retryUtils";
|
|
20
16
|
|
|
21
17
|
// Store cached responses for the lifetime of web session as file link remains the same for given file item
|
|
22
18
|
const fileLinkCache = new Map<string, Promise<string>>();
|
|
@@ -28,17 +24,13 @@ const fileLinkCache = new Map<string, Promise<string>>();
|
|
|
28
24
|
* throttling error. In future, we are thinking of app allowing to pass some cancel token, with which
|
|
29
25
|
* we would be able to stop retrying.
|
|
30
26
|
* @param getToken - used to fetch access tokens needed to execute operation
|
|
31
|
-
* @param
|
|
32
|
-
* @param driveId - drive where file is stored
|
|
33
|
-
* @param itemId - file id
|
|
34
|
-
* @param identityType - type of client account
|
|
27
|
+
* @param odspUrlParts - object describing file storage identity
|
|
35
28
|
* @param logger - used to log results of operation, including any error
|
|
36
29
|
* @returns Promise which resolves to file link url when successful; otherwise, undefined.
|
|
37
30
|
*/
|
|
38
31
|
export async function getFileLink(
|
|
39
32
|
getToken: TokenFetcher<OdspResourceTokenFetchOptions>,
|
|
40
33
|
odspUrlParts: IOdspUrlParts,
|
|
41
|
-
identityType: IdentityType,
|
|
42
34
|
logger: ITelemetryLogger,
|
|
43
35
|
): Promise<string> {
|
|
44
36
|
const cacheKey = `${odspUrlParts.siteUrl}_${odspUrlParts.driveId}_${odspUrlParts.itemId}`;
|
|
@@ -47,33 +39,29 @@ export async function getFileLink(
|
|
|
47
39
|
return maybeFileLinkCacheEntry;
|
|
48
40
|
}
|
|
49
41
|
|
|
50
|
-
const
|
|
51
|
-
let
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
// If the error is throttling error, then wait for the specified time before retrying.
|
|
66
|
-
// If the waitTime is not specified, then we start with retrying immediately to max of 8s.
|
|
67
|
-
retryAfterMs = getRetryDelayFromError(err) ?? Math.min(retryAfterMs * 2, 8000);
|
|
68
|
-
await delay(retryAfterMs);
|
|
42
|
+
const fileLinkGenerator = async function() {
|
|
43
|
+
let fileLinkCore: string;
|
|
44
|
+
try {
|
|
45
|
+
fileLinkCore = await runWithRetry(
|
|
46
|
+
async () => getFileLinkCore(getToken, odspUrlParts, logger),
|
|
47
|
+
"getFileLinkCore",
|
|
48
|
+
logger,
|
|
49
|
+
);
|
|
50
|
+
} catch (err) {
|
|
51
|
+
// runWithRetry throws a non retriable error after it hits the max # of attempts
|
|
52
|
+
// or encounters an unexpected error type
|
|
53
|
+
if (!canRetryOnError(err)) {
|
|
54
|
+
// Delete from the cache to permit retrying later.
|
|
55
|
+
fileLinkCache.delete(cacheKey);
|
|
69
56
|
}
|
|
70
|
-
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
71
59
|
|
|
72
60
|
// We are guaranteed to run the getFileLinkCore at least once with successful result (which must be a string)
|
|
73
|
-
assert(
|
|
74
|
-
return
|
|
61
|
+
assert(fileLinkCore !== undefined, 0x292 /* "Unexpected undefined result from getFileLinkCore" */);
|
|
62
|
+
return fileLinkCore;
|
|
75
63
|
};
|
|
76
|
-
const fileLink =
|
|
64
|
+
const fileLink = fileLinkGenerator();
|
|
77
65
|
fileLinkCache.set(cacheKey, fileLink);
|
|
78
66
|
return fileLink;
|
|
79
67
|
}
|
|
@@ -81,10 +69,9 @@ export async function getFileLink(
|
|
|
81
69
|
async function getFileLinkCore(
|
|
82
70
|
getToken: TokenFetcher<OdspResourceTokenFetchOptions>,
|
|
83
71
|
odspUrlParts: IOdspUrlParts,
|
|
84
|
-
identityType: IdentityType,
|
|
85
72
|
logger: ITelemetryLogger,
|
|
86
73
|
): Promise<string> {
|
|
87
|
-
const fileItem = await getFileItemLite(getToken, odspUrlParts, logger,
|
|
74
|
+
const fileItem = await getFileItemLite(getToken, odspUrlParts, logger, true);
|
|
88
75
|
|
|
89
76
|
// ODSP link requires extra call to return link that is resistant to file being renamed or moved to different folder
|
|
90
77
|
return PerformanceEvent.timedExecAsync(
|
|
@@ -110,7 +97,7 @@ async function getFileLinkCore(
|
|
|
110
97
|
encodeURIComponent(`'${fileItem.webDavUrl}'`)
|
|
111
98
|
}`,
|
|
112
99
|
storageToken,
|
|
113
|
-
|
|
100
|
+
true,
|
|
114
101
|
);
|
|
115
102
|
const requestInit = {
|
|
116
103
|
method: "POST",
|
package/src/index.ts
CHANGED
|
@@ -32,6 +32,4 @@ export * from "./odspDriverUrlResolver";
|
|
|
32
32
|
// It's used by URL resolve code, but also has some public functions
|
|
33
33
|
export * from "./odspFluidFileLink";
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
export * from "./compactSnapshotParser";
|
|
37
|
-
export * from "./ReadBufferUtils";
|
|
35
|
+
export { parseCompactSnapshotResponse } from "./compactSnapshotParser";
|
|
@@ -13,7 +13,6 @@ import { ISnapshotContents } from "../odspPublicUtils";
|
|
|
13
13
|
import { IOdspSnapshot } from "../contracts";
|
|
14
14
|
import { convertOdspSnapshotToSnapshotTreeAndBlobs } from "../odspSnapshotParser";
|
|
15
15
|
import { parseCompactSnapshotResponse } from "../compactSnapshotParser";
|
|
16
|
-
import { ReadBuffer } from "../ReadBufferUtils";
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
18
|
* ODSP document storage service that works on a provided snapshot for all its processing.
|
|
@@ -48,7 +47,8 @@ export class LocalOdspDocumentStorageService extends OdspDocumentStorageServiceB
|
|
|
48
47
|
snapshotContents = convertOdspSnapshotToSnapshotTreeAndBlobs(content);
|
|
49
48
|
} else {
|
|
50
49
|
snapshotContents = parseCompactSnapshotResponse(
|
|
51
|
-
|
|
50
|
+
this.localSnapshot,
|
|
51
|
+
this.logger);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
this.snapshotTreeId = this.initializeFromSnapshot(snapshotContents);
|