-
Notifications
You must be signed in to change notification settings - Fork 532
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
295 additions
and
324 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { File as TutanotaFile } from "../../entities/tutanota/TypeRefs.js" | ||
import { elementIdPart, listIdPart } from "./EntityUtils.js" | ||
import { Blob } from "../../entities/sys/TypeRefs.js" | ||
import { SomeEntity } from "../EntityTypes.js" | ||
|
||
/** | ||
* Common interface for instances that are referencing blobs. Main purpose is to have a proper way to access the attribute for the Blob aggregated type | ||
* because the name of the attribute can be different for each instance. | ||
* | ||
*/ | ||
export type BlobReferencingInstance = { | ||
elementId: Id | ||
|
||
listId: Id | null | ||
|
||
blobs: Blob[] | ||
|
||
entity: SomeEntity | ||
} | ||
|
||
export function createReferencingInstance(tutanotaFile: TutanotaFile): BlobReferencingInstance { | ||
return { | ||
blobs: tutanotaFile.blobs, | ||
elementId: elementIdPart(tutanotaFile._id), | ||
listId: listIdPart(tutanotaFile._id), | ||
entity: tutanotaFile, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
93 changes: 93 additions & 0 deletions
93
src/common/api/worker/facades/lazy/MailExportTokenFacade.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { AccessExpiredError } from "../../../common/error/RestError.js" | ||
import { MailExportTokenService } from "../../../entities/tutanota/Services.js" | ||
import { IServiceExecutor } from "../../../common/ServiceRequest.js" | ||
|
||
const TAG = "[MailExportTokenFacade]" | ||
|
||
/** | ||
* Denotes an export token. This is internally just a string, but we want the TypeScript compiler to enforce strong | ||
* typing. | ||
*/ | ||
type MailExportToken = string & { _exportToken: undefined } | ||
|
||
/** | ||
* Takes care of requested and invalidating export tokens as needed. | ||
* | ||
* Export token should be passed with network requests to avoid server penalties. | ||
*/ | ||
export class MailExportTokenFacade { | ||
// This will only be set if a request is in progress | ||
private currentExportTokenRequest: Promise<MailExportToken> | null = null | ||
// Set when we have a known valid token | ||
private currentExportToken: MailExportToken | null = null | ||
|
||
constructor(private readonly serviceExecutor: IServiceExecutor) {} | ||
|
||
/** | ||
* Runs {@param request}. | ||
* | ||
* If {@link AccessExpiredError} is thrown, deletes the cached token and re-runs it again. | ||
*/ | ||
async loadWithToken<T>(request: (token: string) => Promise<T>): Promise<T> { | ||
const token = this.currentExportToken ?? (await this.requestNewToken()) | ||
try { | ||
return await request(token) | ||
} catch (e) { | ||
// We only allow one retry | ||
if (e instanceof AccessExpiredError) { | ||
let newToken | ||
if (this.currentExportToken === token) { | ||
console.log(TAG, `token expired for exporting and will be renewed`) | ||
newToken = await this.requestNewToken() | ||
} else { | ||
// Already a request going on... wait for that to finish | ||
newToken = this.currentExportToken ?? (await this.requestNewToken()) | ||
} | ||
|
||
return await request(newToken) | ||
} else { | ||
throw e | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Request a new token and write it to {@link currentExportToken}. | ||
* | ||
* This token will be valid for the mail group and current user for a short amount of time, after which you will get | ||
* an {@link AccessExpiredError} when using the token (or {@link NotAuthorizedError} if the user lost access to the group in the | ||
* meantime). | ||
* @throws TooManyRequestsError the user cannot request any more tokens right now | ||
*/ | ||
private requestNewToken(): Promise<MailExportToken> { | ||
if (this.currentExportTokenRequest) { | ||
return this.currentExportTokenRequest | ||
} | ||
|
||
this.currentExportToken = null | ||
this.currentExportTokenRequest = this.serviceExecutor.post(MailExportTokenService, null).then( | ||
(result) => { | ||
this.currentExportToken = result.mailExportToken as MailExportToken | ||
this.currentExportTokenRequest = null | ||
return this.currentExportToken | ||
}, | ||
(error) => { | ||
// Re-initialize in case MailExportTokenService won't fail on a future request | ||
this.currentExportTokenRequest = null | ||
throw error | ||
}, | ||
) | ||
return this.currentExportTokenRequest | ||
} | ||
|
||
// @VisibleForTesting | ||
_setCurrentExportToken(token: string) { | ||
this.currentExportToken = token as MailExportToken | ||
this.currentExportTokenRequest = null | ||
} | ||
|
||
// @VisibleForTesting | ||
_getCurrentExportToken(): string | null { | ||
return this.currentExportToken | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.