-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindexable-stream.ts
103 lines (85 loc) · 2.41 KB
/
indexable-stream.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
export class IndexableStream {
[index: number]: Promise<number>
[index: string]: any
reader: ReadableStreamDefaultReader;
buffer: Uint8Array;
offset: number;
lastRead: number;
done: boolean;
constructor(reader: ReadableStreamDefaultReader) {
this.reader = reader
this.offset = 0
this.lastRead = 0
this.done = false
return new Proxy(this, {
get(target, name) {
const i = Number(name)
if (isNaN(i)) {
return target[name.toString()]
}
const ret = target.getIndex(i)
return ret.catch(e => {
console.log(e)
throw e
})
}
});
}
async getIndex(i: number): Promise<number> {
if (this.buffer === undefined || (this.buffer.length + this.offset <= i)) {
if (this.done) {
throw new Error(`requested byte ${i} but source is done and we only have ${this.buffer.length + this.offset} bytes`)
}
await this.read()
}
return this.buffer[i - this.offset]
}
async slice(from: number, to: number): Promise<Uint8Array> {
try {
if (from < this.offset) {
throw new Error(`can't get data before ${this.offset}`)
}
while (from > this.offset + this.buffer.length) {
await this.read()
}
let ret = new Uint8Array(to - from)
let writeOffset = 0
while (to > this.offset + this.buffer.length) {
let toWrite = this.buffer.slice(from + writeOffset - this.offset)
ret.set(toWrite, writeOffset)
writeOffset += toWrite.length
await this.read()
}
let toWrite = this.buffer.slice(from + writeOffset - this.offset, to - this.offset)
ret.set(toWrite, writeOffset)
return ret
} catch (e) {
console.log(e)
throw e
}
}
async read() {
const { done, value } = await this.reader.read()
this.done = done
if (done) {
return
}
if (this.buffer === undefined) {
this.buffer = value
return
}
let lastChunk: Uint8Array
if (this.lastRead > 0) {
// drop the oldest chunk we read
lastChunk = this.buffer.slice(this.lastRead)
this.offset += this.buffer.length - lastChunk.length
} else {
lastChunk = this.buffer
}
const tmp = new Uint8Array(lastChunk.length + value.length);
tmp.set(lastChunk, 0);
tmp.set(value, lastChunk.length);
this.buffer = tmp
this.lastRead = value.length
}
}