forked from duart38/Thread
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathThread.ts
More file actions
127 lines (113 loc) · 3.51 KB
/
Thread.ts
File metadata and controls
127 lines (113 loc) · 3.51 KB
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
export default class Thread<T> {
public worker: Promise<Worker>;
private imports: Array<string>;
private blob: Promise<Blob>;
private blobURL: string = "";
/**
* Tells if the worker has been stopped
*/
public stopped = false;
/**
*
* @param operation The method to be used in the thread
* @param imports Modules to import in the worker. only JS files allowed (over the net import allowed)
*/
constructor(
operation: (e: MessageEvent, globalObject?:{}) => T,
type?: "classic" | "module",
imports?: Array<string>,
) {
imports?.forEach((v) => {
if (v.endsWith(".ts'") || v.endsWith('.ts"')) {
throw new Error("Threaded imports do no support typescript files");
}
});
this.imports = imports || [];
this.blob = this.populateFile(operation);
this.blob.then(async (b)=>console.log(await b.text()));
this.worker = this.makeWorker(type);
}
private async makeWorker(type?: "classic" | "module"){
this.blobURL = URL.createObjectURL(await this.blob)
return new Worker(
this.blobURL,
{
type: type || "module",
},
);
}
private async populateFile(code: Function) {
let imported = this.imports?.flatMap(async (val) => (await this.copyDep(val)).join("\n"));
return new Blob([`
${(await Promise.all(imported)).join("\n")}
var global = {};
var userCode = ${code.toString()}
onmessage = function(e) {
postMessage(userCode(e, global));
}
`]);
}
/**
* Handles a single import line
* @param str the import line (eg: import {som} from "lorem/ipsum.js";)
*/
private async copyDep(str: string) {
var importPathRegex = /('|"|`)(.+\.js)(\1)/ig; // for the path string ("lorem/ipsum.js")
var importInsRegex = /(import( |))({.+}|.+)(from( |))/ig; // for the instruction before the path (import {som} from)
var matchedPath = importPathRegex.exec(str) || "";
var file = false;
var fqfn = "";
if (
!matchedPath[0].includes("http://") &&
!matchedPath[0].includes("https://")
) {
file = true;
fqfn = matchedPath[0].replaceAll(/('|"|`)/ig, "");
}
var matchedIns = importInsRegex.exec(str) || ""; // matchedIns[0] > import {sss} from
if (!matchedIns) {
throw new Error(
"The import instruction seems to be unreadable try formatting it, for example: \n" +
"import { something } from './somet.js' \n ",
);
}
if (file) {
let x = await import(fqfn); //Deno.realPathSync(fqfn)
return Object.keys(x).map((v)=>x[v].toString())
} else {
let x = await import(matchedPath[0].replaceAll(/'|"/g,""));
return Object.keys(x).map((v)=>x[v].toString())
}
}
/**
* Sends data to the Thread
* @param msg
*/
public postMessage(msg: any): this {
this.worker.then(w=>w.postMessage(msg));
return this;
}
/**
* Handbrakes are very handy you know
*/
public async stop() {
this.stopped = true;
(await this.worker).terminate();
}
/**
* Stops the worker and revokes the blob URL.
* NOTE: Can be used while the program is running (calls stop()..)
*/
public async remove() {
if (this.stopped == false) await this.stop();
URL.revokeObjectURL(this.blobURL);
}
/**
* Bind to the worker to receive messages
* @param callback Function that is called when the worker sends data back
*/
public onMessage(callback: (e: T) => void): this {
this.worker.then(w=>w.onmessage = (e) => callback(e.data));
return this;
}
}