164 lines
4.7 KiB
TypeScript
164 lines
4.7 KiB
TypeScript
import { spawn, ChildProcessWithoutNullStreams } from "child_process";
|
|
import * as fs from "fs";
|
|
|
|
export interface IZap {
|
|
process: ChildProcessWithoutNullStreams | null,
|
|
channel: string,
|
|
adapter: 0 | 1
|
|
strength: {
|
|
signal: string;
|
|
cn: string;
|
|
},
|
|
}
|
|
|
|
export default class Zap {
|
|
private zap0: IZap;
|
|
private zap1: IZap;
|
|
private channelNameList: string[];
|
|
private fileName: string;
|
|
|
|
private regex = /Signal=\s*(-?\d+(\.\d+)?dBm)\s+C\/N=\s*(\d+(\.\d+)?dB)/;
|
|
|
|
|
|
public constructor(fileName = "dvb_channel.conf", channel = "ION") {
|
|
const zap0: IZap = {
|
|
process: null,
|
|
channel,
|
|
adapter: 0,
|
|
strength: {
|
|
signal: "None",
|
|
cn: "None"
|
|
}
|
|
}
|
|
const zap1: IZap = {
|
|
process: null,
|
|
channel,
|
|
adapter: 1,
|
|
strength: {
|
|
signal: "None",
|
|
cn: "None"
|
|
}
|
|
}
|
|
this.zap0 = zap0;
|
|
this.zap1 = zap1;
|
|
|
|
const file = fs.readFileSync('./' + fileName, "utf-8");
|
|
const lines = file.split("\n").map(line => line.trim()).filter(line => line && !line.startsWith("#")).map(line => line.split(":")[0]);
|
|
this.channelNameList = lines;
|
|
this.fileName = fileName;
|
|
|
|
}
|
|
|
|
public getChannels(): string[] {
|
|
return this.channelNameList;
|
|
}
|
|
|
|
public getSignal(adapter: number) {
|
|
if(adapter == 0){
|
|
return this.zap0.strength;
|
|
}
|
|
else if (adapter == 1){
|
|
return this.zap1.strength;
|
|
}
|
|
else {
|
|
return {signal: 'N/A', cn: 'N/A'}
|
|
}
|
|
}
|
|
|
|
private nextChannel(channel: string) :string {
|
|
const size = this.channelNameList.length;
|
|
const currentIndex = this.channelNameList.indexOf(channel);
|
|
if (currentIndex >= 0) {
|
|
return this.channelNameList[this.mod(currentIndex + 1, size)];
|
|
}
|
|
else {
|
|
return channel;
|
|
}
|
|
}
|
|
|
|
private mod(n: number, m: number) :number{
|
|
return ((n % m) + m) % m;
|
|
}
|
|
|
|
private previousChannel(channel: string):string {
|
|
const size = this.channelNameList.length;
|
|
const currentIndex = this.channelNameList.indexOf(channel);
|
|
if (currentIndex >= 0) {
|
|
return this.channelNameList[this.mod(currentIndex - 1, size)];
|
|
}
|
|
else {
|
|
return channel;
|
|
}
|
|
}
|
|
|
|
private cleanup(proc: ChildProcessWithoutNullStreams): Promise<void> {
|
|
proc.kill('SIGHUP');
|
|
return new Promise((resolve, reject) => {
|
|
proc.once('exit', () =>
|
|
resolve()
|
|
)
|
|
proc.on("error", (err: Error) =>
|
|
reject(err)
|
|
);
|
|
})
|
|
}
|
|
|
|
public async zapTo(channel: string, adapter: 0 | 1 = 0): Promise<IZap> {
|
|
let zap = adapter == 0 ? this.zap0 : this.zap1;
|
|
let verifiedChannel: string;
|
|
if (channel == '+') {
|
|
verifiedChannel = this.nextChannel(zap.channel);
|
|
}
|
|
else if (channel == '-') {
|
|
verifiedChannel = this.previousChannel(zap.channel);
|
|
}
|
|
else {
|
|
if (!this.channelNameList.includes(channel)) {
|
|
return Promise.reject(new Error("Invalid Channel name"));
|
|
}
|
|
else {
|
|
verifiedChannel = channel;
|
|
}
|
|
}
|
|
const cmd = 'dvbv5-zap'
|
|
const args: string[] = ["-r", "-C", "US", "-I", "ZAP", "-c", this.fileName, "-a", adapter.toString(), verifiedChannel];
|
|
if (zap.process != null) {
|
|
await this.cleanup(zap.process).catch(err => Promise.reject(err));
|
|
|
|
}
|
|
zap.process = spawn(cmd, args);
|
|
return new Promise((resolve, reject) => {
|
|
let lockTimer: NodeJS.Timeout;
|
|
|
|
|
|
zap.process.stderr.on("data", (data) => {
|
|
const output = data.toString();
|
|
|
|
if (/Lock/.test(output)) {
|
|
clearTimeout(lockTimer);
|
|
const match = output.match(this.regex);
|
|
zap.channel = verifiedChannel;
|
|
zap.strength = {
|
|
signal: match[1],
|
|
cn: match[3]
|
|
}
|
|
resolve(zap);
|
|
}
|
|
|
|
if (/Not locked/.test(output)) {
|
|
clearTimeout(lockTimer);
|
|
zap.process.kill("SIGHUP");
|
|
}
|
|
});
|
|
|
|
zap.process.on("exit", (code) => {
|
|
reject(new Error("Unexpected exit of Zap"));
|
|
});
|
|
|
|
lockTimer = setTimeout(() => {
|
|
reject(new Error("Failed to Zap in time"));
|
|
}, 5000);
|
|
})
|
|
|
|
}
|
|
}
|