Skip to content

Commit 7153bb7

Browse files
committed
Used fixed size byte array
1 parent bf93c4c commit 7153bb7

File tree

1 file changed

+54
-66
lines changed

1 file changed

+54
-66
lines changed

scripts/emulator-testing/emulators/emulator.ts

Lines changed: 54 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -53,70 +53,61 @@ export abstract class Emulator {
5353
return Promise.resolve();
5454
}
5555

56+
const { name: tempDir } = tmp.dirSync({ unsafeCleanup: true });
57+
const filepath = path.resolve(tempDir, this.binaryName);
5658
return new Promise<void>((resolve, reject) => {
57-
tmp.dir((err: Error | null, dir: string) => {
58-
if (err) reject(err);
59-
console.log(`Created temporary directory at [${dir}].`);
60-
const filepath: string = path.resolve(dir, this.binaryName);
61-
const buf: any[] = [];
62-
console.log(`Downloading emulator from [${this.binaryUrl}] ...`);
63-
// Map the DOM's fetch Reader to node's streaming file system
64-
// operations. We will need to access class members `binaryPath` and `copyToCache` after the
65-
// download completes. It's a compilation error to pass `this` into the named function
66-
// `readChunk`, so the download operation is wrapped in a promise that we wait upon.
67-
console.log(process.memoryUsage().heapTotal);
68-
const downloadPromise = new Promise<void>(
69-
(downloadComplete, downloadFailed) => {
70-
fetch(this.binaryUrl)
71-
.then(resp => {
72-
if (resp.status !== 200 || resp.body === null) {
73-
console.log('Download of emulator failed: ', resp.statusText);
74-
downloadFailed();
75-
} else {
76-
const reader = resp.body.getReader();
77-
reader.read().then(function readChunk({ done, value }): any {
78-
if (done) {
79-
console.log('done download. buffer length:', buf.length);
80-
downloadComplete();
81-
} else {
82-
buf.push(...value);
83-
return reader.read().then(readChunk);
84-
}
85-
});
59+
// We want access to `this.binaryPath` after the download is finished, but we can't since in
60+
// `readChunk`, `this` is not inherited from the parent (since it's a named function expression).
61+
// To work around this, we wrap the fetch in a promise, then once it's resolved we can access `this` in the callback arrow function.
62+
const downloadPromise = new Promise<Uint8Array>(
63+
(downloadComplete, downloadFailed) => {
64+
fetch(this.binaryUrl)
65+
.then(resp => {
66+
if (!resp.ok || resp.body === null) {
67+
return downloadFailed(
68+
`Failed to download emulator: [${resp.status}] ${resp.statusText}`
69+
);
70+
}
71+
72+
const buf = new Uint8Array(2 ** 25); // 32Mb
73+
let cur = 0;
74+
const reader = resp.body.getReader();
75+
reader.read().then(function readChunk({ done, value }): any {
76+
if (done) {
77+
return downloadComplete(buf);
8678
}
87-
})
88-
.catch(e => {
89-
console.log(`Download of emulator failed: ${e}`);
90-
downloadFailed();
79+
80+
if (!value) {
81+
return downloadFailed(
82+
'Did not receive chunk in response body'
83+
);
84+
}
85+
86+
buf.set(value, cur);
87+
cur += value.length;
88+
return reader.read().then(readChunk);
9189
});
92-
}
93-
);
90+
})
91+
.catch(err => downloadFailed(err));
92+
}
93+
);
9494

95-
downloadPromise.then(
96-
() => {
97-
console.log('Download complete');
98-
// Change emulator binary file permission to 'rwxr-xr-x'.
99-
// The execute permission is required for it to be able to start
100-
// with 'java -jar'.
101-
fs.writeFileSync(filepath, new Uint8Array(buf));
102-
103-
fs.chmod(filepath, 0o755, err => {
104-
if (err) {
105-
reject(err);
106-
}
95+
downloadPromise.then(buf => {
96+
fs.writeFileSync(filepath, buf);
97+
fs.chmod(filepath, 0o755, err => {
98+
if (err) {
99+
return reject(err);
100+
}
107101

108-
console.log(`Changed emulator file permissions to 'rwxr-xr-x'.`);
109-
this.binaryPath = filepath;
110-
if (this.copyToCache()) {
111-
console.log(`Cached emulator at ${this.cacheBinaryPath}`);
112-
}
113-
resolve();
114-
});
115-
},
116-
() => {
117-
reject();
102+
console.log(`Changed emulator file permissions to 'rwxr-xr-x'.`);
103+
// Since we are now in an arrow function, `this` is inherited from the `download()` method, so it is the Emulator object
104+
this.binaryPath = filepath;
105+
if (this.copyToCache()) {
106+
console.log(`Cached emulator at ${this.cacheBinaryPath}`);
118107
}
119-
);
108+
109+
resolve();
110+
});
120111
});
121112
});
122113
}
@@ -128,14 +119,11 @@ export abstract class Emulator {
128119
}
129120
let promise: ChildProcessPromise<SpawnPromiseResult>;
130121
if (this.isDataConnect) {
131-
promise = spawn(
132-
this.binaryPath,
133-
[
134-
'dev',
135-
'--local_connection_string',
136-
"'postgresql://postgres:secretpassword@localhost:5432/postgres?sslmode=disable'"
137-
]
138-
);
122+
promise = spawn(this.binaryPath, [
123+
'dev',
124+
'--local_connection_string',
125+
"'postgresql://postgres:secretpassword@localhost:5432/postgres?sslmode=disable'"
126+
]);
139127
} else {
140128
promise = spawn(
141129
'java',

0 commit comments

Comments
 (0)