Browse Source

Convert Seeker to use the Microservice package

dev
David Ludwig 4 years ago
parent
commit
4e00d04627
11 changed files with 55 additions and 191 deletions
  1. +1
    -0
      services/seeker/package.json
  2. +4
    -85
      services/seeker/src/Application.ts
  3. +1
    -1
      services/seeker/src/index.ts
  4. +5
    -5
      services/seeker/src/services/Database.ts
  5. +10
    -3
      services/seeker/src/services/IpcInterface.ts
  6. +10
    -3
      services/seeker/src/services/MovieSearch.ts
  7. +8
    -15
      services/seeker/src/services/PostProcessor/PostProcessor.ts
  8. +0
    -58
      services/seeker/src/services/Service.ts
  9. +7
    -10
      services/seeker/src/services/Supervisor.ts
  10. +4
    -4
      services/seeker/src/services/TorrentManager/TorrentClientIpc.ts
  11. +5
    -7
      services/seeker/src/services/TorrentManager/TorrentManager.ts

+ 1
- 0
services/seeker/package.json View File

@ -22,6 +22,7 @@
},
"dependencies": {
"@autoplex/database": "^0.0.0",
"@autoplex/microservice": "^0.0.0",
"@autoplex/utils": "^0.0.0",
"cheerio": "^1.0.0-rc.6",
"diskusage": "^1.1.3",


+ 4
- 85
services/seeker/src/Application.ts View File

@ -1,104 +1,23 @@
import services from "./services";
import Service from "./services/Service";
import assert from "assert";
interface ServiceMap {
[name: string]: Service
}
import { Microservice } from "@autoplex/microservice";
/**
* The main application class
*/
export default class Application
export default class Application extends Microservice
{
private static __instance: Application;
/**
* All available services
*/
protected services: ServiceMap = {};
/**
* Return the current application instance
*/
public static instance() {
return this.__instance;
}
public static instance() { return super.instance() }
/**
* Create a new application instance
*/
public constructor() {
Application.__instance = this;
super();
for (let ServiceClass of Object.values(services)) {
this.installService(ServiceClass);
}
}
/**
* Install a service into the application
*/
protected installService(ServiceClass: new (app: Application) => Service) {
let service = new ServiceClass(this);
this.services[service.name] = service;
}
/**
* Boot the application and all of the services
*/
protected async boot() {
let services = Object.values(this.services);
return Promise.all(services.map(service => service.boot()));
}
/**
* Initialize the application if necessary
*/
protected async initialize() {
}
/**
* Shutdown the application
*/
protected shutdown() {
let services = Object.values(this.services);
return Promise.all(services.map(service => service.shutdown()));
}
/**
* Start the application
*/
public async start() {
await this.boot();
await this.initialize();
for (let service of Object.values(this.services)) {
service.start();
}
}
/**
* Quit the application
*/
public async quit(code: number = 0) {
await this.shutdown();
process.exit(code);
}
// Access --------------------------------------------------------------------------------------
/**
* Get all available services
*/
public serviceList() {
return Object.keys(this.services);
}
/**
* Get an application service instance
*/
public service<T extends Service>(serviceName: string) {
assert(serviceName in this.services, `Could not find service: ${serviceName}`);
return <T>this.services[serviceName];
}
}

+ 1
- 1
services/seeker/src/index.ts View File

@ -4,4 +4,4 @@ import Application from "./Application";
let app = new Application();
// Start the application
app.start();
app.exec();

+ 5
- 5
services/seeker/src/services/Database.ts View File

@ -1,10 +1,10 @@
import { Connection } from "typeorm";
import connectToDatabase from "@autoplex/database";
import { env, secret } from "@autoplex/utils";
import Service from "./Service";
import { InternalService } from "@autoplex/microservice";
import Application from "../Application";
export default class Database extends Service
export default class Database extends InternalService<Application>
{
/**
* The active database connection
@ -12,10 +12,10 @@ export default class Database extends Service
protected connection!: Connection;
/**
* Create a new database instance
* The service name
*/
public constructor(app: Application) {
super("Database", app);
public get name() {
return "Database";
}
/**


+ 10
- 3
services/seeker/src/services/IpcInterface.ts View File

@ -2,12 +2,12 @@ import { IPC } from "node-ipc";
import { Socket } from "net";
import { mkdir } from "fs/promises";
import { dirname } from "path";
import Service from "./Service";
import { InternalService } from "@autoplex/microservice";
import Application from "../Application";
import Supervisor from "./Supervisor";
import { MovieTicket } from "@autoplex/database";
export default class IpcInterface extends Service
export default class IpcInterface extends InternalService<Application>
{
/**
* The IPC instance
@ -18,13 +18,20 @@ export default class IpcInterface extends Service
* Create a new IPC interface
*/
public constructor(app: Application) {
super("IPC", app);
super(app);
this.__ipc = new IPC();
this.__ipc.config.id = "seeker";
this.__ipc.config.retry = 1500;
this.__ipc.config.silent = true;
}
/**
* The service name
*/
public get name() {
return "IPC"
}
/**
* Boot the IPC interface
*/


+ 10
- 3
services/seeker/src/services/MovieSearch.ts View File

@ -4,10 +4,10 @@ import * as providerClasses from "../torrents";
import Provider, { MediaType } from "../torrents/providers/Provider";
import Torrent from "../torrents/Torrent";
import { rankTorrents } from "../torrents/ranking";
import Service from "./Service";
import { InternalService } from "@autoplex/microservice";
import Supervisor from "./Supervisor";
export default class MovieSearch extends Service
export default class MovieSearch extends InternalService
{
/**
* The queue of current movie tickts requiring torrents
@ -33,11 +33,18 @@ export default class MovieSearch extends Service
* Create a new instance of the movie search service
*/
public constructor(app: Application) {
super("Movie Search", app);
super(app);
this.movieQueue = [];
this.isSearchingForMovies = false;
}
/**
* The service name
*/
public get name() {
return "Movie Search";
}
/**
* Boot the movie search service
*/


+ 8
- 15
services/seeker/src/services/PostProcessor/PostProcessor.ts View File

@ -2,10 +2,10 @@ import { link, mkdir } from "fs/promises";
import { dirname, extname } from "path";
import Application from "../../Application";
import { MovieTicket, MovieTorrent } from "@autoplex/database";
import Service from "../Service";
import { ISerializedTorrent } from "../TorrentManager/TorrentClientIpc";
import { safeTitleFileName } from "../../utils";
import Supervisor from "../Supervisor";
import { InternalService } from "@autoplex/microservice";
/**
* Common video file extensions
@ -23,39 +23,32 @@ interface IPendingMovieTorrent {
ticket : MovieTicket
}
export default class PostProcessor extends Service
export default class PostProcessor extends InternalService<Application>
{
/**
* The queue of movies to process
*/
protected pendingMovies: IPendingMovieTorrent[];
protected pendingMovies: IPendingMovieTorrent[] = [];
/**
* Indicate if movies are currently being processed
*/
protected isProcessingMovies: boolean;
protected isProcessingMovies: boolean = false;
/**
* Create a new instance of the post processor
*/
public constructor(app: Application) {
super("Post Processor", app);
super(app);
this.pendingMovies = [];
this.isProcessingMovies = false;
}
/**
* Boot the post-processor service
* The service name
*/
public async boot() {
}
/**
* Shutdown the post-processor service
*/
public async shutdown() {
public get name() {
return "Post Processor";
}
// Methods -------------------------------------------------------------------------------------


+ 0
- 58
services/seeker/src/services/Service.ts View File

@ -1,58 +0,0 @@
import Application from "../Application";
export default abstract class Service
{
/**
* The name of the service
*/
public readonly name: string;
/**
* The application instance
*/
protected readonly app: Application;
/**
* Enable/disable logging for this service
*/
public logging: boolean = true;
/**
* Create a new service
*/
public constructor(name: string, app: Application) {
this.app = app;
this.name = name;
}
// Required Service Implementation -------------------------------------------------------------
/**
* Boot the service
*/
public abstract boot(): Promise<void>;
/**
* Shut the application down
*/
public abstract shutdown(): Promise<void>;
// Miscellaneous ------------------------------------------------------------------------------
/**
* Indicate the application is ready
*/
public start() {
// no-op
};
/**
* Service-specific logging
*/
public log(...args: any[]) {
if (!this.logging) {
return;
}
console.log(`[${this.name}]:`, ...args);
}
}

+ 7
- 10
services/seeker/src/services/Supervisor.ts View File

@ -2,11 +2,11 @@ import Application from "../Application";
import { MovieTicket, MovieTorrent } from "@autoplex/database";
import MovieSearch from "./MovieSearch";
import PostProcessor from "./PostProcessor";
import Service from "./Service";
import { InternalService } from "@autoplex/microservice";
import TorrentManager from "./TorrentManager";
import { ISerializedTorrent } from "./TorrentManager/TorrentClientIpc";
export default class Supervisor extends Service
export default class Supervisor extends InternalService<Application>
{
/**
@ -28,13 +28,15 @@ export default class Supervisor extends Service
* Create a new supervisor service instance
*/
public constructor(app: Application) {
super("Supervisor", app);
super(app);
}
/**
* Boot the supervisor service
* The service name
*/
public async boot() {}
public get name() {
return "Supervisor";
}
/**
* All services are booted and ready
@ -46,11 +48,6 @@ export default class Supervisor extends Service
this.searchMovies();
}
/**
* Shutdown the supervisor service
*/
public async shutdown() {}
// Request Flow --------------------------------------------------------------------------------
/**


+ 4
- 4
services/seeker/src/services/TorrentManager/TorrentClientIpc.ts View File

@ -1,7 +1,7 @@
import { Socket } from "net";
import Application from "../../Application";
import Service from "../Service";
import ipc = require("node-ipc");
import { InternalService } from "@autoplex/microservice";
interface IResponse {
response?: any,
@ -58,7 +58,7 @@ export class TorrentClientConnectionError extends Error {
/**
* The torrent client IPC service
*/
export default class TorrentClientIpc extends Service
export default abstract class TorrentClientIpc extends InternalService<Application>
{
/**
* Indicate if there is an active connection to the IPC
@ -78,8 +78,8 @@ export default class TorrentClientIpc extends Service
/**
* Create a new IPC client for the torrent client
*/
constructor(name: string, app: Application) {
super(name, app);
constructor(app: Application) {
super(app);
this.__ipc.config.id = "seeker";
this.__ipc.config.retry = 1500;
this.__ipc.config.silent = true;


+ 5
- 7
services/seeker/src/services/TorrentManager/TorrentManager.ts View File

@ -23,12 +23,12 @@ export default class TorrentManager extends TorrentClientIpc
/**
* The queue of movies to add to the client
*/
protected pendingMovies: IPendingMovieTorrent[];
protected pendingMovies: IPendingMovieTorrent[] = [];
/**
* Indicate if the service is currently adding movies to the torrent client
*/
protected isAddingMovies: boolean;
protected isAddingMovies: boolean = false;
/**
* Available movie disk names
@ -36,12 +36,10 @@ export default class TorrentManager extends TorrentClientIpc
protected disks!: IDiskMap;
/**
* Create a new torrent manager instance
* The service name
*/
public constructor(app: Application) {
super("Torrent Manager", app);
this.pendingMovies = [];
this.isAddingMovies = false;
public get name() {
return "Torrent Manager";
}
/**


Loading…
Cancel
Save