Skip to content

Commit

Permalink
fix: Enable graceful shutdown
Browse files Browse the repository at this point in the history
  • Loading branch information
schw4rzlicht committed Jun 7, 2020
1 parent 95f6a70 commit 24272bd
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 26 deletions.
8 changes: 6 additions & 2 deletions __tests__/PermissionController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ const _ = require("lodash");
let config: Config;
let permissionController: PermissionController;

beforeAll(() => {
beforeEach(() => {
config = loadConfig();
permissionController = new PermissionController()
.withPermissionInstance(new CooldownPermission())
.withPermissionInstance(new ModeratorPermission())
.withPermissionInstance(new OwnerPermission());
})
});

afterEach(() => {
permissionController.stop();
});

test("Permission collector denies permission", () => {

Expand Down
41 changes: 20 additions & 21 deletions __tests__/Twitch2Ma.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ jest.mock("source-map-support");
jest.mock("twitch-chat-client");
jest.mock("telnet-client", require("./mocks/telnet-client"));

let config = loadConfig();
let config: Config;
let twitch2Ma: Twitch2Ma;

test("Connection chain", async () => {
beforeEach(() => {
config = loadConfig();
twitch2Ma = getTwitch2MaInstanceAndEnableLogin();
});

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin();
afterEach(() => twitch2Ma.stop());

test("Connection chain", async () => {

let spyOnTelnetLogin = jest.spyOn(twitch2Ma, "telnetLogin");
let spyOnInitTwitch = jest.spyOn(twitch2Ma, "initTwitch");
Expand All @@ -45,7 +51,7 @@ test("Connection chain", async () => {

test("Telnet connection failed", async () => {

let twitch2Ma = new Twitch2Ma(config);
twitch2Ma = new Twitch2Ma(config);

jest.spyOn(twitch2Ma["telnet"], "connect").mockRejectedValueOnce("Fooled!");

Expand All @@ -63,7 +69,7 @@ test("Telnet connection failed", async () => {

test("Telnet login failed", async () => {

let twitch2Ma = new Twitch2Ma(config);
twitch2Ma = new Twitch2Ma(config);

let spyOnOnTelnetConnected = jest.fn();
let spyOnOnTwitchConnected = jest.fn();
Expand All @@ -80,8 +86,6 @@ test("Telnet login failed", async () => {

test("Twitch connection failed", async () => {

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin();

let spyOnOnTelnetConnected = jest.fn();
let spyOnOnTwitchConnected = jest.fn();

Expand Down Expand Up @@ -110,8 +114,6 @@ test("Twitch channel join failed", async () => {

let errorHandler = jest.fn();

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin();

let spyOnOnTelnetConnected = jest.fn();
let spyOnOnTwitchConnected = jest.fn();

Expand All @@ -130,7 +132,6 @@ test("Twitch channel join failed", async () => {

test("Message handler set", async () => {

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin();
await twitch2Ma.start();

let spyOnMessageHandler = jest.spyOn(twitch2Ma, "handleMessage");
Expand All @@ -144,8 +145,8 @@ test("Send help", async () => {

let helpExecutedHandler = jest.fn();

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin();
twitch2Ma.onHelpExecuted(helpExecutedHandler);

await twitch2Ma.start();

let spyOnTwitchSay = jest.spyOn(twitch2Ma["chatClient"], "say");
Expand Down Expand Up @@ -181,7 +182,7 @@ test("Send help w/o commands", async () => {

let helpExecutedHandler = jest.fn();

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin(loadConfig({commands: []}));
twitch2Ma = getTwitch2MaInstanceAndEnableLogin(loadConfig({commands: []}));
twitch2Ma.onHelpExecuted(helpExecutedHandler);
await twitch2Ma.start();

Expand All @@ -195,8 +196,8 @@ test("Command successful", async () => {
let aliceRawMessage = new TwitchPrivateMessage("doesNotMatter", null, null, {nick: "Alice"});
let commandExecutedHandler = jest.fn();

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin();
twitch2Ma.onCommandExecuted(commandExecutedHandler);

await twitch2Ma.start();

await sendMessageToBotAndExpectAnswer(twitch2Ma, jest.spyOn(twitch2Ma["chatClient"], "say"), "#doesNotMatter",
Expand All @@ -214,8 +215,8 @@ test("Text only command successful", async () => {
let aliceRawMessage = new TwitchPrivateMessage("doesNotMatter", null, null, {nick: "Alice"});
let commandExecutedHandler = jest.fn();

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin();
twitch2Ma.onCommandExecuted(commandExecutedHandler);

await twitch2Ma.start();

await sendMessageToBotAndExpectAnswer(twitch2Ma, jest.spyOn(twitch2Ma["chatClient"], "say"), "#doesNotMatter",
Expand All @@ -230,8 +231,8 @@ test("Parameter successful", async () => {
let aliceRawMessage = new TwitchPrivateMessage("doesNotMatter", null, null, {nick: "Alice"});
let commandExecutedHandler = jest.fn();

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin();
twitch2Ma.onCommandExecuted(commandExecutedHandler);

await twitch2Ma.start();

await sendMessageToBotAndExpectAnswer(twitch2Ma, jest.spyOn(twitch2Ma["chatClient"], "say"), "#doesNotMatter",
Expand All @@ -246,8 +247,8 @@ test("Parameter does not exist", async () => {
let aliceRawMessage = new TwitchPrivateMessage("doesNotMatter", null, null, {nick: "Alice"});
let commandExecutedHandler = jest.fn();

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin();
twitch2Ma.onCommandExecuted(commandExecutedHandler);

await twitch2Ma.start();

await sendMessageToBotAndExpectAnswer(twitch2Ma, jest.spyOn(twitch2Ma["chatClient"], "say"), "#doesNotMatter",
Expand All @@ -263,7 +264,6 @@ test("Telnet command failed", async () => {
let commandExecutedHandler = jest.fn();
let errorHandler = jest.fn();

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin(loadConfig());
twitch2Ma.onCommandExecuted(commandExecutedHandler);
twitch2Ma.onError(errorHandler);

Expand All @@ -284,8 +284,8 @@ test("Command permissions denied", async () => {
let aliceRawMessage = new TwitchPrivateMessage("doesNotMatter", null, null, {nick: "Alice"});
let permissionDeniedHandler = jest.fn();

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin();
twitch2Ma.onPermissionDenied(permissionDeniedHandler);

await twitch2Ma.start();

await sendMessageToBotAndExpectAnswer(twitch2Ma, jest.spyOn(twitch2Ma["chatClient"], "say"), "#doesNotMatter",
Expand All @@ -302,8 +302,8 @@ test("Command permissions denied but godMode enabled", async () => {
let aliceRawMessage = new TwitchPrivateMessage("doesNotMatter", null, new Map([["badges", "moderator"]]), {nick: "Alice"});
let godModeHandler = jest.fn();

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin();
twitch2Ma.onGodMode(godModeHandler);

await twitch2Ma.start();

await sendMessageToBotAndExpectAnswer(twitch2Ma, jest.spyOn(twitch2Ma["chatClient"], "say"), "#doesNotMatter",
Expand All @@ -317,7 +317,6 @@ test("Command permissions denied but godMode enabled", async () => {

test("Message not involving the bot", async () => {

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin();
await twitch2Ma.start();

let spyOnTwitchSay = jest.spyOn(twitch2Ma["chatClient"], "say");
Expand Down Expand Up @@ -359,7 +358,7 @@ async function sendMessageToBot(twitch2Ma: Twitch2Ma, channel: string, user: str

function getTwitch2MaInstanceAndEnableLogin(newConfig?: Config): Twitch2Ma {

let twitch2Ma = newConfig ? new Twitch2Ma(newConfig) : new Twitch2Ma(config);
let twitch2Ma = new Twitch2Ma(newConfig || config);

jest.spyOn(twitch2Ma["telnet"], "exec")
.mockResolvedValueOnce(`Logged in as User '${config.ma.user}'`);
Expand Down
9 changes: 9 additions & 0 deletions src/lib/PermissionController.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import {RuntimeInformation} from "./RuntimeInformation";

export interface PermissionInstance {

check(permissionCollector: PermissionCollector,
runtimeInformation: RuntimeInformation,
additionalRuntimeInformation: Map<String, any>): void;

stop(): void;
}

export class PermissionError extends Error {
Expand Down Expand Up @@ -60,6 +63,12 @@ export class PermissionController {
setAdditionalRuntimeInformation(name: string, value: any) {
this.additionalRuntimeInformation.set(name, value);
}

stop() {
for (const permissionInstance of this.permissionInstances) {
permissionInstance.stop();
}
}
}

export class PermissionCollector {
Expand Down
1 change: 1 addition & 0 deletions src/lib/Twitch2Ma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export default class Twitch2Ma extends EventEmitter {
return this.chatClient.quit()
.finally(this.telnet.end);
}
this.permissionController.stop();
return this.telnet.end();
}

Expand Down
15 changes: 14 additions & 1 deletion src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,20 @@ import chalk = require("chalk");
const semverGt = require('semver/functions/gt')
const packageInformation = require("../../package.json");

let twitch2Ma: Twitch2Ma;

export async function main() {

process.on("SIGINT", () => {
console.log(chalk`\n{bold Thank you for using twitch2ma} ❤️`);
if(twitch2Ma) {
twitch2Ma.stop()
.catch((err: Error) => {
error(err.message);
process.exit(1);
})
.then(process.exit(0))
}
process.exit(0);
});

Expand All @@ -32,7 +42,10 @@ function init(): void {
.arguments("[configFile]")
.action(configFile => {
loadConfig(configFile)
.then(config => new Twitch2Ma(config))
.then(config => {
twitch2Ma = new Twitch2Ma(config);
return twitch2Ma;
})
.then(attachEventHandlers)
.then(twitch2Ma => twitch2Ma.start())
.catch(exitWithError);
Expand Down
3 changes: 3 additions & 0 deletions src/lib/permissions/CooldownPermission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ export default class CooldownPermission implements PermissionInstance {
}
}
}

stop(): void {
}
}
4 changes: 4 additions & 0 deletions src/lib/permissions/ModeratorPermission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import {PermissionCollector, PermissionInstance} from "../PermissionController";
import {RuntimeInformation} from "../RuntimeInformation";

export default class ModeratorPermission implements PermissionInstance {

check(permissionCollector: PermissionCollector, runtimeInformation: RuntimeInformation): void {
if (runtimeInformation.rawMessage.userInfo.isMod) {
permissionCollector.enableGodMode("user is moderator");
}
}

stop(): void {
}
}
4 changes: 4 additions & 0 deletions src/lib/permissions/OwnerPermission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import {PermissionCollector, PermissionController, PermissionInstance} from "../
import {RuntimeInformation} from "../RuntimeInformation";

export default class OwnerPermission implements PermissionInstance {

check(permissionCollector: PermissionCollector, runtimeInformation: RuntimeInformation): void {
if (runtimeInformation.rawMessage.userInfo.userName === runtimeInformation.config.twitch.channel.toLowerCase()) {
permissionCollector.enableGodMode("user is channel owner");
}
}

stop(): void {
}
}
11 changes: 9 additions & 2 deletions src/lib/permissions/SACNPermission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {Receiver, Packet} from "sacn";
export default class SACNPermission implements PermissionInstance {

private readonly universeData: Map<number, Array<number>>;
private readonly sACNReceiver: Receiver;

constructor(config: Config) {
this.universeData = new Map();
Expand All @@ -22,12 +23,12 @@ export default class SACNPermission implements PermissionInstance {
}

if(this.universeData.size > 0) {
let receiver = new Receiver({
this.sACNReceiver = new Receiver({
universes: Array.from(this.universeData.keys()),
reuseAddr: true
});

receiver.on("packet", (packet: Packet) => {
this.sACNReceiver.on("packet", (packet: Packet) => {
let i = 0;
// this.universeData.set(packet.universe, packet.slotsData)
});
Expand All @@ -49,4 +50,10 @@ export default class SACNPermission implements PermissionInstance {
}
}
}

stop(): void {
if(this.sACNReceiver) {
this.sACNReceiver.close();
}
}
}

0 comments on commit 24272bd

Please sign in to comment.