-
Notifications
You must be signed in to change notification settings - Fork 2
/
eltrafico.ts
90 lines (82 loc) · 2.45 KB
/
eltrafico.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
import { z } from "https://deno.land/x/[email protected]/mod.ts";
export const zProcess = z.object({
// the only required prop, can be made optional as well
match: z.object({ name: z.string().optional() }).array(),
download: z.string().optional(),
upload: z.string().optional(),
"download-minimum": z.string().optional(),
"upload-minimum": z.string().optional(),
//TODO: use these
"download-priority": z.number().optional(),
"upload-priority": z.number().optional(),
});
export type Process = z.infer<typeof zProcess>;
function findEltraficoTc() {
return Deno.env.get("TC") || "eltrafico-tc";
}
//TODO: add reset
export class ElTrafico {
#tc: Deno.ChildProcess;
#reader;
#writer;
constructor() {
this.#tc = new Deno.Command("pkexec", {
args: [findEltraficoTc()],
stdout: "piped",
stdin: "piped",
stderr: "inherit",
}).spawn();
this.#reader = this.#tc.stdout.getReader();
this.#writer = this.#tc.stdin.getWriter();
}
async limitGlobal(global: Omit<Process, "match">) {
const startMsg = "Global: ";
const limitAction = `${startMsg} ${utn(global.download)} ${
utn(global.upload)
} ${utn(global["download-minimum"])} ${utn(global["upload-minimum"])}`;
await this.#write(limitAction);
}
async limit(process: Process) {
//TODO: use all match names
const startMsg = `Program: ${utn(process.match[0].name)}`;
const limitAction = `${startMsg} ${utn(process.download)} ${
utn(process.upload)
} ${utn(process["download-minimum"])} ${utn(process["upload-minimum"])}`;
await this.#write(limitAction);
}
async stop() {
await this.#write("Stop");
}
async interface(name: string) {
await this.#write(`Interface: ${name}`);
}
async poll() {
const data = await this.#read();
if (data == "Stop") {
return { stop: true };
}
return (data.split("\n").filter((l) => l).map((line) => {
return { name: line.split("ProgramEntry: ")[1] };
}));
}
async #read() {
return await this.#reader.read().then((data) =>
// the data is small
// it should be done in one read
// NOTE: this assumption might not hold
new TextDecoder().decode(data.value)
);
}
async #write(data: string) {
return await this.#writer.write(
new TextEncoder().encode(data + "\n"),
);
}
}
/** Undefined to None */
function utn(
maybeValue: string | undefined,
) {
if (maybeValue === undefined) return "None";
return maybeValue;
}