Исправлены ошибки сборки проекта
This commit is contained in:
parent
326b97931c
commit
eb16e92a6c
27 changed files with 284 additions and 327 deletions
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
|
|
@ -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}"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
4
libs/event-emitter/src/issues/issues.controller.ts
Normal file
4
libs/event-emitter/src/issues/issues.controller.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import { Controller } from '@nestjs/common';
|
||||
|
||||
@Controller('issues')
|
||||
export class IssuesController {}
|
||||
76
libs/event-emitter/src/issues/issues.service.ts
Normal file
76
libs/event-emitter/src/issues/issues.service.ts
Normal file
|
|
@ -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<number, RedmineTypes.Issue>(
|
||||
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<RedmineTypes.Issue | null> {
|
||||
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<RedmineTypes.Issue | null> {
|
||||
return await this.redmineDataLoader.loadIssue(issueId);
|
||||
}
|
||||
|
||||
async getIssueFromCache(issueId: number): Promise<RedmineTypes.Issue | null> {
|
||||
const issueDb = await this.issues.getDatasource();
|
||||
try {
|
||||
return (await issueDb.get(String(issueId))) as any;
|
||||
} catch (ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
export type Timestamped = {
|
||||
_timestamp: number;
|
||||
timestamp__: number;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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<RedmineTypes.User & Timestamped> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
23
libs/event-emitter/src/users/users.controller.ts
Normal file
23
libs/event-emitter/src/users/users.controller.ts
Normal file
|
|
@ -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<RedmineTypes.User> {
|
||||
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,
|
||||
};
|
||||
}
|
||||
}
|
||||
70
libs/event-emitter/src/users/users.service.ts
Normal file
70
libs/event-emitter/src/users/users.service.ts
Normal file
|
|
@ -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<number, RedmineTypes.User & Timestamped> = {};
|
||||
|
||||
constructor(
|
||||
private users: Users,
|
||||
private redmineDataLoader: RedmineDataLoader,
|
||||
private redmineUserCacheWriterService: RedmineUserCacheWriterService,
|
||||
) {}
|
||||
|
||||
async getUser(userId: number): Promise<RedmineTypes.User> {
|
||||
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<RedmineTypes.User | null> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
48
libs/event-emitter/src/utils/memory-cache.ts
Normal file
48
libs/event-emitter/src/utils/memory-cache.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import { Timestamped } from '../models/timestamped';
|
||||
import { TimestampIsTimeouted } from './timestamp-is-timeouted';
|
||||
import { TimestampNowFill } from './timestamp-now-fill';
|
||||
|
||||
export class MemoryCache<K, T> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
9
libs/event-emitter/src/utils/timestamp-is-timeouted.ts
Normal file
9
libs/event-emitter/src/utils/timestamp-is-timeouted.ts
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -2,7 +2,5 @@ import { Timestamped } from '../models/timestamped';
|
|||
|
||||
export function TimestampNowFill<T>(obj: T): T & Timestamped {
|
||||
const now = new Date().getDate();
|
||||
const res: any = obj;
|
||||
res._timestamp = now;
|
||||
return res;
|
||||
return { ...obj, timestamp__: now };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
export * from './redmine-data-loader.module';
|
||||
export * from './redmine-data-loader.service';
|
||||
|
|
@ -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<RedmineTypes.Issue>
|
||||
>;
|
||||
userDocumentScopeProvider: () => Promise<
|
||||
nano.DocumentScope<RedmineTypes.User>
|
||||
>;
|
||||
}): DynamicModule {
|
||||
return {
|
||||
module: RedmineDataLoaderModule,
|
||||
providers: [
|
||||
RedmineDataLoaderService,
|
||||
{
|
||||
provide: 'ISSUE_DOCUMENT_SCOPE',
|
||||
useValue: params.issueDocumentScopeProvider,
|
||||
},
|
||||
{
|
||||
provide: 'USER_DOCUMENT_SCOPE',
|
||||
useValue: params.userDocumentScopeProvider,
|
||||
},
|
||||
],
|
||||
exports: [RedmineDataLoaderService],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class RedmineDataLoaderService {}
|
||||
|
|
@ -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"]
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
export * from './redmine-issues-cache-writer.module';
|
||||
export * from './redmine-issues-cache-writer.service';
|
||||
|
|
@ -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<RedmineTypes.Issue>
|
||||
>;
|
||||
}): DynamicModule {
|
||||
return {
|
||||
module: RedmineIssuesCacheWriterModule,
|
||||
providers: [
|
||||
RedmineIssuesCacheWriterService,
|
||||
{
|
||||
provide: 'ISSUE_DOCUMENT_SCOPE',
|
||||
useValue: params.issueDocumentScopeProvider,
|
||||
},
|
||||
],
|
||||
exports: [RedmineIssuesCacheWriterService],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -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<SaveResponse>();
|
||||
|
||||
constructor(
|
||||
@Inject('ISSUE_DOCUMENT_SCOPE')
|
||||
private issueDbProvider: () => Promise<
|
||||
nano.DocumentScope<RedmineTypes.Issue>
|
||||
>,
|
||||
) {}
|
||||
|
||||
async saveIssue(issue: RedmineTypes.Issue): Promise<SaveResponse> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import { RedmineTypes } from 'libs/redmine-types';
|
||||
|
||||
export type SaveResponse = {
|
||||
prev: RedmineTypes.Issue | null;
|
||||
current: RedmineTypes.Issue;
|
||||
journalsDiff: RedmineTypes.Journal[];
|
||||
};
|
||||
|
|
@ -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"]
|
||||
}
|
||||
|
|
@ -81,9 +81,7 @@
|
|||
"<rootDir>/libs/"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"^@app/event-emitter(|/.*)$": "<rootDir>/libs/event-emitter/src/$1",
|
||||
"^@app/redmine-issues-cache-writer(|/.*)$": "<rootDir>/libs/redmine-issues-cache-writer/src/$1",
|
||||
"^@app/redmine-data-loader(|/.*)$": "<rootDir>/libs/redmine-data-loader/src/$1"
|
||||
"^@app/event-emitter(|/.*)$": "<rootDir>/libs/event-emitter/src/$1"
|
||||
}
|
||||
},
|
||||
"workspaces": [
|
||||
|
|
|
|||
|
|
@ -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 {}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<RedmineTypes.Issue>
|
||||
> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<nano.DocumentScope<RedmineTypes.User>> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue