diff --git a/.vscode/launch.json b/.vscode/launch.json index 5b64f53..ba43061 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,10 +8,10 @@ "type": "node", "request": "launch", "name": "Launch Program", - "runtimeExecutable": "yarn", + "runtimeExecutable": "npm", "console": "integratedTerminal", "runtimeArgs": [ - "start:debug" + "run", "start:debug" ], "cwd": "${workspaceFolder}" } diff --git a/libs/event-emitter/src/event-emitter.module.ts b/libs/event-emitter/src/event-emitter.module.ts index 29e6448..fbdef49 100644 --- a/libs/event-emitter/src/event-emitter.module.ts +++ b/libs/event-emitter/src/event-emitter.module.ts @@ -13,6 +13,7 @@ import { CouchDb } from './couchdb-datasources/couchdb'; import { Users } from './couchdb-datasources/users'; import { Issues } from './couchdb-datasources/issues'; import { RedmineTypes } from '@app/redmine-types/index'; +import { RedmineUserCacheWriterService } from './user-cache-writer/user-cache-writer.service'; @Module({}) export class EventEmitterModule implements OnModuleInit { @@ -33,6 +34,7 @@ export class EventEmitterModule implements OnModuleInit { CouchDb, Users, Issues, + RedmineUserCacheWriterService, ], exports: [ EventEmitterService, @@ -42,6 +44,7 @@ export class EventEmitterModule implements OnModuleInit { CouchDb, Users, Issues, + RedmineUserCacheWriterService, ], controllers: [MainController], }; diff --git a/libs/event-emitter/src/issue-cache-writer/redmine-issues-cache-writer.service.ts b/libs/event-emitter/src/issue-cache-writer/redmine-issues-cache-writer.service.ts index 8e97718..7f205a9 100644 --- a/libs/event-emitter/src/issue-cache-writer/redmine-issues-cache-writer.service.ts +++ b/libs/event-emitter/src/issue-cache-writer/redmine-issues-cache-writer.service.ts @@ -4,6 +4,8 @@ import nano from 'nano'; import { Subject } from 'rxjs'; import { Issues } from '../couchdb-datasources/issues'; import { SaveResponse } from '../models/save-response'; +import { Timestamped } from '../models/timestamped'; +import { TimestampNowFill } from '../utils/timestamp-now-fill'; @Injectable() export class RedmineIssuesCacheWriterService { @@ -23,24 +25,21 @@ export class RedmineIssuesCacheWriterService { let prevIssue: (nano.DocumentGetResponse & RedmineTypes.Issue) | null; const issueDb = await Issues.getDatasource(); if (!issueDb) { - console.error(`CouchDb datasource must defined`); + throw `CouchDb datasource must defined`; } try { prevIssue = await issueDb.get(String(id)); } catch (ex) { prevIssue = null; } - let newIssue: nano.DocumentGetResponse & RedmineTypes.Issue; - if (!prevIssue) { - newIssue = { ...(issue as any) }; - newIssue._id = String(id); - await issueDb.insert(newIssue); - } else { - newIssue = { ...(issue as any) }; - newIssue._id = String(id); + const newIssue: nano.DocumentGetResponse & + RedmineTypes.Issue & + Timestamped = TimestampNowFill({ ...(issue as any) }); + newIssue._id = String(id); + if (prevIssue) { newIssue._rev = prevIssue._rev; - await issueDb.insert(newIssue); } + await issueDb.insert(newIssue); const res = { prev: prevIssue, current: newIssue, diff --git a/libs/event-emitter/src/issues/issues.controller.ts b/libs/event-emitter/src/issues/issues.controller.ts new file mode 100644 index 0000000..f443873 --- /dev/null +++ b/libs/event-emitter/src/issues/issues.controller.ts @@ -0,0 +1,4 @@ +import { Controller } from '@nestjs/common'; + +@Controller('issues') +export class IssuesController {} diff --git a/libs/event-emitter/src/issues/issues.service.ts b/libs/event-emitter/src/issues/issues.service.ts new file mode 100644 index 0000000..c442bbb --- /dev/null +++ b/libs/event-emitter/src/issues/issues.service.ts @@ -0,0 +1,76 @@ +import { RedmineTypes } from '@app/redmine-types/index'; +import { Injectable } from '@nestjs/common'; +import { Issues } from '../couchdb-datasources/issues'; +import { RedmineEventsGateway } from '../events/redmine-events.gateway'; +import { RedmineIssuesCacheWriterService } from '../issue-cache-writer/redmine-issues-cache-writer.service'; +import { RedmineDataLoader } from '../redmine-data-loader/redmine-data-loader'; +import { MemoryCache } from '../utils/memory-cache'; + +export const ISSUE_MEMORY_CACHE_LIFETIME = 30 * 1000; +const ISSUE_MEMORY_CACHE_AUTOCLEAN_INTERVAL = 1000 * 60 * 5; + +@Injectable() +export class IssuesService { + private memoryCache = new MemoryCache( + ISSUE_MEMORY_CACHE_LIFETIME, + ISSUE_MEMORY_CACHE_AUTOCLEAN_INTERVAL, + ); + + constructor( + private redmineDataLoader: RedmineDataLoader, + private issues: Issues, + private redmineIssuesCacheWriterService: RedmineIssuesCacheWriterService, + private redmineEventsGateway: RedmineEventsGateway, + ) {} + + async getIssue( + issueId: number, + force = false, + ): Promise { + const issueFromMemoryCache = this.getIssueFromMemoryCache(issueId); + if (issueFromMemoryCache) { + return issueFromMemoryCache; + } + const issueFromCache = await this.getIssueFromCache(issueId); + if (issueFromCache) { + this.memoryCache.set(issueId, issueFromCache); + return issueFromCache; + } + if (force) { + // force = true - прямо из redmine + const issueFromRedmine = await this.redmineDataLoader.loadIssue(issueId); + if (issueFromRedmine) { + await this.redmineIssuesCacheWriterService.saveIssue(issueFromRedmine); + this.memoryCache.set(issueId, issueFromRedmine); + return issueFromRedmine; + } else { + return null; + } + } else { + // force = false - через очередь + this.redmineEventsGateway.addIssues([issueId]); + const unknownIssue = { ...RedmineTypes.Unknown.issue }; + this.memoryCache.set(issueId, unknownIssue); + return unknownIssue; + } + } + + getIssueFromMemoryCache(issueId: number): RedmineTypes.Issue | null { + return this.memoryCache.get(issueId); + } + + async getIssueFromRedmine( + issueId: number, + ): Promise { + return await this.redmineDataLoader.loadIssue(issueId); + } + + async getIssueFromCache(issueId: number): Promise { + const issueDb = await this.issues.getDatasource(); + try { + return (await issueDb.get(String(issueId))) as any; + } catch (ex) { + return null; + } + } +} diff --git a/libs/event-emitter/src/models/timestamped.ts b/libs/event-emitter/src/models/timestamped.ts index 48256f8..10602e0 100644 --- a/libs/event-emitter/src/models/timestamped.ts +++ b/libs/event-emitter/src/models/timestamped.ts @@ -1,3 +1,3 @@ export type Timestamped = { - _timestamp: number; + timestamp__: number; }; diff --git a/libs/event-emitter/src/user-cache-writer/user-cache-writer.service.ts b/libs/event-emitter/src/user-cache-writer/user-cache-writer.service.ts new file mode 100644 index 0000000..93f2793 --- /dev/null +++ b/libs/event-emitter/src/user-cache-writer/user-cache-writer.service.ts @@ -0,0 +1,34 @@ +import { RedmineTypes } from '@app/redmine-types/index'; +import { Injectable, Logger } from '@nestjs/common'; +import { Users } from '../couchdb-datasources/users'; +import nano from 'nano'; +import { Timestamped } from '../models/timestamped'; +import { TimestampNowFill } from '../utils/timestamp-now-fill'; + +@Injectable() +export class RedmineUserCacheWriterService { + private logger = new Logger(RedmineUserCacheWriterService.name); + + constructor(private users: Users) {} + + async saveUser( + user: RedmineTypes.User, + ): Promise { + this.logger.debug(`Saving user ${user.id} - ${user.login}`); + const id = user.id; + const userDb = await this.users.getDatasource(); + let prevUser: (nano.DocumentGetResponse & RedmineTypes.User) | null; + try { + prevUser = await userDb.get(String(id)); + } catch (ex) { + prevUser = null; + } + const newUser: nano.DocumentGetResponse & RedmineTypes.User & Timestamped = + TimestampNowFill({ ...(user as any) }); + if (prevUser) { + newUser._rev = prevUser._rev; + } + await userDb.insert(newUser); + return newUser; + } +} diff --git a/libs/event-emitter/src/users/users.controller.ts b/libs/event-emitter/src/users/users.controller.ts new file mode 100644 index 0000000..0451415 --- /dev/null +++ b/libs/event-emitter/src/users/users.controller.ts @@ -0,0 +1,23 @@ +import { RedmineTypes } from '@app/redmine-types/index'; +import { Controller, Get, Param } from '@nestjs/common'; +import { UsersService } from './users.service'; + +@Controller('users') +export class UsersController { + constructor(private readonly usersService: UsersService) {} + + @Get(':id') + async getUser(@Param('id') id: number): Promise { + return await this.usersService.getUser(id); + } + + @Get(':id.json') + async getUserLikeRedmine( + @Param('id') id: number, + ): Promise<{ user: RedmineTypes.User }> { + const user = await this.usersService.getUser(id); + return { + user: user, + }; + } +} diff --git a/libs/event-emitter/src/users/users.service.ts b/libs/event-emitter/src/users/users.service.ts new file mode 100644 index 0000000..85203cc --- /dev/null +++ b/libs/event-emitter/src/users/users.service.ts @@ -0,0 +1,70 @@ +import { Injectable } from '@nestjs/common'; +import { RedmineTypes } from '@app/redmine-types/index'; +import { Timestamped } from '../models/timestamped'; +import { Users } from '../couchdb-datasources/users'; +import { RedmineDataLoader } from '../redmine-data-loader/redmine-data-loader'; +import { TimestampNowFill } from '../utils/timestamp-now-fill'; +import { RedmineUserCacheWriterService } from '../user-cache-writer/user-cache-writer.service'; +import { TimestampIsTimeouted } from '../utils/timestamp-is-timeouted'; + +export const USER_MEMORY_CACHE_LIFETIME = 24 * 60 * 60 * 1000; + +@Injectable() +export class UsersService { + private memoryCache: Record = {}; + + constructor( + private users: Users, + private redmineDataLoader: RedmineDataLoader, + private redmineUserCacheWriterService: RedmineUserCacheWriterService, + ) {} + + async getUser(userId: number): Promise { + const userFromMemoryCache = this.getUserFromMemoryCache(userId); + if (userFromMemoryCache) { + return userFromMemoryCache; + } + const userFromCache = await this.getUserFromCache(userId); + if (userFromCache) { + this.memoryCache[userId] = TimestampNowFill({ ...userFromCache }); + return this.memoryCache[userId]; + } + let userFromRedmine = await this.getUserFromRedmine(userId); + if (userFromRedmine) { + userFromRedmine = await this.redmineUserCacheWriterService.saveUser( + userFromRedmine, + ); + } + const unknownUser = TimestampNowFill({ ...RedmineTypes.Unknown.user }); + this.memoryCache[userId] = (userFromRedmine || unknownUser) as any; + return this.memoryCache[userId]; + } + + async getUserFromRedmine(userId: number): Promise { + return await this.redmineDataLoader.loadUser(userId); + } + + async getUserFromCache( + userId: number, + ): Promise<(RedmineTypes.User & Timestamped) | null> { + const usersDb = await this.users.getDatasource(); + try { + return (await usersDb.get(String(userId))) as any; + } catch (ex) { + return null; + } + } + + getUserFromMemoryCache(userId: number): RedmineTypes.User | null { + if ( + this.memoryCache[userId] && + !TimestampIsTimeouted( + this.memoryCache[userId], + USER_MEMORY_CACHE_LIFETIME, + ) + ) { + return this.memoryCache[userId]; + } + return null; + } +} diff --git a/libs/event-emitter/src/utils/memory-cache.ts b/libs/event-emitter/src/utils/memory-cache.ts new file mode 100644 index 0000000..59c5fb6 --- /dev/null +++ b/libs/event-emitter/src/utils/memory-cache.ts @@ -0,0 +1,48 @@ +import { Timestamped } from '../models/timestamped'; +import { TimestampIsTimeouted } from './timestamp-is-timeouted'; +import { TimestampNowFill } from './timestamp-now-fill'; + +export class MemoryCache { + private memoryCache = {}; + + constructor(private timeout: number, private autoclean: number = 0) { + if (autoclean > 0) { + this.startAutoclean(); + } + } + + get(key: K): T | null { + const k = key as any; + if (this.memoryCache[k]) { + if (TimestampIsTimeouted(this.memoryCache[k], this.timeout)) { + delete this.memoryCache[k]; + return null; + } + return this.memoryCache[k]; + } + return null; + } + + set(key: K, value: T): T & Timestamped { + this.memoryCache[key as any] = TimestampNowFill({ ...value }); + return this.memoryCache[key as any]; + } + + cleanTimeouted(): void { + for (const key in this.memoryCache) { + if (Object.prototype.hasOwnProperty.call(this.memoryCache, key)) { + const item = this.memoryCache[key]; + if (TimestampIsTimeouted(item, this.timeout)) { + delete this.memoryCache[key]; + } + } + } + } + + private startAutoclean() { + setTimeout(() => { + this.cleanTimeouted(); + this.startAutoclean(); + }, this.autoclean); + } +} diff --git a/libs/event-emitter/src/utils/timestamp-is-timeouted.ts b/libs/event-emitter/src/utils/timestamp-is-timeouted.ts new file mode 100644 index 0000000..dd07e17 --- /dev/null +++ b/libs/event-emitter/src/utils/timestamp-is-timeouted.ts @@ -0,0 +1,9 @@ +import { Timestamped } from '../models/timestamped'; + +export function TimestampIsTimeouted( + obj: Timestamped, + timeout: number, +): boolean { + const now = new Date().getDate(); + return obj.timestamp__ < now - timeout; +} diff --git a/libs/event-emitter/src/utils/timestamp-now-fill.ts b/libs/event-emitter/src/utils/timestamp-now-fill.ts index f1333b2..2b14705 100644 --- a/libs/event-emitter/src/utils/timestamp-now-fill.ts +++ b/libs/event-emitter/src/utils/timestamp-now-fill.ts @@ -2,7 +2,5 @@ import { Timestamped } from '../models/timestamped'; export function TimestampNowFill(obj: T): T & Timestamped { const now = new Date().getDate(); - const res: any = obj; - res._timestamp = now; - return res; + return { ...obj, timestamp__: now }; } diff --git a/libs/redmine-data-loader/src/index.ts b/libs/redmine-data-loader/src/index.ts deleted file mode 100644 index e59bee4..0000000 --- a/libs/redmine-data-loader/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './redmine-data-loader.module'; -export * from './redmine-data-loader.service'; diff --git a/libs/redmine-data-loader/src/redmine-data-loader.module.ts b/libs/redmine-data-loader/src/redmine-data-loader.module.ts deleted file mode 100644 index 3a6ade6..0000000 --- a/libs/redmine-data-loader/src/redmine-data-loader.module.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { RedmineTypes } from '@app/redmine-types/index'; -import { DynamicModule, Module } from '@nestjs/common'; -import nano from 'nano'; -import { RedmineDataLoaderService } from './redmine-data-loader.service'; - -@Module({}) -export class RedmineDataLoaderModule { - static register(params: { - issueDocumentScopeProvider: () => Promise< - nano.DocumentScope - >; - userDocumentScopeProvider: () => Promise< - nano.DocumentScope - >; - }): DynamicModule { - return { - module: RedmineDataLoaderModule, - providers: [ - RedmineDataLoaderService, - { - provide: 'ISSUE_DOCUMENT_SCOPE', - useValue: params.issueDocumentScopeProvider, - }, - { - provide: 'USER_DOCUMENT_SCOPE', - useValue: params.userDocumentScopeProvider, - }, - ], - exports: [RedmineDataLoaderService], - }; - } -} diff --git a/libs/redmine-data-loader/src/redmine-data-loader.service.ts b/libs/redmine-data-loader/src/redmine-data-loader.service.ts deleted file mode 100644 index 2c41a71..0000000 --- a/libs/redmine-data-loader/src/redmine-data-loader.service.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -@Injectable() -export class RedmineDataLoaderService {} diff --git a/libs/redmine-data-loader/tsconfig.lib.json b/libs/redmine-data-loader/tsconfig.lib.json deleted file mode 100644 index a29bb5d..0000000 --- a/libs/redmine-data-loader/tsconfig.lib.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "declaration": true, - "outDir": "../../dist/libs/redmine-data-loader" - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] -} diff --git a/libs/redmine-issues-cache-writer/src/index.ts b/libs/redmine-issues-cache-writer/src/index.ts deleted file mode 100644 index b210d7b..0000000 --- a/libs/redmine-issues-cache-writer/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './redmine-issues-cache-writer.module'; -export * from './redmine-issues-cache-writer.service'; diff --git a/libs/redmine-issues-cache-writer/src/redmine-issues-cache-writer.module.ts b/libs/redmine-issues-cache-writer/src/redmine-issues-cache-writer.module.ts deleted file mode 100644 index d5bae9b..0000000 --- a/libs/redmine-issues-cache-writer/src/redmine-issues-cache-writer.module.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { DynamicModule, Module } from '@nestjs/common'; -import { RedmineIssuesCacheWriterService } from './redmine-issues-cache-writer.service'; -import nano = require('nano'); -import { RedmineTypes } from 'libs/redmine-types'; - -@Module({}) -export class RedmineIssuesCacheWriterModule { - static register(params: { - issueDocumentScopeProvider: () => Promise< - nano.DocumentScope - >; - }): DynamicModule { - return { - module: RedmineIssuesCacheWriterModule, - providers: [ - RedmineIssuesCacheWriterService, - { - provide: 'ISSUE_DOCUMENT_SCOPE', - useValue: params.issueDocumentScopeProvider, - }, - ], - exports: [RedmineIssuesCacheWriterService], - }; - } -} diff --git a/libs/redmine-issues-cache-writer/src/redmine-issues-cache-writer.service.ts b/libs/redmine-issues-cache-writer/src/redmine-issues-cache-writer.service.ts deleted file mode 100644 index dcd4cb8..0000000 --- a/libs/redmine-issues-cache-writer/src/redmine-issues-cache-writer.service.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { Inject, Injectable, Logger } from '@nestjs/common'; -import { RedmineTypes } from 'libs/redmine-types'; -import nano from 'nano'; -import { Subject } from 'rxjs'; -import { SaveResponse } from './save-response'; - -@Injectable() -export class RedmineIssuesCacheWriterService { - private logger = new Logger(RedmineIssuesCacheWriterService.name); - - subject = new Subject(); - - constructor( - @Inject('ISSUE_DOCUMENT_SCOPE') - private issueDbProvider: () => Promise< - nano.DocumentScope - >, - ) {} - - async saveIssue(issue: RedmineTypes.Issue): Promise { - this.logger.debug( - `Saving issue ${issue?.id || '-'} - ${ - issue?.subject || '-' - }, issue data = ${JSON.stringify(issue)}`, - ); - const id = Number(issue['id']); - let prevIssue: (nano.DocumentGetResponse & RedmineTypes.Issue) | null; - const issueDb = await this.issueDbProvider(); - try { - prevIssue = await issueDb.get(String(id)); - } catch (ex) { - prevIssue = null; - } - let newIssue: nano.DocumentGetResponse & RedmineTypes.Issue; - if (!prevIssue) { - newIssue = { ...(issue as any) }; - newIssue._id = String(id); - await issueDb.insert(newIssue); - } else { - newIssue = { ...(issue as any) }; - newIssue._id = String(id); - newIssue._rev = prevIssue._rev; - await issueDb.insert(newIssue); - } - const res = { - prev: prevIssue, - current: newIssue, - journalsDiff: this.getJournalsDiff(prevIssue, newIssue), - }; - this.logger.debug( - `Saving issue success ${issue?.id || '-'} - ${issue?.subject || '-'}`, - ); - this.subject.next(res); - return res; - } - - getJournalsDiff( - prev: (nano.DocumentGetResponse & RedmineTypes.Issue) | null, - current: nano.DocumentGetResponse & RedmineTypes.Issue, - ): RedmineTypes.Journal[] { - if ( - (!prev || !prev.journals || prev.journals.length === 0) && - current?.journals - ) { - return current.journals; - } else if (prev?.journals && current?.journals) { - return this.calcJournalsDiff(prev?.journals, current?.journals); - } - return []; - } - - private calcJournalsDiff( - prev: RedmineTypes.Journal[], - current: RedmineTypes.Journal[], - ): RedmineTypes.Journal[] { - const res: RedmineTypes.Journal[] = []; - - const prevIds = prev.map((item) => item.id); - - for (let i = 0; i < current.length; i++) { - const currentItem = current[i]; - if (!prevIds.includes(currentItem.id)) { - res.push(currentItem); - } - } - return res; - } -} diff --git a/libs/redmine-issues-cache-writer/src/save-response.ts b/libs/redmine-issues-cache-writer/src/save-response.ts deleted file mode 100644 index fedc9c4..0000000 --- a/libs/redmine-issues-cache-writer/src/save-response.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { RedmineTypes } from 'libs/redmine-types'; - -export type SaveResponse = { - prev: RedmineTypes.Issue | null; - current: RedmineTypes.Issue; - journalsDiff: RedmineTypes.Journal[]; -}; diff --git a/libs/redmine-issues-cache-writer/tsconfig.lib.json b/libs/redmine-issues-cache-writer/tsconfig.lib.json deleted file mode 100644 index 1c4b1db..0000000 --- a/libs/redmine-issues-cache-writer/tsconfig.lib.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "declaration": true, - "outDir": "../../dist/libs/redmine-issues-cache-writer" - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] -} diff --git a/package.json b/package.json index e1e5bea..3a39561 100644 --- a/package.json +++ b/package.json @@ -81,9 +81,7 @@ "/libs/" ], "moduleNameMapper": { - "^@app/event-emitter(|/.*)$": "/libs/event-emitter/src/$1", - "^@app/redmine-issues-cache-writer(|/.*)$": "/libs/redmine-issues-cache-writer/src/$1", - "^@app/redmine-data-loader(|/.*)$": "/libs/redmine-data-loader/src/$1" + "^@app/event-emitter(|/.*)$": "/libs/event-emitter/src/$1" } }, "workspaces": [ diff --git a/src/app.module.ts b/src/app.module.ts index 45ad32d..30b982f 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,14 +1,10 @@ import { EventEmitterModule } from '@app/event-emitter'; import { MainController } from '@app/event-emitter/main/main.controller'; -import { Logger, Module, OnModuleInit } from '@nestjs/common'; +import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { AppController } from './app.controller'; import { AppService } from './app.service'; -import { Issues } from './datasources/issues'; import configuration from './configs/app'; -import { RedmineEventsGateway } from '@app/event-emitter/events/redmine-events.gateway'; -import { CouchDb } from './datasources/couchdb'; -import { Users } from './datasources/users'; @Module({ imports: [ @@ -18,40 +14,6 @@ import { Users } from './datasources/users'; ConfigModule.forRoot({ load: [configuration] }), ], controllers: [AppController, MainController], - providers: [AppService, Issues, CouchDb, Users], + providers: [AppService], }) -export class AppModule implements OnModuleInit { - private logger = new Logger(AppModule.name); - - constructor(private redmineEventsGateway: RedmineEventsGateway) {} - - onModuleInit() { - // const queue = this.redmineEventsGateway.getIssuesChangesQueue(); - // const subj = queue.queue; - // subj.subscribe(async (issues: any) => { - // this.logger.debug(`Changed issues = ${JSON.stringify(issues)}`); - // - // for (let i = 0; i < issues.length; i++) { - // const issue: RedmineTypes.Issue = issues[i]; - // - // try { - // this.logger.debug( - // `Save issue #${issue.id} - ${JSON.stringify(issue)}`, - // ); - // - // const response = await this.redmineIssuesCacheWriterService.saveIssue( - // issue, - // ); - // - // this.logger.debug( - // `Save issue #${issue.id} response = ${JSON.stringify(response)}`, - // ); - // } catch (ex) { - // this.logger.error(`Saving issue error - ${ex}`, null, { - // issue: issue, - // }); - // } - // } - // }); - } -} +export class AppModule {} diff --git a/src/datasources/couchdb.ts b/src/datasources/couchdb.ts deleted file mode 100644 index ec31d6a..0000000 --- a/src/datasources/couchdb.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Injectable, Logger } from '@nestjs/common'; -import * as nano from 'nano'; -import configuration from '../configs/app'; - -const config = configuration(); - -@Injectable() -export class CouchDb { - private static logger = new Logger(CouchDb.name); - private static couchdb: nano.ServerScope | null = null; - - static getCouchDb(): nano.ServerScope { - if (CouchDb.couchdb) { - return CouchDb.couchdb; - } - const n = nano(config.couchDbUrl); - CouchDb.logger.log(`CouchDb connected by url ${config.couchDbUrl} ...`); - CouchDb.couchdb = n; - return CouchDb.couchdb; - } -} diff --git a/src/datasources/issues.ts b/src/datasources/issues.ts deleted file mode 100644 index 126ef1d..0000000 --- a/src/datasources/issues.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { RedmineTypes } from '@app/redmine-types/index'; -import { Injectable, Logger } from '@nestjs/common'; -import configuration from '../configs/app'; -import nano = require('nano'); -import { CouchDb } from './couchdb'; - -const config = configuration(); - -@Injectable() -export class Issues { - private static logger = new Logger(Issues.name); - private static issuesDb = null; - - static async getDatasource(): Promise< - nano.DocumentScope - > { - if (Issues.issuesDb) { - return Issues.issuesDb; - } - const n = CouchDb.getCouchDb(); - const dbs = await n.db.list(); - if (!dbs.includes(config.dbs.issues)) { - await n.db.create(config.dbs.issues); - } - Issues.issuesDb = await n.db.use(config.dbs.issues); - Issues.logger.log(`Connected to issues db - ${config.dbs.issues}`); - return Issues.issuesDb; - } -} diff --git a/src/datasources/users.ts b/src/datasources/users.ts deleted file mode 100644 index 1f2fc2b..0000000 --- a/src/datasources/users.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { RedmineTypes } from '@app/redmine-types/index'; -import { Injectable, Logger } from '@nestjs/common'; -import nano from 'nano'; -import { CouchDb } from './couchdb'; -import configuration from '../configs/app'; - -const config = configuration(); - -@Injectable() -export class Users { - private static logger = new Logger(Users.name); - private static usersDb = null; - - static async getDatasource(): Promise> { - if (Users.usersDb) { - return Users.usersDb; - } - const n = CouchDb.getCouchDb(); - const dbs = await n.db.list(); - if (!dbs.includes(config.dbs.users)) { - await n.db.create(config.dbs.users); - } - Users.usersDb = await n.db.use(config.dbs.users); - Users.logger.log(`Connected to users db - ${config.dbs.users}`); - return Users.usersDb; - } -} diff --git a/tsconfig.json b/tsconfig.json index bb172b6..721f1db 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,20 +24,8 @@ "@app/event-emitter/*": [ "libs/event-emitter/src/*" ], - "@app/redmine-issues-cache-writer": [ - "libs/redmine-issues-cache-writer/src" - ], - "@app/redmine-issues-cache-writer/*": [ - "libs/redmine-issues-cache-writer/src/*" - ], "@app/redmine-types/*": [ "libs/redmine-types/*" - ], - "@app/redmine-data-loader": [ - "libs/redmine-data-loader/src" - ], - "@app/redmine-data-loader/*": [ - "libs/redmine-data-loader/src/*" ] } }