UNPKG

mirakurun

Version:

DVR Tuner Server for Japanese TV.

164 lines 5.86 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const stream = __importStar(require("stream")); const child_process = __importStar(require("child_process")); const log = __importStar(require("./log")); const status_1 = __importDefault(require("./status")); let idCounter = 0; class TSDecoder extends stream.Writable { _output; _id; _command; _process; _readable; _writable; _isNew = false; _timeout; _closed = false; _deadCount = 0; constructor(opts) { super(); this._id = idCounter++; this._command = opts.command; this._output = opts.output; this._output.once("finish", this._close.bind(this)); this._output.once("close", this._close.bind(this)); Object.defineProperty(this, "writableLength", { get() { return opts.output.writableLength; } }); Object.defineProperty(this, "writableHighWaterMark", { get() { return opts.output.writableHighWaterMark; } }); this.once("close", this._close.bind(this)); log.info("TSDecoder#%d has created (command=%s)", this._id, this._command); ++status_1.default.streamCount.decoder; this._spawn(); } _write(chunk, encoding, callback) { if (!this._writable) { callback(); return; } if (this._isNew === true && this._process) { this._isNew = false; this._timeout = setTimeout(() => { log.warn("TSDecoder#%d process will force killed because no respond...", this._id); this._dead(); }, 1500); } this._writable.write(chunk); callback(); } _final() { this._close(); } _spawn() { if (this._closed === true || this._process) { return; } if (this._deadCount > 0) { ++status_1.default.errorCount.decoderRespawn; log.warn("TSDecoder#%d respawning because dead (count=%d)", this._id, this._deadCount); } const proc = this._process = child_process.spawn(this._command); proc.once("close", (code, signal) => { log.info("TSDecoder#%d process has closed with exit code=%d by signal `%s` (pid=%d)", this._id, code, signal, proc.pid); this._dead(); }); proc.stderr.pipe(process.stderr); proc.stdout.once("data", () => clearTimeout(this._timeout)); proc.stdout.on("data", chunk => this._output.write(chunk)); this._readable = proc.stdout; this._writable = proc.stdin; this._isNew = true; log.info("TSDecoder#%d process has spawned by command `%s` (pid=%d)", this._id, this._command, proc.pid); } _dead() { if (this._closed === true) { return; } log.error("TSDecoder#%d unexpected dead", this._id); ++this._deadCount; this._kill(); if (this._deadCount > 3) { this._fallback(); return; } setTimeout(() => this._spawn(), 1500); } _fallback() { const passThrough = new stream.PassThrough({ allowHalfOpen: false }); passThrough.on("data", chunk => this._output.write(chunk)); this._readable = passThrough; this._writable = passThrough; log.warn("TSDecoder#%d has been fallback into pass-through stream", this._id); } _kill() { if (this._process) { this._process.kill("SIGKILL"); delete this._process; } if (this._readable) { this._readable.destroy(); delete this._readable; } if (this._writable) { this._writable.destroy(); delete this._writable; } } _close() { if (this._closed === true) { return; } this._closed = true; this._kill(); if (this._output.writableEnded === false) { this._output.end(); } this._output.removeAllListeners(); delete this._output; --status_1.default.streamCount.decoder; log.info("TSDecoder#%d has closed (command=%s)", this._id, this._command); this.emit("close"); this.emit("end"); } } exports.default = TSDecoder; //# sourceMappingURL=TSDecoder.js.map