feat: make services gettable and injectable by simple strings and not needing to call Symbol.for every time

This commit is contained in:
Xymorot 2020-08-08 18:23:29 +02:00
parent 6c0456fa0d
commit fc391a02e5
10 changed files with 51 additions and 32 deletions

View File

@ -13,22 +13,22 @@ import { ISession } from './main/modules/session/i-session';
* https://nodejs.org/api/process.html#process_event_unhandledrejection
*/
process.on('unhandledRejection', (reason) => {
const logger: ILogger = container.get(Symbol.for('logger'));
const logger: ILogger = container.get('logger');
void logger.fatal(`Unhandled Rejection, see ${logger.getExceptionsLogFile()}`);
throw reason;
});
process.on('uncaughtException', (error) => {
const logger: ILogger = container.get(Symbol.for('logger'));
const logger: ILogger = container.get('logger');
void logger.exception(error);
throw error;
});
async function createWindow(): Promise<void> {
const session: ISession = container.get(Symbol.for('session'));
const session: ISession = container.get('session');
session.setHeaders();
const appWindowMain: IAppWindow = container.get(Symbol.for('app-window-main'));
const appWindowMain: IAppWindow = container.get('app-window-main');
// and load the index.html of the app.
await appWindowMain.open();
@ -57,7 +57,7 @@ app.on('window-all-closed', () => {
app.on('activate', async () => {
// On OS X it"s common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
const appWindowMain: IAppWindow = container.get(Symbol.for('app-window-main'));
const appWindowMain: IAppWindow = container.get('app-window-main');
if (appWindowMain.isClosed()) {
await createWindow();
}

View File

@ -1,5 +1,5 @@
import 'reflect-metadata';
import { Container } from 'inversify';
import { Container, interfaces } from 'inversify';
import { MainAppWindow } from '../modules/app-window/main-app-window';
import { Logger } from '../modules/logger/logger';
import { NhentaiApi } from '../modules/nhentai/nhentai-api';
@ -7,17 +7,29 @@ import '../modules/nhentai/nhentai-ipc-controller';
import { Session } from '../modules/session/session';
import { Store } from '../modules/store/store';
import { WebCrawler } from '../modules/web-crawler/web-crawler';
import BindingToSyntax = interfaces.BindingToSyntax;
export const container = new Container({ defaultScope: 'Singleton' });
export const container = {
original: new Container({ defaultScope: 'Singleton' }),
bind<T>(key: string): BindingToSyntax<T> {
return this.original.bind<T>(Symbol.for(key));
},
unbind(key: string): void {
return this.original.unbind(Symbol.for(key));
},
get<T>(key: string): T {
return this.original.get<T>(Symbol.for(key));
},
};
container.bind(Symbol.for('store')).to(Store);
container.bind('store').to(Store);
container.bind(Symbol.for('web-crawler')).to(WebCrawler);
container.bind('web-crawler').to(WebCrawler);
container.bind(Symbol.for('nhentai-api')).to(NhentaiApi);
container.bind('nhentai-api').to(NhentaiApi);
container.bind(Symbol.for('app-window-main')).to(MainAppWindow);
container.bind('app-window-main').to(MainAppWindow);
container.bind(Symbol.for('session')).to(Session);
container.bind('session').to(Session);
container.bind(Symbol.for('logger')).to(Logger);
container.bind('logger').to(Logger);

5
src/main/core/inject.ts Normal file
View File

@ -0,0 +1,5 @@
import { inject as inversifyInject } from 'inversify';
export function inject(key: string): ReturnType<typeof inversifyInject> {
return inversifyInject(Symbol.for(key));
}

View File

@ -1,6 +1,6 @@
import { registerHandler } from '../ipc-server';
export function answer(channel: IpcChannel): DecoratorFactory<IIpcController, IpcHandler> {
export function answer(channel: IpcChannel): DecoratorFactory<IIpcController> {
return function (target: IIpcController, propertyKey): void {
registerHandler(channel, target, propertyKey);
};

View File

@ -53,20 +53,20 @@ describe('Logger Service', () => {
});
it('creates log files', () => {
const logger: ILogger = container.get(Symbol.for('logger'));
const logger: ILogger = container.get('logger');
expect(logger.getLogFile()).path('log file is not created');
expect(logger.getExceptionsLogFile()).path('exception log file is not created');
});
it('logs exceptions', async () => {
const logger: ILogger = container.get(Symbol.for('logger'));
const logger: ILogger = container.get('logger');
await logger.exception(new Error('this is an error'));
});
it("default log file doesn't get bigger than 50KB @slow", async () => {
const logger: ILogger = container.get(Symbol.for('logger'));
const logger: ILogger = container.get('logger');
for (let i = 0; i < maxLogSize; i++) {
await logger.log(4, 'your waifu is trash');
@ -77,7 +77,7 @@ describe('Logger Service', () => {
}).timeout(15000);
it("exception log file doesn't get bigger than 50KB @slow", async () => {
const logger: ILogger = container.get(Symbol.for('logger'));
const logger: ILogger = container.get('logger');
for (let i = 0; i < maxLogSize; ++i) {
await logger.exception(new Error('your waifu is trash'));
@ -88,7 +88,7 @@ describe('Logger Service', () => {
}).timeout(15000);
it('logs different levels directly', () => {
const logger: ILogger = container.get(Symbol.for('logger'));
const logger: ILogger = container.get('logger');
return fc.assert(
fc.asyncProperty(logLevelArbitrary as LogLevelArbitrary, fc.string(), async (logLevel, message) => {
@ -104,7 +104,7 @@ describe('Logger Service', () => {
});
it('logs different levels indirectly via the generic log function', () => {
const logger: ILogger = container.get(Symbol.for('logger'));
const logger: ILogger = container.get('logger');
return fc.assert(
fc.asyncProperty(logLevelNumberArbitrary, fc.string(), async (logLevelNumber, message) => {
@ -123,7 +123,7 @@ describe('Logger Service', () => {
});
it('logs debug only in dev mode', async () => {
const logger: ILogger = container.get(Symbol.for('logger'));
const logger: ILogger = container.get('logger');
setDev();
await logger.debug('this is a development message');

View File

@ -1,6 +1,7 @@
import { inject, injectable } from 'inversify';
import { injectable } from 'inversify';
import { JSDOM } from 'jsdom';
import { RequestInit, Response } from 'node-fetch';
import { inject } from '../../core/inject';
import { WebCrawlerFormError } from '../error/web-crawler-form-error';
import { WebCrawlerLoginError } from '../error/web-crawler-login-error';
import { IWebCrawler } from '../web-crawler/i-web-crawler';
@ -33,7 +34,7 @@ interface ILoginParams extends ILoginMeta, ILoginAuth {}
export class NhentaiApi implements INhentaiApi {
private webCrawler: IWebCrawler;
public constructor(@inject(Symbol.for('web-crawler')) webCrawler: IWebCrawler) {
public constructor(@inject('web-crawler') webCrawler: IWebCrawler) {
this.webCrawler = webCrawler;
}

View File

@ -20,7 +20,7 @@ export class NhentaiIpcController implements IIpcController {
}
public get(): NhentaiIpcController {
const nhentaiApi: INhentaiApi = container.get(Symbol.for('nhentai-api'));
const nhentaiApi: INhentaiApi = container.get('nhentai-api');
return new NhentaiIpcController(nhentaiApi);
}
}

View File

@ -18,7 +18,7 @@ describe('Store Service', function () {
});
it('loads saved data', () => {
const store: IStore = container.get(Symbol.for('store'));
const store: IStore = container.get('store');
const testData = {
something: 'gaga',
somethingElse: 0,

View File

@ -17,8 +17,8 @@ describe('Web Crawler', function () {
before(() => {
rewiremock.enable();
container.unbind(Symbol.for('store'));
container.bind(Symbol.for('store')).to(StoreMock);
container.unbind('store');
container.bind('store').to(StoreMock);
});
beforeEach(() => {
@ -34,8 +34,8 @@ describe('Web Crawler', function () {
after(() => {
rewiremock.disable();
container.unbind(Symbol.for('store'));
container.bind(Symbol.for('store')).to(Store);
container.unbind('store');
container.bind('store').to(Store);
});
it('fetches websites', async () => {
@ -54,7 +54,7 @@ describe('Web Crawler', function () {
)
.persist();
const webCrawler: IWebCrawler = container.get(Symbol.for('web-crawler'));
const webCrawler: IWebCrawler = container.get('web-crawler');
const res: Response = await webCrawler.fetch(testUrl);
expect(callback.callCount).to.equal(1, 'multiple requests (or none) are sent when only one should be');

View File

@ -1,6 +1,7 @@
import { inject, injectable } from 'inversify';
import { injectable } from 'inversify';
import { CookieJar } from 'jsdom';
import nodeFetch, { RequestInit, Response } from 'node-fetch';
import { inject } from '../../core/inject';
import { CookieSaveError } from '../error/cookie-save-error';
import { IStore } from '../store/i-store';
import { IWebCrawler } from './i-web-crawler';
@ -13,7 +14,7 @@ export class WebCrawler implements IWebCrawler {
private store: IStore;
public constructor(@inject(Symbol.for('store')) store: IStore) {
public constructor(@inject('store') store: IStore) {
this.initialized = false;
this.cookieJar = new CookieJar();
this.store = store;