feat(files): add in memory upload repository for home server purposes (#583)

This commit is contained in:
Karol Sójko 2023-05-02 13:02:09 +02:00 committed by GitHub
parent 063a3e425d
commit 14ce6dd818
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 1 deletions

View file

@ -43,6 +43,7 @@ import {
import { MarkFilesToBeRemoved } from '../Domain/UseCase/MarkFilesToBeRemoved/MarkFilesToBeRemoved'
import { AccountDeletionRequestedEventHandler } from '../Domain/Handler/AccountDeletionRequestedEventHandler'
import { SharedSubscriptionInvitationCanceledEventHandler } from '../Domain/Handler/SharedSubscriptionInvitationCanceledEventHandler'
import { InMemoryUploadRepository } from '../Infra/InMemory/InMemoryUploadRepository'
export class ContainerConfigLoader {
async load(): Promise<Container> {
@ -51,6 +52,8 @@ export class ContainerConfigLoader {
const container = new Container()
const isConfiguredForHomeServer = env.get('DB_TYPE') === 'sqlite'
const logger = this.createLogger({ env })
container.bind<winston.Logger>(TYPES.Logger).toConstantValue(logger)
@ -155,7 +158,13 @@ export class ContainerConfigLoader {
container.bind<DomainEventFactoryInterface>(TYPES.DomainEventFactory).to(DomainEventFactory)
// repositories
container.bind<UploadRepositoryInterface>(TYPES.UploadRepository).to(RedisUploadRepository)
if (isConfiguredForHomeServer) {
container
.bind<UploadRepositoryInterface>(TYPES.UploadRepository)
.toConstantValue(new InMemoryUploadRepository(container.get(TYPES.Timer)))
} else {
container.bind<UploadRepositoryInterface>(TYPES.UploadRepository).to(RedisUploadRepository)
}
container
.bind<SNSDomainEventPublisher>(TYPES.DomainEventPublisher)

View file

@ -0,0 +1,77 @@
import { TimerInterface } from '@standardnotes/time'
import { UploadRepositoryInterface } from '../../Domain/Upload/UploadRepositoryInterface'
import { UploadChunkResult } from '../../Domain/Upload/UploadChunkResult'
export class InMemoryUploadRepository implements UploadRepositoryInterface {
private readonly UPLOAD_SESSION_PREFIX = 'upload-session'
private readonly UPLOAD_CHUNKS_PREFIX = 'upload-chunks'
private readonly UPLOAD_SESSION_DEFAULT_TTL = 7200
private inMemoryUploadCacheMap: Map<string, string> = new Map()
private inMemoryUploadTTLMap: Map<string, number> = new Map()
constructor(private timer: TimerInterface) {}
async storeUploadSession(filePath: string, uploadId: string): Promise<void> {
this.inMemoryUploadCacheMap.set(`${this.UPLOAD_SESSION_PREFIX}:${filePath}`, uploadId)
this.inMemoryUploadTTLMap.set(
`${this.UPLOAD_SESSION_PREFIX}:${filePath}`,
+this.timer.getUTCDateNSecondsAhead(this.UPLOAD_SESSION_DEFAULT_TTL) / 1000,
)
}
async retrieveUploadSessionId(filePath: string): Promise<string | undefined> {
this.invalidateStaleUploads()
return this.inMemoryUploadCacheMap.get(`${this.UPLOAD_SESSION_PREFIX}:${filePath}`)
}
async storeUploadChunkResult(uploadId: string, uploadChunkResult: UploadChunkResult): Promise<void> {
this.invalidateStaleUploads()
let uploadResults = []
const uploadResultsJSON = this.inMemoryUploadCacheMap.get(`${this.UPLOAD_CHUNKS_PREFIX}:${uploadId}`)
if (uploadResultsJSON) {
uploadResults = JSON.parse(uploadResultsJSON)
}
uploadResults.unshift(JSON.stringify(uploadChunkResult))
this.inMemoryUploadCacheMap.set(`${this.UPLOAD_CHUNKS_PREFIX}:${uploadId}`, JSON.stringify(uploadResults))
this.inMemoryUploadTTLMap.set(
`${this.UPLOAD_CHUNKS_PREFIX}:${uploadId}`,
+this.timer.getUTCDateNSecondsAhead(this.UPLOAD_SESSION_DEFAULT_TTL) / 1000,
)
}
async retrieveUploadChunkResults(uploadId: string): Promise<UploadChunkResult[]> {
this.invalidateStaleUploads()
let uploadResults = []
const uploadResultsJSON = this.inMemoryUploadCacheMap.get(`${this.UPLOAD_CHUNKS_PREFIX}:${uploadId}`)
if (uploadResultsJSON) {
uploadResults = JSON.parse(uploadResultsJSON)
}
const uploadChunksResults: UploadChunkResult[] = []
for (const stringifiedUploadChunkResult of uploadResults) {
uploadChunksResults.push(JSON.parse(stringifiedUploadChunkResult))
}
const sortedResults = uploadChunksResults.sort((a, b) => {
return a.chunkId - b.chunkId
})
return sortedResults
}
private invalidateStaleUploads(): void {
const now = this.timer.getTimestampInSeconds()
for (const [key, value] of this.inMemoryUploadTTLMap.entries()) {
if (value < now) {
this.inMemoryUploadCacheMap.delete(key)
this.inMemoryUploadTTLMap.delete(key)
}
}
}
}