From 8cc6f3e83c321a58950047536473e5ecaff84e04 Mon Sep 17 00:00:00 2001 From: David Ludwig Date: Mon, 19 Apr 2021 19:31:25 -0500 Subject: [PATCH] Add Seeker IPC and movie-added notification. Make year nullable again in movie model --- src/server/database/entities/MovieTicket.ts | 5 +- src/server/services/MovieSearch.ts | 1 - src/server/services/SeekerIpc.ts | 134 ++++++++++++++++++++ src/server/services/WebServer/routes/api.ts | 2 + src/server/services/index.ts | 2 + 5 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 src/server/services/SeekerIpc.ts diff --git a/src/server/database/entities/MovieTicket.ts b/src/server/database/entities/MovieTicket.ts index cfb8aeb..75a1603 100644 --- a/src/server/database/entities/MovieTicket.ts +++ b/src/server/database/entities/MovieTicket.ts @@ -16,8 +16,8 @@ export class MovieTicket extends BaseEntity @Column({ type: "varchar" }) title!: string; - @Column({ type: "year" }) - year!: number; + @Column({ type: "year", nullable: true }) + year!: number | null; @CreateDateColumn() createdAt!: Date; @@ -69,6 +69,7 @@ export class MovieTicket extends BaseEntity let ticket = new MovieTicket(); ticket.imdbId = movie.imdb_id; ticket.title = movie.title; + ticket.year = parseInt(movie.release_date.slice(0, 4)); ticket.user = user; ticket.info = info; return await ticket.save(); diff --git a/src/server/services/MovieSearch.ts b/src/server/services/MovieSearch.ts index 6f7f87a..a1821f2 100644 --- a/src/server/services/MovieSearch.ts +++ b/src/server/services/MovieSearch.ts @@ -119,7 +119,6 @@ export default class MovieSearch extends Service */ public async details(id: number) { if (id in this.movieCache) { - console.log("Returning the cached movie"); if (!this.movieCache[id].movie.is_requested) { let isRequested = await MovieInfo.count({tmdbId: id}) > 0; this.movieCache[id].movie.is_requested = isRequested; diff --git a/src/server/services/SeekerIpc.ts b/src/server/services/SeekerIpc.ts new file mode 100644 index 0000000..0a03451 --- /dev/null +++ b/src/server/services/SeekerIpc.ts @@ -0,0 +1,134 @@ +import ipc from "node-ipc"; +import { Socket } from "net"; +import Service from "./Service"; +import Application from "../Application"; +import RawIPC = require("node-ipc"); + +interface IResponse { + response?: any, + error?: string | Error +} + +export default class SeekerIpc extends Service +{ + /** + * Indicate if there is an active connection to the IPC + */ + private __isConnected: boolean; + + /** + * HOLY @#$@% WHOEVER MADE THE TYPES FOR node-ipc SHOULDB BE HANGED + */ + protected ipc; + + /** + * The active IPC socket + */ + protected socket!: Socket; + + /** + * Create a new IPC client for the Seeker + */ + constructor(app: Application) { + super("Seeker IPC", app); + this.ipc = new RawIPC.IPC(); + this.ipc.config.id = "request"; + this.ipc.config.retry = 1500; + this.ipc.config.silent = true; + + this.__isConnected = false; + } + + /** + * Boot the seeker client IPC service + */ + public boot() { + return new Promise((resolve, reject) => { + this.ipc.connectTo("seeker", process.env["SEEKER_IPC_SOCKET"], () => { + this.socket = this.ipc.of["seeker"]; + this.installSocketEventHandlers(this.socket); + this.installSocketMessageHandlers(this.socket); + resolve(); + }); + }); + } + + /** + * Shutdown the seeker IPC service + */ + public async shutdown() { + this.ipc.disconnect("seeker"); + } + + /** + * Install the event handlers for the IPC socket + */ + protected installSocketEventHandlers(socket: Socket) { + socket.on("connect", () => this.onConnect()); + socket.on("error", (error: any) => this.onError(error)); + socket.on("disconnect", () => this.onDisconnect()); + socket.on("destroy", () => this.onDestroy()); + } + + protected installSocketMessageHandlers(socket: Socket) { + } + + // Socket Event Handlers ----------------------------------------------------------------------- + + protected onConnect() { + this.log("Seeker IPC: Connection established"); + this.__isConnected = true; + } + + protected onError(error: string | Error) { + this.log("Seeker IPC: Error occurred:", error); + } + + protected onDisconnect() { + this.log("Seeker IPC: Disconnected"); + this.__isConnected = false; + } + + protected onDestroy() { + this.log("Seeker IPC: Destroyed"); + } + + // Methods ------------------------------------------------------------------------------------- + + /** + * Perform a general request to the Seeker + */ + protected async request(method: string, message?: any) { + return new Promise((resolve, reject) => { + if (!this.isConnected) { + throw new Error("Not connected to Seeker"); + } + let respond = (response: any) => { + clearTimeout(timeout); + resolve(response); + } + // Include timeout mechanism in the off chance something breaks + let timeout = setTimeout(() => { + this.socket.off(method, respond); + reject("Seeker IPC request timeout") + }, 1000); + this.socket.once(method, respond); + this.socket.emit(method, message); + }); + } + + /** + * Notify Seeker that a movie was added + */ + public notifyMovieRequested(ticketId: number) { + this.request("search_movie", ticketId).catch((e) => { + this.log("No response from seeker notifying added movie"); + }); + } + + // Accessors ----------------------------------------------------------------------------------- + + get isConnected() { + return this.__isConnected; + } +} diff --git a/src/server/services/WebServer/routes/api.ts b/src/server/services/WebServer/routes/api.ts index 2a4f254..1ce33cd 100644 --- a/src/server/services/WebServer/routes/api.ts +++ b/src/server/services/WebServer/routes/api.ts @@ -1,4 +1,5 @@ import Application from "@server/Application"; +import SeekerIpc from "@server/services/SeekerIpc"; import MovieSearch from "@server/services/MovieSearch"; import RequestImdbMovieRequest from "../requests/RequestImdbMovieRequest"; import { auth } from "../middleware/auth"; @@ -67,6 +68,7 @@ export default function register(factory: RouteRegisterFactory, app: Application // Create the movie request ticket let user = request.middlewareParams.auth.user; let ticket = await MovieTicket.requestTmdb(user, tmdbId, movieDetails); + app.service("Seeker IPC").notifyMovieRequested(ticket.id); return reply.send({ status: "Success", data: { ticket_id: ticket.id }}); })); diff --git a/src/server/services/index.ts b/src/server/services/index.ts index e232f54..640729e 100644 --- a/src/server/services/index.ts +++ b/src/server/services/index.ts @@ -1,6 +1,7 @@ import Database from "./Database"; import DiscordBot from "./DiscordBot"; import MovieSearch from "./MovieSearch"; +import SeekerIpc from "./SeekerIpc"; import TorrentClientIpc from "./TorrentClientIpc"; import TvDb from "./TvDb"; import WebServer from "./WebServer"; @@ -10,6 +11,7 @@ export default { // DiscordBot, MovieSearch, // TorrentClientIpc, + SeekerIpc, TvDb, WebServer }