@viplance/nestjs-logger 0.4.7 → 0.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -63,10 +63,99 @@ export class MemoryDbService {
63
63
  entity: EntitySchema,
64
64
  options?: {
65
65
  select?: string[];
66
+ where?: any;
67
+ order?: { [key: string]: 'ASC' | 'DESC' };
68
+ take?: number;
69
+ skip?: number;
66
70
  }
67
71
  ): Promise<any[]> {
68
72
  const table = this.getTableName(entity);
73
+ let data = [...this.db[table]];
74
+
75
+ // filter by search if where contains $or or Like (simplified for memory db)
76
+ // filter by search if where contains $or or Like (simplified for memory db)
77
+ if (options?.where) {
78
+ if (options.where.$or) {
79
+ const search = options.where.$or[0].message.$regex;
80
+ if (search) {
81
+ const regex = new RegExp(search, 'i');
82
+ data = data.filter(
83
+ (item) => regex.test(item.message) || regex.test(item.trace || '')
84
+ );
85
+ }
86
+ } else if (Array.isArray(options.where)) {
87
+ // handle Like constraints
88
+ const searchItem = options.where.find((w: any) => w.message);
89
+ if (searchItem && searchItem.message) {
90
+ let search = '';
91
+ if (typeof searchItem.message === 'string') {
92
+ search = searchItem.message.replace(/%/g, '');
93
+ } else if (searchItem.message.value) {
94
+ // FindOperator
95
+ search = searchItem.message.value.replace(/%/g, '');
96
+ } else if (searchItem.message._value) {
97
+ // FindOperator private
98
+ search = searchItem.message._value.replace(/%/g, '');
99
+ }
100
+
101
+ if (search) {
102
+ const regex = new RegExp(search, 'i');
103
+ data = data.filter(
104
+ (item) => regex.test(item.message) || regex.test(item.trace || '')
105
+ );
106
+ }
107
+ }
108
+ }
109
+
110
+ // Handle type filtering
111
+ let types: string[] | null = null;
112
+ let typeVal: any;
113
+
114
+ if (Array.isArray(options.where)) {
115
+ typeVal = options.where[0]?.type;
116
+ } else {
117
+ typeVal = options.where.type;
118
+ }
119
+
120
+ if (typeVal) {
121
+ if (Array.isArray(typeVal)) {
122
+ types = typeVal;
123
+ } else if (typeVal.value && Array.isArray(typeVal.value)) {
124
+ types = typeVal.value;
125
+ } else if (typeVal._value && Array.isArray(typeVal._value)) {
126
+ types = typeVal._value;
127
+ } else if (typeVal.$in && Array.isArray(typeVal.$in)) {
128
+ types = typeVal.$in;
129
+ }
130
+ }
131
+
132
+ if (types) {
133
+ data = data.filter((item) => types!.includes(item.type));
134
+ }
135
+ }
136
+
137
+ // sort
138
+ if (options?.order) {
139
+ const field = Object.keys(options.order)[0];
140
+ const direction = options.order[field];
141
+ data.sort((a, b) => {
142
+ if (a[field] < b[field]) return direction === 'ASC' ? -1 : 1;
143
+ if (a[field] > b[field]) return direction === 'ASC' ? 1 : -1;
144
+ return 0;
145
+ });
146
+ } else {
147
+ data.sort((a, b) => b.updatedAt - a.updatedAt);
148
+ }
149
+
150
+ // pagination
151
+ if (options?.skip !== undefined) {
152
+ data = data.slice(options.skip);
153
+ }
154
+ if (options?.take !== undefined) {
155
+ data = data.slice(0, options.take);
156
+ }
69
157
 
158
+ // mapping (select)
70
159
  let mapOptions = (obj: any) => obj; // return the object as is by default
71
160
 
72
161
  if (options?.select) {
@@ -81,9 +170,7 @@ export class MemoryDbService {
81
170
  };
82
171
  }
83
172
 
84
- return Promise.resolve(
85
- this.db[table].map(mapOptions).sort((a, b) => b.updatedAt - a.updatedAt)
86
- );
173
+ return Promise.resolve(data.map(mapOptions));
87
174
  }
88
175
 
89
176
  public async getOneById(entity: EntitySchema, _id: string): Promise<any> {
@@ -6,14 +6,14 @@ import { Subject } from 'rxjs';
6
6
  @Injectable()
7
7
  export class WsService {
8
8
  public onMessage: Subject<any> = new Subject();
9
- private ws: WebSocket | null = null;
10
- private connected: boolean = false;
9
+ private clients: Set<any> = new Set();
11
10
  private connectionTimeout: number = 500;
12
11
  private options: LogModuleOptions['websocket'] = {
13
12
  port: 8080,
14
13
  host: 'localhost',
15
14
  };
16
15
  private key: string = '';
16
+ private wsServer: any | null = null;
17
17
 
18
18
  setupConnection(options: LogModuleOptions['websocket'], key = '') {
19
19
  this.options = {
@@ -23,11 +23,11 @@ export class WsService {
23
23
  this.key = key;
24
24
 
25
25
  // Set up Web Socket server
26
- if (this.ws) {
26
+ if (this.wsServer) {
27
27
  return;
28
28
  }
29
29
 
30
- const wsServer = new WebSocketServer({
30
+ this.wsServer = new WebSocketServer({
31
31
  retryCount: 1,
32
32
  reconnectInterval: 1,
33
33
  handshakeTimeout: this.connectionTimeout,
@@ -38,45 +38,44 @@ export class WsService {
38
38
  `Logs WebSocket server is listening on port ${this.options.port}`
39
39
  );
40
40
 
41
- wsServer.on('error', this.handleError);
42
- wsServer.on('open', () => this.handleOpenConnection());
43
- wsServer.on('ping', () => this.ping(this.ws));
44
- wsServer.on('close', () => this.closeConnection(this.ws));
45
- wsServer.on('message', this.handleMessage);
46
- wsServer.on('connection', (connection: WebSocket) => {
47
- this.ws = connection;
48
- connection.onmessage = this.handleMessage;
41
+ this.wsServer.on('error', this.handleError);
42
+ this.wsServer.on('listening', () => this.handleOpenConnection());
43
+ this.wsServer.on('close', () => {
44
+ console.log('WebSocket server closed.');
45
+ this.wsServer = null;
46
+ });
47
+
48
+ this.wsServer.on('connection', (connection: any) => {
49
+ this.clients.add(connection);
50
+
51
+ connection.on('message', (message: any) => this.handleMessage(message));
52
+
53
+ connection.on('close', () => {
54
+ this.clients.delete(connection);
55
+ });
56
+
57
+ connection.on('error', () => {
58
+ this.clients.delete(connection);
59
+ });
49
60
  });
50
61
  }
51
62
 
52
63
  sendMessage(message: any) {
53
- this.ws?.send(JSON.stringify(message));
64
+ this.clients.forEach((client) => {
65
+ if (client.readyState === WebSocket.OPEN) {
66
+ client.send(JSON.stringify(message));
67
+ }
68
+ });
54
69
  }
55
70
 
56
71
  private handleError = () => {
57
72
  const serverUrl = this.getServerUrl();
58
73
  console.error(`Server ${serverUrl} is not available.`);
59
74
 
60
- setTimeout(this.setupConnection, this.connectionTimeout);
61
- };
62
-
63
- private closeConnection = (connection: any) => {
64
- clearTimeout(connection.pingTimeout);
65
-
66
- if (this.connected) {
67
- console.log('Connection has been closed by server.');
68
- this.connected = false;
69
- this.handleError();
70
- }
71
- };
72
-
73
- private ping = (connection: any) => {
74
- console.log('Ping remote server.');
75
- clearTimeout(connection.pingTimeout);
75
+ // If server failed, reset instance so retry can happen
76
+ this.wsServer = null;
76
77
 
77
- connection.pingTimeout = setTimeout(() => {
78
- connection.terminate();
79
- }, 30000 + this.connectionTimeout);
78
+ setTimeout(() => this.setupConnection(this.options, this.key), this.connectionTimeout);
80
79
  };
81
80
 
82
81
  private handleMessage = (message: any) => {
@@ -97,13 +96,11 @@ export class WsService {
97
96
  };
98
97
 
99
98
  private getServerUrl = (): string => {
100
- return `${this.options?.secure ? 'wss' : 'ws'}://${this.options?.host}:${
101
- this.options?.port
102
- }`;
99
+ return `${this.options?.secure ? 'wss' : 'ws'}://${this.options?.host}:${this.options?.port
100
+ }`;
103
101
  };
104
102
 
105
103
  private handleOpenConnection = async () => {
106
- this.connected = true;
107
104
  const serverUrl = this.getServerUrl();
108
105
  console.log(`${serverUrl} has been connected.`);
109
106
  };