fix(files): filepicker circular dependency
This commit is contained in:
@@ -32,7 +32,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.23.1",
|
||||
"@standardnotes/services": "workspace:*",
|
||||
"@standardnotes/files": "workspace:*",
|
||||
"@standardnotes/utils": "workspace:*",
|
||||
"@types/wicg-file-system-access": "^2020.9.5",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { EncryptedBytes } from './../TypedBytes'
|
||||
import { EncryptedBytes } from '@standardnotes/files'
|
||||
|
||||
import { FileMemoryCache } from './FileMemoryCache'
|
||||
|
||||
describe('file memory cache', () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { removeFromArray } from '@standardnotes/utils'
|
||||
import { Uuid } from '@standardnotes/common'
|
||||
import { EncryptedBytes } from '../TypedBytes'
|
||||
import { EncryptedBytes } from '@standardnotes/files'
|
||||
|
||||
export class FileMemoryCache {
|
||||
private cache: Record<Uuid, EncryptedBytes> = {}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
import { ByteChunker } from './ByteChunker'
|
||||
|
||||
const chunkOfSize = (size: number) => {
|
||||
return new TextEncoder().encode('a'.repeat(size))
|
||||
}
|
||||
|
||||
describe('byte chunker', () => {
|
||||
it('should hold back small chunks until minimum size is met', async () => {
|
||||
let receivedBytes = new Uint8Array()
|
||||
let numChunks = 0
|
||||
const chunker = new ByteChunker(100, async (bytes) => {
|
||||
numChunks++
|
||||
receivedBytes = new Uint8Array([...receivedBytes, ...bytes])
|
||||
})
|
||||
|
||||
await chunker.addBytes(chunkOfSize(50), false)
|
||||
await chunker.addBytes(chunkOfSize(50), false)
|
||||
await chunker.addBytes(chunkOfSize(50), false)
|
||||
await chunker.addBytes(chunkOfSize(50), true)
|
||||
|
||||
expect(numChunks).toEqual(2)
|
||||
expect(receivedBytes.length).toEqual(200)
|
||||
})
|
||||
|
||||
it('should send back big chunks immediately', async () => {
|
||||
let receivedBytes = new Uint8Array()
|
||||
let numChunks = 0
|
||||
const chunker = new ByteChunker(100, async (bytes) => {
|
||||
numChunks++
|
||||
receivedBytes = new Uint8Array([...receivedBytes, ...bytes])
|
||||
})
|
||||
|
||||
await chunker.addBytes(chunkOfSize(150), false)
|
||||
await chunker.addBytes(chunkOfSize(150), false)
|
||||
await chunker.addBytes(chunkOfSize(150), false)
|
||||
await chunker.addBytes(chunkOfSize(50), true)
|
||||
|
||||
expect(numChunks).toEqual(4)
|
||||
expect(receivedBytes.length).toEqual(500)
|
||||
})
|
||||
|
||||
it('last chunk should be popped regardless of size', async () => {
|
||||
let receivedBytes = new Uint8Array()
|
||||
let numChunks = 0
|
||||
const chunker = new ByteChunker(100, async (bytes) => {
|
||||
numChunks++
|
||||
receivedBytes = new Uint8Array([...receivedBytes, ...bytes])
|
||||
})
|
||||
|
||||
await chunker.addBytes(chunkOfSize(50), false)
|
||||
await chunker.addBytes(chunkOfSize(25), true)
|
||||
|
||||
expect(numChunks).toEqual(1)
|
||||
expect(receivedBytes.length).toEqual(75)
|
||||
})
|
||||
|
||||
it('single chunk should be popped immediately', async () => {
|
||||
let receivedBytes = new Uint8Array()
|
||||
let numChunks = 0
|
||||
const chunker = new ByteChunker(100, async (bytes) => {
|
||||
numChunks++
|
||||
receivedBytes = new Uint8Array([...receivedBytes, ...bytes])
|
||||
})
|
||||
|
||||
await chunker.addBytes(chunkOfSize(50), true)
|
||||
|
||||
expect(numChunks).toEqual(1)
|
||||
expect(receivedBytes.length).toEqual(50)
|
||||
})
|
||||
})
|
||||
@@ -1,35 +0,0 @@
|
||||
import { OnChunkCallback } from '../types'
|
||||
|
||||
export class ByteChunker {
|
||||
public loggingEnabled = false
|
||||
private bytes = new Uint8Array()
|
||||
private index = 1
|
||||
|
||||
constructor(private minimumChunkSize: number, private onChunk: OnChunkCallback) {}
|
||||
|
||||
private log(...args: any[]): void {
|
||||
if (!this.loggingEnabled) {
|
||||
return
|
||||
}
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(args)
|
||||
}
|
||||
|
||||
public async addBytes(bytes: Uint8Array, isLast: boolean): Promise<void> {
|
||||
this.bytes = new Uint8Array([...this.bytes, ...bytes])
|
||||
|
||||
this.log(`Chunker adding ${bytes.length}, total size ${this.bytes.length}`)
|
||||
|
||||
if (this.bytes.length >= this.minimumChunkSize || isLast) {
|
||||
await this.popBytes(isLast)
|
||||
}
|
||||
}
|
||||
|
||||
private async popBytes(isLast: boolean): Promise<void> {
|
||||
const maxIndex = Math.max(this.minimumChunkSize, this.bytes.length)
|
||||
const chunk = this.bytes.slice(0, maxIndex)
|
||||
this.bytes = new Uint8Array([...this.bytes.slice(maxIndex)])
|
||||
this.log(`Chunker popping ${chunk.length}, total size in queue ${this.bytes.length}`)
|
||||
await this.onChunk(chunk, this.index++, isLast)
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import { OrderedByteChunker } from './OrderedByteChunker'
|
||||
|
||||
const chunkOfSize = (size: number) => {
|
||||
return new TextEncoder().encode('a'.repeat(size))
|
||||
}
|
||||
|
||||
describe('ordered byte chunker', () => {
|
||||
it('should callback multiple times if added bytes matches multiple chunk sizes', async () => {
|
||||
const chunkSizes = [10, 10, 10]
|
||||
let receivedBytes = new Uint8Array()
|
||||
let numCallbacks = 0
|
||||
|
||||
const chunker = new OrderedByteChunker(chunkSizes, async (bytes) => {
|
||||
numCallbacks++
|
||||
receivedBytes = new Uint8Array([...receivedBytes, ...bytes])
|
||||
})
|
||||
|
||||
await chunker.addBytes(chunkOfSize(30))
|
||||
|
||||
expect(numCallbacks).toEqual(3)
|
||||
expect(receivedBytes.length).toEqual(30)
|
||||
})
|
||||
})
|
||||
@@ -1,40 +0,0 @@
|
||||
export class OrderedByteChunker {
|
||||
private bytes = new Uint8Array()
|
||||
private index = 1
|
||||
private remainingChunks: number[] = []
|
||||
|
||||
constructor(
|
||||
private chunkSizes: number[],
|
||||
private onChunk: (chunk: Uint8Array, index: number, isLast: boolean) => Promise<void>,
|
||||
) {
|
||||
this.remainingChunks = chunkSizes.slice()
|
||||
}
|
||||
|
||||
private needsPop(): boolean {
|
||||
return this.remainingChunks.length > 0 && this.bytes.length >= this.remainingChunks[0]
|
||||
}
|
||||
|
||||
public async addBytes(bytes: Uint8Array): Promise<void> {
|
||||
this.bytes = new Uint8Array([...this.bytes, ...bytes])
|
||||
|
||||
if (this.needsPop()) {
|
||||
await this.popBytes()
|
||||
}
|
||||
}
|
||||
|
||||
private async popBytes(): Promise<void> {
|
||||
const readUntil = this.remainingChunks[0]
|
||||
|
||||
const chunk = this.bytes.slice(0, readUntil)
|
||||
|
||||
this.bytes = new Uint8Array([...this.bytes.slice(readUntil)])
|
||||
|
||||
this.remainingChunks.shift()
|
||||
|
||||
await this.onChunk(chunk, this.index++, this.index === this.chunkSizes.length - 1)
|
||||
|
||||
if (this.needsPop()) {
|
||||
await this.popBytes()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ByteChunker } from './../Chunker/ByteChunker'
|
||||
import { OnChunkCallback, FileSelectionResponse } from '../types'
|
||||
import { ByteChunker, OnChunkCallback } from '@standardnotes/files'
|
||||
import { FileSelectionResponse } from '../types'
|
||||
import { readFile as utilsReadFile } from '../utils'
|
||||
import { FileReaderInterface } from '../Interface/FileReader'
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { OnChunkCallback, FileSelectionResponse } from '../types'
|
||||
import { OnChunkCallback } from '@standardnotes/files'
|
||||
|
||||
import { FileSelectionResponse } from '../types'
|
||||
|
||||
export interface FileReaderInterface {
|
||||
selectFiles(): Promise<File[]>
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
FileHandleRead,
|
||||
FileSystemNoSelection,
|
||||
FileSystemResult,
|
||||
} from '@standardnotes/services'
|
||||
} from '@standardnotes/files'
|
||||
|
||||
interface WebDirectoryHandle extends DirectoryHandle {
|
||||
nativeHandle: FileSystemDirectoryHandle
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ByteChunker, OnChunkCallback } from '@standardnotes/files'
|
||||
|
||||
import { FileReaderInterface } from './../Interface/FileReader'
|
||||
import { ByteChunker } from '../Chunker/ByteChunker'
|
||||
import { OnChunkCallback, FileSelectionResponse } from '../types'
|
||||
import { FileSelectionResponse } from '../types'
|
||||
|
||||
interface StreamingFileReaderInterface {
|
||||
getFilesFromHandles(handles: FileSystemFileHandle[]): Promise<File[]>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
export type EncryptedBytes = {
|
||||
encryptedBytes: Uint8Array
|
||||
}
|
||||
|
||||
export type DecryptedBytes = {
|
||||
decryptedBytes: Uint8Array
|
||||
}
|
||||
@@ -5,7 +5,4 @@ export * from './Streaming/StreamingReader'
|
||||
export * from './Streaming/StreamingSaver'
|
||||
export * from './Streaming/StreamingApi'
|
||||
export * from './utils'
|
||||
export * from './Chunker/ByteChunker'
|
||||
export * from './Chunker/OrderedByteChunker'
|
||||
export * from './Cache/FileMemoryCache'
|
||||
export * from './TypedBytes'
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
export type OnChunkCallback = (chunk: Uint8Array, index: number, isLast: boolean) => Promise<void>
|
||||
|
||||
export type FileSelectionResponse = {
|
||||
name: string
|
||||
mimeType: string
|
||||
|
||||
Reference in New Issue
Block a user