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 7f205a9..0c38f2b 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
@@ -1,5 +1,5 @@
import { Injectable, Logger } from '@nestjs/common';
-import { RedmineTypes } from 'libs/redmine-types';
+import { RedmineTypes } from '../models/redmine-types';
import nano from 'nano';
import { Subject } from 'rxjs';
import { Issues } from '../couchdb-datasources/issues';
diff --git a/libs/event-emitter/src/models/redmine-types/index.d.ts b/libs/event-emitter/src/models/redmine-types.ts
similarity index 87%
rename from libs/event-emitter/src/models/redmine-types/index.d.ts
rename to libs/event-emitter/src/models/redmine-types.ts
index a904d28..09c3587 100644
--- a/libs/event-emitter/src/models/redmine-types/index.d.ts
+++ b/libs/event-emitter/src/models/redmine-types.ts
@@ -1,6 +1,4 @@
-///
-
-// eslint-disable-next-line @typescript-eslint/prefer-namespace-keyword
+// eslint-disable-next-line @typescript-eslint/prefer-namespace-keyword, @typescript-eslint/no-namespace
export module RedmineTypes {
export type IdAndName = {
id: number;
@@ -51,7 +49,7 @@ export module RedmineTypes {
journals?: Journal[];
};
- // eslint-disable-next-line @typescript-eslint/prefer-namespace-keyword
+ // eslint-disable-next-line @typescript-eslint/prefer-namespace-keyword, @typescript-eslint/no-namespace
export module Unknown {
export const num = -1;
export const str = '';
@@ -83,6 +81,7 @@ export module RedmineTypes {
export const user: User = {
id: num,
+ login: unknownName,
firstname: unknownName,
lastname: unknownName,
mail: str,
@@ -96,4 +95,14 @@ export module RedmineTypes {
lastname: string;
mail: string;
};
+
+ export function ExtractUser(obj: User): User {
+ return {
+ id: obj.id,
+ login: obj.login,
+ firstname: obj.firstname,
+ lastname: obj.lastname,
+ mail: obj.mail,
+ };
+ }
}
diff --git a/libs/event-emitter/src/models/redmine-types/index.js b/libs/event-emitter/src/models/redmine-types/index.js
deleted file mode 100644
index e69de29..0000000
diff --git a/libs/event-emitter/src/models/redmine-types/package.json b/libs/event-emitter/src/models/redmine-types/package.json
deleted file mode 100644
index 4df9704..0000000
--- a/libs/event-emitter/src/models/redmine-types/package.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "redmine-types",
- "version": "0.1.0",
- "description": "",
- "main": "index.js",
- "types": "index.d.ts",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "author": "Pavel Gnedov",
- "license": "MIT"
-}
diff --git a/libs/event-emitter/src/models/save-response.ts b/libs/event-emitter/src/models/save-response.ts
index 91f2d05..d43c4f6 100644
--- a/libs/event-emitter/src/models/save-response.ts
+++ b/libs/event-emitter/src/models/save-response.ts
@@ -1,4 +1,4 @@
-import { RedmineTypes } from 'libs/redmine-types';
+import { RedmineTypes } from './redmine-types';
// TODO: Переименовать в IssueCacheSaveResponse
diff --git a/libs/event-emitter/src/redmine-data-loader/redmine-data-loader.ts b/libs/event-emitter/src/redmine-data-loader/redmine-data-loader.ts
index dcbca96..f116783 100644
--- a/libs/event-emitter/src/redmine-data-loader/redmine-data-loader.ts
+++ b/libs/event-emitter/src/redmine-data-loader/redmine-data-loader.ts
@@ -51,7 +51,7 @@ export class RedmineDataLoader {
this.logger.debug(
`Loaded user, userNumber = ${userNumber}, login = ${user.login}, firstname = ${user.firstname}, lastname = ${user.lastname}`,
);
- return user;
+ return RedmineTypes.ExtractUser(user);
}
private getIssueUrl(issueNumber: number): string {
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
index 14157d7..3615d6f 100644
--- 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
@@ -24,7 +24,7 @@ export class RedmineUserCacheWriterService {
prevUser = null;
}
const newUser: nano.DocumentGetResponse & RedmineTypes.User & Timestamped =
- TimestampNowFill({ ...(user as any) });
+ TimestampNowFill({ ...(user as any), _id: String(id) });
if (prevUser) {
newUser._rev = prevUser._rev;
}
diff --git a/libs/event-emitter/src/users/users.controller.ts b/libs/event-emitter/src/users/users.controller.ts
index 2367d43..686723e 100644
--- a/libs/event-emitter/src/users/users.controller.ts
+++ b/libs/event-emitter/src/users/users.controller.ts
@@ -11,7 +11,7 @@ export class UsersController {
return await this.usersService.getUser(id);
}
- @Get(':id.json')
+ @Get(':id/json')
async getUserLikeRedmine(
@Param('id') id: number,
): Promise<{ user: RedmineTypes.User }> {
diff --git a/libs/event-emitter/src/users/users.service.ts b/libs/event-emitter/src/users/users.service.ts
index 40b543e..1209dce 100644
--- a/libs/event-emitter/src/users/users.service.ts
+++ b/libs/event-emitter/src/users/users.service.ts
@@ -1,17 +1,21 @@
-import { Injectable } from '@nestjs/common';
-import { RedmineTypes } from '../models/redmine-types';
+import { Injectable, Logger } from '@nestjs/common';
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';
+import { RedmineTypes } from '../models/redmine-types';
+import { MemoryCache } from '../utils/memory-cache';
export const USER_MEMORY_CACHE_LIFETIME = 24 * 60 * 60 * 1000;
+const USER_MEMORY_CACHE_AUTOCLEAN_INTERVAL = 1000 * 60 * 5;
@Injectable()
export class UsersService {
- private memoryCache: Record = {};
+ private logger = new Logger(UsersService.name);
+ private memoryCache = new MemoryCache(
+ USER_MEMORY_CACHE_LIFETIME,
+ USER_MEMORY_CACHE_AUTOCLEAN_INTERVAL,
+ );
constructor(
private users: Users,
@@ -26,8 +30,8 @@ export class UsersService {
}
const userFromCache = await this.getUserFromCache(userId);
if (userFromCache) {
- this.memoryCache[userId] = TimestampNowFill({ ...userFromCache });
- return this.memoryCache[userId];
+ this.memoryCache.set(userId, userFromCache);
+ return userFromCache;
}
let userFromRedmine = await this.getUserFromRedmine(userId);
if (userFromRedmine) {
@@ -35,13 +39,18 @@ export class UsersService {
userFromRedmine,
);
}
- const unknownUser = TimestampNowFill({ ...RedmineTypes.Unknown.user });
- this.memoryCache[userId] = (userFromRedmine || unknownUser) as any;
- return this.memoryCache[userId];
+ return this.memoryCache.set(
+ userId,
+ userFromRedmine || RedmineTypes.Unknown.user,
+ );
}
async getUserFromRedmine(userId: number): Promise {
- return await this.redmineDataLoader.loadUser(userId);
+ const user = await this.redmineDataLoader.loadUser(userId);
+ this.logger.debug(
+ `Get user from redmine with userId = ${userId}, login = ${user.login}`,
+ );
+ return user;
}
async getUserFromCache(
@@ -49,22 +58,23 @@ export class UsersService {
): Promise<(RedmineTypes.User & Timestamped) | null> {
const usersDb = await this.users.getDatasource();
try {
- return (await usersDb.get(String(userId))) as any;
+ const user = (await usersDb.get(String(userId))) as any;
+ this.logger.debug(
+ `Get user from couchdb with userId = ${userId}, login = ${user.login}`,
+ );
+ return user;
} 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];
+ const user = this.memoryCache.get(userId);
+ if (user) {
+ this.logger.debug(
+ `Get user from memory cache with userId = ${userId}, login = ${user.login}`,
+ );
}
- return null;
+ return user;
}
}
diff --git a/libs/event-emitter/src/utils/memory-cache.ts b/libs/event-emitter/src/utils/memory-cache.ts
index 59c5fb6..b7433a4 100644
--- a/libs/event-emitter/src/utils/memory-cache.ts
+++ b/libs/event-emitter/src/utils/memory-cache.ts
@@ -11,7 +11,7 @@ export class MemoryCache {
}
}
- get(key: K): T | null {
+ get(key: K): (T & Timestamped) | null {
const k = key as any;
if (this.memoryCache[k]) {
if (TimestampIsTimeouted(this.memoryCache[k], this.timeout)) {
diff --git a/libs/event-emitter/src/utils/timestamp-is-timeouted.ts b/libs/event-emitter/src/utils/timestamp-is-timeouted.ts
index dd07e17..55f4e49 100644
--- a/libs/event-emitter/src/utils/timestamp-is-timeouted.ts
+++ b/libs/event-emitter/src/utils/timestamp-is-timeouted.ts
@@ -4,6 +4,6 @@ export function TimestampIsTimeouted(
obj: Timestamped,
timeout: number,
): boolean {
- const now = new Date().getDate();
+ const now = new Date().getTime();
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 2b14705..79f7aa3 100644
--- a/libs/event-emitter/src/utils/timestamp-now-fill.ts
+++ b/libs/event-emitter/src/utils/timestamp-now-fill.ts
@@ -1,6 +1,6 @@
import { Timestamped } from '../models/timestamped';
export function TimestampNowFill(obj: T): T & Timestamped {
- const now = new Date().getDate();
+ const now = new Date().getTime();
return { ...obj, timestamp__: now };
}
diff --git a/libs/redmine-types/index.d.ts b/libs/redmine-types/index.d.ts
deleted file mode 100644
index a904d28..0000000
--- a/libs/redmine-types/index.d.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-///
-
-// eslint-disable-next-line @typescript-eslint/prefer-namespace-keyword
-export module RedmineTypes {
- export type IdAndName = {
- id: number;
- name: string;
- };
-
- export type CustomField = {
- id: number;
- name: string;
- value: string;
- };
-
- export type JournalDetail = {
- property: string;
- name: string;
- old_value?: string;
- new_value?: string;
- };
-
- export type Journal = {
- id: number;
- user: IdAndName;
- notes?: string;
- created_on: string;
- details?: JournalDetail[];
- };
-
- export type Issue = {
- id: number;
- project: IdAndName;
- tracker: IdAndName;
- status: IdAndName;
- priority: IdAndName;
- author: IdAndName;
- category: IdAndName;
- fixed_version: IdAndName;
- subject: string;
- description: string;
- start_date: string;
- done_ratio: number;
- spent_hours: number;
- total_spent_hours: number;
- custom_fields: CustomField[];
- created_on: string;
- updated_on?: string;
- closed_on?: string;
- relations?: Record[];
- journals?: Journal[];
- };
-
- // eslint-disable-next-line @typescript-eslint/prefer-namespace-keyword
- export module Unknown {
- export const num = -1;
- export const str = '';
- export const idAndName: IdAndName = {
- id: -1,
- name: str,
- };
- export const unknownName = 'Unknown';
- export const subject = 'Unknown';
- export const date = '1970-01-01T00:00:00Z';
- export const issue: Issue = {
- id: num,
- project: idAndName,
- tracker: idAndName,
- status: idAndName,
- priority: idAndName,
- author: idAndName,
- category: idAndName,
- fixed_version: idAndName,
- subject: subject,
- description: str,
- start_date: date,
- done_ratio: num,
- spent_hours: num,
- total_spent_hours: num,
- custom_fields: [],
- created_on: date,
- };
-
- export const user: User = {
- id: num,
- firstname: unknownName,
- lastname: unknownName,
- mail: str,
- };
- }
-
- export type User = {
- id: number;
- login: string;
- firstname: string;
- lastname: string;
- mail: string;
- };
-}
diff --git a/libs/redmine-types/index.js b/libs/redmine-types/index.js
deleted file mode 100644
index e69de29..0000000
diff --git a/libs/redmine-types/package.json b/libs/redmine-types/package.json
deleted file mode 100644
index 4df9704..0000000
--- a/libs/redmine-types/package.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "redmine-types",
- "version": "0.1.0",
- "description": "",
- "main": "index.js",
- "types": "index.d.ts",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "author": "Pavel Gnedov",
- "license": "MIT"
-}
diff --git a/package-lock.json b/package-lock.json
index 96a6d7b..d5b4a29 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,9 +8,6 @@
"name": "eltex-redmine-helper-2",
"version": "0.0.1",
"license": "UNLICENSED",
- "workspaces": [
- "libs/redmine-types"
- ],
"dependencies": {
"@nestjs/common": "^8.0.0",
"@nestjs/config": "^2.0.0",
@@ -54,6 +51,7 @@
},
"libs/redmine-types": {
"version": "0.1.0",
+ "extraneous": true,
"license": "MIT"
},
"node_modules/@ampproject/remapping": {
@@ -6595,10 +6593,6 @@
"node": ">= 0.10"
}
},
- "node_modules/redmine-types": {
- "resolved": "libs/redmine-types",
- "link": true
- },
"node_modules/reflect-metadata": {
"version": "0.1.13",
"license": "Apache-2.0"
@@ -12384,9 +12378,6 @@
"resolve": "^1.1.6"
}
},
- "redmine-types": {
- "version": "file:libs/redmine-types"
- },
"reflect-metadata": {
"version": "0.1.13"
},
diff --git a/package.json b/package.json
index 3a39561..a61e0d0 100644
--- a/package.json
+++ b/package.json
@@ -83,8 +83,5 @@
"moduleNameMapper": {
"^@app/event-emitter(|/.*)$": "/libs/event-emitter/src/$1"
}
- },
- "workspaces": [
- "libs/redmine-types"
- ]
+ }
}