Skip to content

Commit

Permalink
simplify clients by loading stuff in constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike Zrimsek committed Jun 23, 2021
1 parent 6f84877 commit ad7cdcb
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 134 deletions.
22 changes: 9 additions & 13 deletions src/clients/discord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,19 @@ import { Client, Message } from 'discord.js';
import { discordConfig, logger } from '../config';

export class DiscordClient {
private client: Client | null = null;
private client: Client;

private async getClient(): Promise<Client> {
if (!this.client) {
this.client = new Client();
this.client.login(discordConfig.token);
constructor() {
this.client = new Client();
this.client.login(discordConfig.token);

this.client.on('ready', () => {
logger.info('Connected to Discord');
logger.info(`Logged in as: ${this.client?.user?.tag} - (${this.client?.user?.id})`);
});
}
return this.client;
this.client.on('ready', () => {
logger.info('Connected to Discord');
logger.info(`Logged in as: ${this.client?.user?.tag} - (${this.client?.user?.id})`);
});
}

async onMessage(messageHandler: (message: Message) => void): Promise<void> {
const client = await this.getClient();
client.on('message', messageHandler);
this.client.on('message', messageHandler);
}
}
51 changes: 22 additions & 29 deletions src/clients/firebase.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as admin from 'firebase-admin';

import { COMMANDS_COLLECTION, WORD_TRACKING_COLLECTION } from '../constants';
import { Command, FirestoreCollection, FirestoreData, TrackedWord } from '../models';
import { Command, TrackedWord } from '../models';
import { firebaseConfig, logger } from '../config';

export class FirestoreClient {
private client: FirestoreData | null = null;
private client: FirebaseFirestore.Firestore;

private getFirestore(): FirebaseFirestore.Firestore {
constructor() {
const firestoreSettings = {
timestampsInSnapshots: true
};
Expand All @@ -21,15 +21,13 @@ export class FirestoreClient {
databaseURL: firebaseConfig.database_url
});

const firestore: FirebaseFirestore.Firestore = admin.firestore();
firestore.settings(firestoreSettings);
return firestore;
this.client = admin.firestore();
this.client.settings(firestoreSettings);

logger.info('Connected to Firestore');
}

private getCollection<DataType>(
firestore: FirebaseFirestore.Firestore,
collection: string
): FirestoreCollection<DataType> {
getCollection<DataType>(collection: string): admin.firestore.CollectionReference<DataType> {
const converter: FirebaseFirestore.FirestoreDataConverter<DataType> = {
toFirestore(concreteType: DataType): FirebaseFirestore.DocumentData {
return concreteType;
Expand All @@ -40,27 +38,22 @@ export class FirestoreClient {
}
};

return firestore.collection(collection).withConverter(converter);
return this.client.collection(collection).withConverter(converter);
}

async getClient(): Promise<FirestoreData> {
if (!this.client) {
const firestore = this.getFirestore();
logger.info('Connected to Firestore');

const commandsCollection = this.getCollection<Command>(firestore, COMMANDS_COLLECTION);
const trackingWordsCollection = this.getCollection<TrackedWord>(
firestore,
WORD_TRACKING_COLLECTION
);

const collections = { commandsCollection, trackingWordsCollection };
async loadUserCommands(): Promise<Command[]> {
const commandsSnapshot = await this.getCollection<Command>(COMMANDS_COLLECTION).get();
logger.info('User commands loaded');
return commandsSnapshot.docs.map((doc: admin.firestore.QueryDocumentSnapshot<Command>) =>
doc.data()
);
}

this.client = {
firestore,
collections
};
}
return this.client;
async loadTrackingPhrases(): Promise<string[]> {
const wordsSnapshot = await this.getCollection<TrackedWord>(WORD_TRACKING_COLLECTION).get();
logger.info('Tracking words loaded');
return wordsSnapshot.docs.map(
(doc: admin.firestore.QueryDocumentSnapshot<TrackedWord>) => doc.id
);
}
}
18 changes: 7 additions & 11 deletions src/clients/mqtt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,16 @@ import * as mqtt from 'mqtt';
import { logger, mqttConfig } from '../config';

export class MqttClient {
private client: mqtt.MqttClient | null = null;
private client: mqtt.MqttClient;

private async getClient(): Promise<mqtt.MqttClient> {
if (!this.client) {
this.client = mqtt.connect(`tcp://${mqttConfig.address}`);
this.client.on('connect', () => {
logger.info('Connected to MQTT Broker');
});
}
return this.client;
constructor() {
this.client = mqtt.connect(`tcp://${mqttConfig.address}`);
this.client.on('connect', () => {
logger.info('Connected to MQTT Broker');
});
}

async publish(topic: string, message: string): Promise<void> {
const client = await this.getClient();
client.publish(topic, message);
this.client.publish(topic, message);
}
}
32 changes: 13 additions & 19 deletions src/clients/obs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,29 @@ import { ObsActionArgs, ObsActionType } from '../models';
import { logger, obsConfig } from '../config';

export class ObsClient {
private client: OBSWebSocket | null = null;
private client: OBSWebSocket;
private obsConnected = false;

private async getClient(): Promise<OBSWebSocket> {
if (!this.client) {
this.client = new OBSWebSocket();
constructor() {
this.client = new OBSWebSocket();

this.client.on('ConnectionOpened', () => {
this.obsConnected = true;
logger.info('Connected to OBSWebSocket');
});
this.client.on('ConnectionClosed', () => {
this.obsConnected = false;
logger.info('Disconnected from OBSWebSocket');
});
}
return this.client;
this.client.on('ConnectionOpened', () => {
this.obsConnected = true;
logger.info('Connected to OBSWebSocket');
});
this.client.on('ConnectionClosed', () => {
this.obsConnected = false;
logger.info('Disconnected from OBSWebSocket');
});
}

async send(
actionType: ObsActionType,
actionSettings: ObsActionArgs[ObsActionType]
): Promise<void> {
const client = await this.getClient();

if (!this.obsConnected) {
await client.connect(obsConfig);
await this.client.connect(obsConfig);
}

client.send(actionType, actionSettings);
this.client.send(actionType, actionSettings);
}
}
38 changes: 16 additions & 22 deletions src/clients/twitch/botChat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,34 @@ import { ChatClient } from 'twitch-chat-client';
import { getRefreshableAuthProvider } from './helpers';

export class TwitchBotChatClient {
private client: ChatClient | null = null;
private client: ChatClient;

private async getClient(): Promise<ChatClient> {
if (!this.client) {
const { channel, botClientId, botClientSecret, botTokensLocation } = twitchConfig;
constructor() {
const { channel, botClientId, botClientSecret, botTokensLocation } = twitchConfig;

const botAuthProvider = getRefreshableAuthProvider(
botClientId,
botClientSecret,
botTokensLocation
);
this.client = new ChatClient(botAuthProvider, {
channels: [channel]
});
this.client.connect();
this.client.onConnect(() => logger.info('Connected to Twitch Chat'));
}
return this.client;
const botAuthProvider = getRefreshableAuthProvider(
botClientId,
botClientSecret,
botTokensLocation
);
this.client = new ChatClient(botAuthProvider, {
channels: [channel]
});
this.client.connect();
this.client.onConnect(() => logger.info('Connected to Twitch Chat'));
}

async onMessage(
messageHandler: (channel: string, user: string, message: string) => void
): Promise<void> {
const client = await this.getClient();
client.onMessage(messageHandler);
this.client.onMessage(messageHandler);
}

async say(channel: string, message: string): Promise<void> {
const client = await this.getClient();
client.say(channel, message);
this.client.say(channel, message);
}

async getMods(channel: string): Promise<string[]> {
const client = await this.getClient();
return client.getMods(channel);
return this.client.getMods(channel);
}
}
40 changes: 0 additions & 40 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import * as OBSWebSocket from 'obs-websocket-js';

import { Command, FirestoreData, TrackedWord } from '../models';
import { logger, obsConfig } from '../config';

import { ApiClient } from 'twitch';
import { COMMAND_SPACER } from '../constants';
import { firestore } from 'firebase-admin';

// Deleting this breaks the bot even though it is not used
// Trying to import it in the OBS redemptions file seems to
Expand All @@ -28,40 +22,6 @@ export function randomlyPadContent(content: string): string {
return `${content}${padding}`;
}

export async function loadUserCommands(firebase: FirestoreData): Promise<Command[]> {
const { collections } = firebase;
const { commandsCollection } = collections;

const commandsSnapshot = await commandsCollection.get();
logger.info('User commands loaded');
return commandsSnapshot.docs.map((doc: firestore.QueryDocumentSnapshot<Command>) => doc.data());
}

export async function loadTrackingPhrases(firebase: FirestoreData): Promise<string[]> {
const { collections } = firebase;
const { trackingWordsCollection } = collections;

const wordsSnapshot = await trackingWordsCollection.get();
logger.info('Tracking words loaded');
return wordsSnapshot.docs.map((doc: firestore.QueryDocumentSnapshot<TrackedWord>) => doc.id);
}

export async function isOBSClientConnected(
obsClient: OBSWebSocket,
obsConnected: boolean
): Promise<boolean> {
if (!obsConnected) {
try {
await obsClient.connect(obsConfig);
return true;
} catch {
logger.info('Unable to connect to OBSWebsocket');
return false;
}
}
return true;
}

export async function isChannelLive(apiClient: ApiClient, channel: string): Promise<boolean> {
const stream = await apiClient.helix.streams.getStreamByUserName(channel);
return stream !== null;
Expand Down

0 comments on commit ad7cdcb

Please sign in to comment.