5htp-core 0.0.7 → 0.0.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.
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",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/5htp-core.git",
|
|
7
7
|
"license": "MIT",
|
|
@@ -58,7 +58,6 @@
|
|
|
58
58
|
"nodemailer": "^6.6.3",
|
|
59
59
|
"path-to-regexp": "^6.2.0",
|
|
60
60
|
"picomatch": "^2.3.1",
|
|
61
|
-
"preact-render-to-string": "^5.1.19",
|
|
62
61
|
"react-scrollbars-custom": "^4.0.27",
|
|
63
62
|
"react-slider": "^2.0.1",
|
|
64
63
|
"react-textarea-autosize": "^8.3.3",
|
|
@@ -73,7 +72,9 @@
|
|
|
73
72
|
"uuid-by-string": "^3.0.4",
|
|
74
73
|
"validator": "^13.7.0",
|
|
75
74
|
"ws": "^8.2.2",
|
|
76
|
-
"yaml": "^1.10.2"
|
|
75
|
+
"yaml": "^1.10.2",
|
|
76
|
+
"preact": "^10.5.15",
|
|
77
|
+
"preact-render-to-string": "^5.1.19"
|
|
77
78
|
},
|
|
78
79
|
"devDependencies": {
|
|
79
80
|
"@types/cookie": "^0.4.1",
|
|
@@ -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/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;
|