5htp-core 0.0.6 → 0.0.8-1
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.
- package/package.json +6 -4
- package/src/client/assets/css/components/button.less +1 -1
- package/src/client/context/index.ts +3 -2
- package/src/client/index.tsx +2 -1
- package/src/client/router/component.tsx +6 -6
- package/src/server/app/config.ts +23 -19
- package/src/server/app/index.ts +48 -14
- package/src/server/data/Cache.ts +124 -74
- package/src/server/patch.ts +3 -0
- package/src/server/services/console/bugReporter.ts +30 -26
- package/src/server/services/console/html.ts +0 -0
- package/src/server/services/console/index.ts +1 -1
- package/src/server/services/database/connection.ts +7 -5
- package/src/server/services/database/index.ts +12 -4
- package/src/server/services/http/index.ts +2 -2
- package/src/server/services/socket/index.ts +1 -1
- package/tsconfig.common.json +3 -3
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "5htp-core",
|
|
3
3
|
"description": "5-HTP, scientifically called 5-Hydroxytryptophan, is the precursor of happiness neurotransmitter.",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.8-1",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/5htp-core.git",
|
|
7
7
|
"license": "MIT",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"fast-safe-stringify": "^2.1.1",
|
|
38
38
|
"fs-extra": "^10.1.0",
|
|
39
39
|
"google-auth-library": "^7.11.0",
|
|
40
|
+
"got": "^11.8.3",
|
|
40
41
|
"handlebars": "^4.7.7",
|
|
41
42
|
"helmet": "^4.6.0",
|
|
42
43
|
"history": "^5.0.1",
|
|
@@ -57,7 +58,6 @@
|
|
|
57
58
|
"nodemailer": "^6.6.3",
|
|
58
59
|
"path-to-regexp": "^6.2.0",
|
|
59
60
|
"picomatch": "^2.3.1",
|
|
60
|
-
"preact-render-to-string": "^5.1.19",
|
|
61
61
|
"react-scrollbars-custom": "^4.0.27",
|
|
62
62
|
"react-slider": "^2.0.1",
|
|
63
63
|
"react-textarea-autosize": "^8.3.3",
|
|
@@ -72,8 +72,10 @@
|
|
|
72
72
|
"uuid-by-string": "^3.0.4",
|
|
73
73
|
"validator": "^13.7.0",
|
|
74
74
|
"ws": "^8.2.2",
|
|
75
|
-
"yaml": "^1.10.2"
|
|
76
|
-
|
|
75
|
+
"yaml": "^1.10.2",
|
|
76
|
+
"preact": "^10.5.15",
|
|
77
|
+
"preact-render-to-string": "^5.1.19"
|
|
78
|
+
},
|
|
77
79
|
"devDependencies": {
|
|
78
80
|
"@types/cookie": "^0.4.1",
|
|
79
81
|
"@types/express": "^4.17.13",
|
|
@@ -202,7 +202,7 @@ export class ClientContext {
|
|
|
202
202
|
public handleError(e: Error) {
|
|
203
203
|
switch (e.http) {
|
|
204
204
|
case 401:
|
|
205
|
-
this.page?.
|
|
205
|
+
this.page?.go('/');
|
|
206
206
|
break;
|
|
207
207
|
default:
|
|
208
208
|
this.toast.error(e.title || "Uh Oh ...", e.message, null, { autohide: false });
|
|
@@ -225,12 +225,13 @@ export class ClientContext {
|
|
|
225
225
|
}
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
// Services
|
|
228
229
|
public modal = createDialog(this, false);
|
|
229
230
|
public toast = createDialog(this, true);
|
|
230
|
-
|
|
231
231
|
public socket = new SocketClient(this)
|
|
232
232
|
public captcha = new Recaptcha(this);
|
|
233
233
|
|
|
234
|
+
// Tracking
|
|
234
235
|
public event( name: string, params?: object ) {
|
|
235
236
|
if (!window.gtag) return;
|
|
236
237
|
if (name === 'pageview')
|
package/src/client/index.tsx
CHANGED
|
@@ -69,10 +69,10 @@ export default () => {
|
|
|
69
69
|
|
|
70
70
|
const [pages, setPages] = React.useState<{
|
|
71
71
|
current: undefined | PageResponse,
|
|
72
|
-
previous: undefined | PageResponse
|
|
72
|
+
//previous: undefined | PageResponse
|
|
73
73
|
}>({
|
|
74
74
|
current: gui.page,
|
|
75
|
-
previous: undefined
|
|
75
|
+
//previous: undefined
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
const resolvePage = async (request: ClientRequest, locationUpdate?: Update) => {
|
|
@@ -116,13 +116,13 @@ export default () => {
|
|
|
116
116
|
if (oldPage !== undefined) {
|
|
117
117
|
setTimeout(() => setPages({
|
|
118
118
|
current: newpage,
|
|
119
|
-
previous: undefined
|
|
119
|
+
//previous: undefined
|
|
120
120
|
}), 500);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
return {
|
|
124
124
|
current: newpage,
|
|
125
|
-
previous: oldPage
|
|
125
|
+
//previous: oldPage
|
|
126
126
|
}
|
|
127
127
|
});
|
|
128
128
|
}
|
|
@@ -175,9 +175,9 @@ export default () => {
|
|
|
175
175
|
|
|
176
176
|
// Render the page component
|
|
177
177
|
return <>
|
|
178
|
-
{pages.previous && (
|
|
178
|
+
{/*pages.previous && (
|
|
179
179
|
<Page page={pages.previous} key={pages.previous.id === undefined ? undefined : 'page_' + pages.previous.id} />
|
|
180
|
-
)}
|
|
180
|
+
)*/}
|
|
181
181
|
|
|
182
182
|
{pages.current && (
|
|
183
183
|
<Page page={pages.current} isCurrent key={pages.current.id === undefined ? undefined : 'page_' + pages.current.id} />
|
package/src/server/app/config.ts
CHANGED
|
@@ -35,23 +35,9 @@ export type TEnvConfig = {
|
|
|
35
35
|
profile: 'dev' | 'prod',
|
|
36
36
|
level: 'silly' | 'info' | 'warn' | 'error',
|
|
37
37
|
|
|
38
|
+
localIP: string,
|
|
38
39
|
domain: string,
|
|
39
|
-
|
|
40
|
-
url: string, // protocol + domain
|
|
41
|
-
localIP?: string
|
|
42
|
-
|
|
43
|
-
http: {
|
|
44
|
-
port: number,
|
|
45
|
-
ssl: boolean
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
database: {
|
|
49
|
-
host: string,
|
|
50
|
-
port: number,
|
|
51
|
-
login: string,
|
|
52
|
-
password: string,
|
|
53
|
-
list: string[]
|
|
54
|
-
},
|
|
40
|
+
url: string,
|
|
55
41
|
}
|
|
56
42
|
|
|
57
43
|
type AppIdentityConfig = {
|
|
@@ -101,9 +87,27 @@ export default class ConfigParser {
|
|
|
101
87
|
return yaml.parse(rawConfig);
|
|
102
88
|
}
|
|
103
89
|
|
|
104
|
-
public env() {
|
|
105
|
-
|
|
106
|
-
|
|
90
|
+
public env(): TEnvConfig {
|
|
91
|
+
// We assume that when we run 5htp dev, we're in local
|
|
92
|
+
// Otherwise, we're in production environment (docker)
|
|
93
|
+
console.log("Using environment:", process.env.NODE_ENV);
|
|
94
|
+
return process.env.NODE_ENV === 'development' ? {
|
|
95
|
+
name: 'local',
|
|
96
|
+
profile: 'dev',
|
|
97
|
+
level: 'silly',
|
|
98
|
+
|
|
99
|
+
localIP: '86.76.176.80',
|
|
100
|
+
domain: 'localhost:3010',
|
|
101
|
+
url: 'http://localhost:3010',
|
|
102
|
+
} : {
|
|
103
|
+
name: 'server',
|
|
104
|
+
profile: 'prod',
|
|
105
|
+
level: 'silly',
|
|
106
|
+
|
|
107
|
+
localIP: '86.76.176.80',
|
|
108
|
+
domain: 'megacharger.io',
|
|
109
|
+
url: 'https://megacharger.io',
|
|
110
|
+
}
|
|
107
111
|
}
|
|
108
112
|
|
|
109
113
|
public identity() {
|
package/src/server/app/index.ts
CHANGED
|
@@ -15,7 +15,7 @@ import ConfigParser, { TEnvConfig } from './config';
|
|
|
15
15
|
----------------------------------*/
|
|
16
16
|
|
|
17
17
|
type THookName = 'ready' | 'cleanup' | 'error'
|
|
18
|
-
type THook = () => void
|
|
18
|
+
type THook = () => Promise<void>;
|
|
19
19
|
|
|
20
20
|
type TServiceOptions = {
|
|
21
21
|
instanciate: boolean
|
|
@@ -106,21 +106,42 @@ export class App {
|
|
|
106
106
|
console.log("Configure services with", this.config);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
// Register a service
|
|
109
110
|
public register( id: string, Service: TServiceClass, options: Partial<TServiceOptions> = {}) {
|
|
110
111
|
|
|
111
112
|
// Pas d'export default new Service pour chaque fichier de service,
|
|
112
113
|
// dissuaded'importer ms service sn'importe où, ce qui créé des références circulaires
|
|
113
|
-
console.log(`
|
|
114
|
+
console.log(`[services] Registering service ${id} ...`);
|
|
114
115
|
const service = options.instanciate !== false ? new Service() : Service;
|
|
115
116
|
this.services[id] = service;
|
|
116
117
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
service
|
|
118
|
+
if ('load' in service) {
|
|
119
|
+
|
|
120
|
+
console.log(`[services] Starting service ${id} ...`);
|
|
121
|
+
const loading = service.load()
|
|
122
|
+
|
|
123
|
+
// Lorsque service.load est async, une propriété loading doit etre présente
|
|
124
|
+
// De façon à ce que les autres services puissent savoir quand ce service est prêt
|
|
125
|
+
if (('loading' in service) && (loading instanceof Promise)) {
|
|
126
|
+
|
|
127
|
+
console.log(`[services] Waiting service ${id} to be fully loaded ...`);
|
|
128
|
+
service.loading = loading.then(() => {
|
|
129
|
+
console.info(`[service] Service ${id} successfully started.`);
|
|
130
|
+
}).catch(e => {
|
|
131
|
+
// Bug report via email
|
|
132
|
+
console.error(`[service] Error while starting the ${id} service:`, e);
|
|
133
|
+
e.message = `Start ${id} service: ` + e.message;
|
|
134
|
+
$.console.bugReport.server(e);
|
|
135
|
+
});;
|
|
136
|
+
|
|
137
|
+
this.loading.push(service.loading);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Test if a service was registered
|
|
143
|
+
public isLoaded( id: string ) {
|
|
144
|
+
return id in this.services;
|
|
124
145
|
}
|
|
125
146
|
|
|
126
147
|
public on( name: THookName, callback: THook ) {
|
|
@@ -128,23 +149,36 @@ export class App {
|
|
|
128
149
|
return this;
|
|
129
150
|
}
|
|
130
151
|
|
|
152
|
+
public runHook( hookName: THookName ) {
|
|
153
|
+
console.info(`[hook] Run all ${hookName} hook (${this.hooks.ready.length}).`);
|
|
154
|
+
return Promise.all(
|
|
155
|
+
this.hooks.ready.map(
|
|
156
|
+
cb => cb().catch(e => {
|
|
157
|
+
console.error(`[hook] Error while executing hook ${hookName}:`, e);
|
|
158
|
+
})
|
|
159
|
+
)
|
|
160
|
+
).then(() => {
|
|
161
|
+
console.info(`[hook] Hooks ${hookName} executed with success.`);
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
|
|
131
165
|
/*----------------------------------
|
|
132
166
|
- LAUNCH
|
|
133
167
|
----------------------------------*/
|
|
134
168
|
public async launch() {
|
|
135
169
|
|
|
136
|
-
console.info(`Waiting for services to be ready ...`);
|
|
170
|
+
console.info(`[boot] Waiting for all services to be ready ...`);
|
|
137
171
|
await Promise.all( this.loading );
|
|
138
172
|
|
|
139
|
-
console.info(`Launching application ...`);
|
|
140
|
-
await
|
|
173
|
+
console.info(`[boot] Launching application ...`);
|
|
174
|
+
await this.runHook('ready');
|
|
141
175
|
|
|
142
176
|
// NOTE: Useless ?
|
|
143
177
|
/*if (this.hmr)
|
|
144
178
|
this.activateHMR();*/
|
|
145
179
|
|
|
146
|
-
console.info(`Application is ready.`);
|
|
147
|
-
|
|
180
|
+
console.info(`[boot] Application is ready.`);
|
|
181
|
+
|
|
148
182
|
this.launched = true;
|
|
149
183
|
|
|
150
184
|
}
|
package/src/server/data/Cache.ts
CHANGED
|
@@ -2,68 +2,123 @@
|
|
|
2
2
|
- DEPENDANCES
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
|
+
// Node
|
|
6
|
+
import path from 'path';
|
|
7
|
+
|
|
5
8
|
// Npm
|
|
6
9
|
import hInterval from 'human-interval';
|
|
10
|
+
import fs from 'fs-extra';
|
|
11
|
+
|
|
12
|
+
// Core
|
|
13
|
+
import app from '@server/app';
|
|
7
14
|
|
|
8
15
|
// Libs
|
|
9
|
-
|
|
10
|
-
|
|
16
|
+
|
|
17
|
+
/*----------------------------------
|
|
18
|
+
- TYPES
|
|
19
|
+
----------------------------------*/
|
|
20
|
+
|
|
21
|
+
type TPrimitiveValue = string | boolean | number | undefined | {[key: string]: TPrimitiveValue} | TPrimitiveValue[];
|
|
22
|
+
|
|
23
|
+
type TExpirationDelay = string | number | Date | null;
|
|
24
|
+
|
|
25
|
+
type CacheEntry = {
|
|
26
|
+
// Value
|
|
27
|
+
value: TPrimitiveValue,
|
|
28
|
+
// Expiration Timestamp
|
|
29
|
+
expiration?: number
|
|
30
|
+
};
|
|
11
31
|
|
|
12
32
|
/*----------------------------------
|
|
13
33
|
- SERVICE
|
|
14
34
|
----------------------------------*/
|
|
15
|
-
|
|
35
|
+
class Cache {
|
|
36
|
+
|
|
37
|
+
private cacheFile = path.join(app.path.data, 'cache/mem.json');
|
|
38
|
+
|
|
39
|
+
private data: {[key: string]: CacheEntry | undefined} = {};
|
|
40
|
+
|
|
41
|
+
private changes: number = 0;
|
|
42
|
+
|
|
43
|
+
public constructor() {
|
|
44
|
+
|
|
45
|
+
setInterval(() => this.cleanMem(), 10000);
|
|
46
|
+
|
|
47
|
+
if (fs.existsSync(this.cacheFile))
|
|
48
|
+
this.data = fs.readJSONSync(this.cacheFile)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private cleanMem() {
|
|
52
|
+
|
|
53
|
+
console.log("[cache] Clean memory");
|
|
54
|
+
|
|
55
|
+
const now = Date.now();
|
|
56
|
+
for (const key in this.data) {
|
|
57
|
+
const entry = this.data[ key ];
|
|
58
|
+
if (entry?.expiration && entry.expiration < now)
|
|
59
|
+
this.del(key);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (this.changes > 0)
|
|
63
|
+
fs.outputJSONSync(this.cacheFile, this.data);
|
|
64
|
+
}
|
|
16
65
|
|
|
17
66
|
// Expiration = Durée de vie en secondes ou date max
|
|
18
67
|
// Retourne null quand pas de valeur
|
|
19
|
-
|
|
68
|
+
public get<TValeur extends TPrimitiveValue>(
|
|
69
|
+
cle: string,
|
|
70
|
+
func?: (() => Promise<TValeur>),
|
|
71
|
+
expiration?: TExpirationDelay,
|
|
72
|
+
avecDetails?: true
|
|
73
|
+
): Promise<CacheEntry>;
|
|
74
|
+
|
|
75
|
+
public get<TValeur extends TPrimitiveValue>(
|
|
76
|
+
cle: string,
|
|
77
|
+
func: (() => Promise<TValeur>),
|
|
78
|
+
expiration?: TExpirationDelay,
|
|
79
|
+
avecDetails?: false
|
|
80
|
+
): Promise<null | TValeur>;
|
|
81
|
+
|
|
82
|
+
public async get<TValeur extends TPrimitiveValue>(
|
|
20
83
|
cle: string,
|
|
21
|
-
func
|
|
22
|
-
expiration
|
|
84
|
+
func?: (() => Promise<TValeur>),
|
|
85
|
+
expiration?: TExpirationDelay,
|
|
23
86
|
avecDetails?: boolean
|
|
24
|
-
): Promise<null | TValeur> {
|
|
87
|
+
): Promise<null | TValeur | CacheEntry> {
|
|
88
|
+
|
|
89
|
+
let retour: CacheEntry | undefined = this.data[cle];
|
|
90
|
+
|
|
91
|
+
console.log(`[cache] Get "${cle}".`);
|
|
25
92
|
|
|
26
|
-
|
|
93
|
+
// Expired
|
|
94
|
+
if (retour?.expiration && retour.expiration < Date.now()){
|
|
95
|
+
console.log(`[cache] Key ${cle} expired.`);
|
|
96
|
+
retour = undefined;
|
|
97
|
+
}
|
|
27
98
|
|
|
28
99
|
// Donnée inexistante
|
|
29
|
-
if (retour ===
|
|
100
|
+
if (retour === undefined && func !== undefined) {
|
|
30
101
|
|
|
31
102
|
// Rechargement
|
|
32
|
-
retour =
|
|
103
|
+
retour = {
|
|
104
|
+
value: await func(),
|
|
105
|
+
expiration: expiration
|
|
106
|
+
? this.delayToTimestamp(expiration)
|
|
107
|
+
: undefined
|
|
108
|
+
}
|
|
33
109
|
|
|
34
110
|
// undefined retourné = pas d'enregistrement
|
|
35
|
-
if (retour !== undefined)
|
|
111
|
+
if (retour.value !== undefined)
|
|
36
112
|
await this.set(cle, retour, expiration);
|
|
37
113
|
}
|
|
38
114
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
donnees: retour
|
|
42
|
-
}
|
|
43
|
-
: retour;
|
|
44
|
-
},
|
|
45
|
-
|
|
46
|
-
getVal<TValeur>(cle: string): Promise<TValeur | null> {
|
|
47
|
-
return new Promise((resolve) => {
|
|
48
|
-
|
|
49
|
-
redis.instance.get(cle, (err, val) => {
|
|
115
|
+
if (retour === undefined)
|
|
116
|
+
return null;
|
|
50
117
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
resolve( JSON.parse(val) )
|
|
56
|
-
} catch (error) {
|
|
57
|
-
|
|
58
|
-
console.warn(`Error while parsing JSON value from cache (id: ${cle})`, error, 'Raw value:', val);
|
|
59
|
-
resolve(null);
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
},
|
|
118
|
+
return avecDetails
|
|
119
|
+
? retour
|
|
120
|
+
: retour.value as TValeur;
|
|
121
|
+
};
|
|
67
122
|
|
|
68
123
|
/**
|
|
69
124
|
* Put in cache a JSON value, associated with an unique ID.
|
|
@@ -76,49 +131,44 @@ const Cache = {
|
|
|
76
131
|
* - null: no expiration (default)
|
|
77
132
|
* @returns A void promise
|
|
78
133
|
*/
|
|
79
|
-
set( cle: string, val:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
134
|
+
public set( cle: string, val: TPrimitiveValue, expiration: TExpirationDelay = null ): void {
|
|
135
|
+
|
|
136
|
+
console.log("[cache] Updating cache " + cle);
|
|
137
|
+
this.data[ cle ] = {
|
|
138
|
+
value: val,
|
|
139
|
+
expiration: this.delayToTimestamp(expiration)
|
|
140
|
+
}
|
|
86
141
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
redis.instance.set(cle, val, () => {
|
|
90
|
-
resolve()
|
|
91
|
-
});
|
|
92
|
-
else {
|
|
142
|
+
this.changes++;
|
|
143
|
+
};
|
|
93
144
|
|
|
94
|
-
|
|
145
|
+
public del( cle: string ): void {
|
|
146
|
+
this.data[ cle ] = undefined;
|
|
147
|
+
this.changes++;
|
|
148
|
+
}
|
|
95
149
|
|
|
96
|
-
// H expression
|
|
97
|
-
if (typeof expiration === 'string') {
|
|
98
150
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
151
|
+
/*----------------------------------
|
|
152
|
+
- UTILS
|
|
153
|
+
----------------------------------*/
|
|
154
|
+
private delayToTimestamp( delay: TExpirationDelay ): number {
|
|
102
155
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
secondes = expiration;
|
|
106
|
-
// Date limite
|
|
107
|
-
else
|
|
108
|
-
secondes = (expiration.getTime() - (new Date).getTime()) / 1000;
|
|
156
|
+
// H expression
|
|
157
|
+
if (typeof delay === 'string') {
|
|
109
158
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
},
|
|
159
|
+
const ms = hInterval(delay);
|
|
160
|
+
if (ms === undefined) throw new Error(`Invalid period string: ` + delay);
|
|
161
|
+
return Date.now() + ms;
|
|
116
162
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
163
|
+
// Via durée de vie en secondes
|
|
164
|
+
} else if (typeof delay === 'number')
|
|
165
|
+
return Date.now() + delay;
|
|
166
|
+
// Date limite
|
|
167
|
+
else if (delay !== null)
|
|
168
|
+
return delay.getTime();
|
|
169
|
+
else
|
|
170
|
+
return Date.now();
|
|
121
171
|
}
|
|
122
172
|
}
|
|
123
173
|
|
|
124
|
-
export default Cache;
|
|
174
|
+
export default new Cache;
|
package/src/server/patch.ts
CHANGED
|
@@ -79,7 +79,6 @@ export default class BugReporter {
|
|
|
79
79
|
// Get context
|
|
80
80
|
const now = new Date();
|
|
81
81
|
const hash = uuid();
|
|
82
|
-
const erroTitle = "Server Bug: " + error.message;
|
|
83
82
|
const { channelType, channelId } = this.console.getChannel();
|
|
84
83
|
|
|
85
84
|
// On envoi l'email avant l'insertion dans bla bdd
|
|
@@ -90,31 +89,36 @@ export default class BugReporter {
|
|
|
90
89
|
);
|
|
91
90
|
|
|
92
91
|
// Send notification
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
92
|
+
if (app.isLoaded('email'))
|
|
93
|
+
$.email.send({
|
|
94
|
+
to: app.identity.author.email,
|
|
95
|
+
subject: "Server bug: " + error.message,
|
|
96
|
+
html: `
|
|
97
|
+
<a href="${app.env.url}/admin/activity/requests/${channelId}">
|
|
98
|
+
View Request details & console
|
|
99
|
+
</a>
|
|
100
|
+
<br/>
|
|
101
|
+
${logsHtml}
|
|
102
|
+
`
|
|
103
|
+
});
|
|
104
|
+
else
|
|
105
|
+
console.error("Unable to send bug report: email service not loaded.");
|
|
106
|
+
|
|
107
|
+
/*if (app.isLoaded('sql'))
|
|
108
|
+
// Memorize
|
|
109
|
+
$.sql.insert('BugServer', {
|
|
110
|
+
// Context
|
|
111
|
+
hash: hash,
|
|
112
|
+
date: now,
|
|
113
|
+
channelType,
|
|
114
|
+
channelId,
|
|
115
|
+
// User
|
|
116
|
+
user: request?.user?.name,
|
|
117
|
+
ip: request?.ip,
|
|
118
|
+
// Error
|
|
119
|
+
stacktrace: error.stack || error.message,
|
|
120
|
+
logs: logsHtml
|
|
121
|
+
});*/
|
|
118
122
|
|
|
119
123
|
// Update error message
|
|
120
124
|
error.message = "A bug report has been sent to my personal mailbox. Sorry for the inconvenience.";
|
|
File without changes
|
|
@@ -256,7 +256,7 @@ export class Console {
|
|
|
256
256
|
let html = logs.map( log => logToHTML( log, this )).join('\n');
|
|
257
257
|
|
|
258
258
|
if (full) {
|
|
259
|
-
const consoleCss = `background: #000; padding: 20px; font-family: 'monospace'; font-size: 12px; line-height: 20px;`
|
|
259
|
+
const consoleCss = `background: #000; padding: 20px; font-family: 'Fira Mono', 'monospace', 'Monaco'; font-size: 12px; line-height: 20px;`
|
|
260
260
|
html = '<div style="' + consoleCss + '">' + html + '</div>';
|
|
261
261
|
}
|
|
262
262
|
|
|
@@ -62,13 +62,15 @@ export default class FastDatabase {
|
|
|
62
62
|
|
|
63
63
|
console.info(`Connecting to databases ...`);
|
|
64
64
|
|
|
65
|
+
const creds = this.config[ app.env.profile ];
|
|
66
|
+
|
|
65
67
|
return await mysql.createPool({
|
|
66
68
|
|
|
67
69
|
// Identification
|
|
68
|
-
host:
|
|
69
|
-
port:
|
|
70
|
-
user:
|
|
71
|
-
password:
|
|
70
|
+
host: creds.host,
|
|
71
|
+
port: creds.port,
|
|
72
|
+
user: creds.login,
|
|
73
|
+
password: creds.password,
|
|
72
74
|
database: this.config.list[0],
|
|
73
75
|
|
|
74
76
|
// Pool
|
|
@@ -106,7 +108,7 @@ export default class FastDatabase {
|
|
|
106
108
|
let type = field.type;
|
|
107
109
|
if (field.db) {
|
|
108
110
|
|
|
109
|
-
// A revoir, car les infos passées peuvent être des alias
|
|
111
|
+
// TODO: A revoir, car les infos passées peuvent être des alias
|
|
110
112
|
|
|
111
113
|
const db = this.tables[ field.db ];
|
|
112
114
|
if (db === undefined) {
|
|
@@ -41,11 +41,19 @@ export type TInsertQueryOptions<TData extends TObjetDonnees = TObjetDonnees> = T
|
|
|
41
41
|
----------------------------------*/
|
|
42
42
|
|
|
43
43
|
export type DatabaseServiceConfig = {
|
|
44
|
-
host: string,
|
|
45
44
|
list: string[],
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
dev: {
|
|
46
|
+
host: string,
|
|
47
|
+
port: number,
|
|
48
|
+
login: string,
|
|
49
|
+
password: string,
|
|
50
|
+
},
|
|
51
|
+
prod: {
|
|
52
|
+
host: string,
|
|
53
|
+
port: number,
|
|
54
|
+
login: string,
|
|
55
|
+
password: string,
|
|
56
|
+
}
|
|
49
57
|
}
|
|
50
58
|
|
|
51
59
|
declare global {
|
|
@@ -89,7 +89,7 @@ export default class HttpServer {
|
|
|
89
89
|
|
|
90
90
|
this.http = http.createServer(this.express);
|
|
91
91
|
|
|
92
|
-
} else if ('ssh' in app.env) {
|
|
92
|
+
} /*else if ('ssh' in app.env) {
|
|
93
93
|
|
|
94
94
|
const ssh = app.env.ssh;
|
|
95
95
|
|
|
@@ -102,7 +102,7 @@ export default class HttpServer {
|
|
|
102
102
|
rejectUnauthorized: false
|
|
103
103
|
}, this.express);
|
|
104
104
|
|
|
105
|
-
} else
|
|
105
|
+
}*/ else
|
|
106
106
|
throw new Error(`SSL was enabled, but no ssh config was specified in app.env (required to load ssl certificate files)`);
|
|
107
107
|
|
|
108
108
|
// Start HTTP Server
|
package/tsconfig.common.json
CHANGED
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"@errors": ["./common/errors"],
|
|
35
35
|
"@models": ["./common/models"],
|
|
36
36
|
|
|
37
|
-
"react": ["
|
|
38
|
-
"react-dom": ["
|
|
39
|
-
"react/jsx-runtime": ["
|
|
37
|
+
"react": ["preact/compat"],
|
|
38
|
+
"react-dom": ["preact/compat"],
|
|
39
|
+
"react/jsx-runtime": ["preact/jsx-runtime"]
|
|
40
40
|
},
|
|
41
41
|
},
|
|
42
42
|
"include": ["src"]
|