@glassnote/client 2.4.9 → 2.4.10
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/main.js +732 -725
- package/package.json +2 -1
- package/versionReport.js +156 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glassnote/client",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.10",
|
|
4
4
|
"description": "GlassNote — cliente de escritorio de notas superpuestas. Se instala con npx, sin instaladores nativos ni firmas.",
|
|
5
5
|
"main": "main.js",
|
|
6
6
|
"publishConfig": {
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"rendererPaths.js",
|
|
33
33
|
"npmMode.js",
|
|
34
34
|
"npmUpdate.js",
|
|
35
|
+
"versionReport.js",
|
|
35
36
|
"localserver.js",
|
|
36
37
|
"logUtilities.js",
|
|
37
38
|
"userData.js",
|
package/versionReport.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// El cliente le dice a la API qué versión corre, y se lleva de vuelta la que debería
|
|
2
|
+
// correr. Un solo viaje para las dos cosas.
|
|
3
|
+
//
|
|
4
|
+
// Por qué hace falta: hasta ahora la API no sabía la versión de ningún equipo. Un cliente
|
|
5
|
+
// que no se actualiza se ve exactamente igual que uno al día, y por eso la
|
|
6
|
+
// auto-actualización pudo estar rota en Windows durante meses sin que nadie lo notara.
|
|
7
|
+
//
|
|
8
|
+
// Y de paso cierra `desiredVersion`, que estaba muerto: la API lo tiene en la base y lo
|
|
9
|
+
// empuja por websocket, pero el renderer nunca lo guardó, así que fijar la versión de un
|
|
10
|
+
// equipo no hacía nada. Viniendo en la respuesta de este reporte, se cierra el circuito
|
|
11
|
+
// sin tocar el renderer —cuyo código, además, no vive en este repo—.
|
|
12
|
+
const http = require('http');
|
|
13
|
+
const https = require('https');
|
|
14
|
+
|
|
15
|
+
const userData = require('./userData');
|
|
16
|
+
const packageJson = require('./package.json');
|
|
17
|
+
|
|
18
|
+
const DELAY_MS = 15000; // después del arranque, sin competir con la carga del renderer
|
|
19
|
+
const INTERVALO_MS = 6 * 60 * 60 * 1000;
|
|
20
|
+
const TIMEOUT_MS = 10000;
|
|
21
|
+
|
|
22
|
+
class VersionReport {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.timer = null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
start() {
|
|
28
|
+
setTimeout(() => this.reportar(), DELAY_MS);
|
|
29
|
+
this.timer = setInterval(() => this.reportar(), INTERVALO_MS);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
stop() {
|
|
33
|
+
if (this.timer) {
|
|
34
|
+
clearInterval(this.timer);
|
|
35
|
+
this.timer = null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Los servidores se guardan como URLs de websocket (ws://, wss://). La API HTTP vive
|
|
40
|
+
// en el mismo origen, así que basta con quedarse con el origen y cambiar el esquema.
|
|
41
|
+
origenes() {
|
|
42
|
+
let servers = [];
|
|
43
|
+
try {
|
|
44
|
+
servers = userData.get('servers') || [];
|
|
45
|
+
} catch (error) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
if (!Array.isArray(servers)) return [];
|
|
49
|
+
|
|
50
|
+
const vistos = new Set();
|
|
51
|
+
for (const server of servers) {
|
|
52
|
+
if (typeof server !== 'string' || !server.trim()) continue;
|
|
53
|
+
try {
|
|
54
|
+
const url = new URL(server.trim());
|
|
55
|
+
const esquema = url.protocol === 'wss:' || url.protocol === 'https:' ? 'https:' : 'http:';
|
|
56
|
+
vistos.add(`${esquema}//${url.host}`);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
/* una entrada mal formada no puede tumbar al resto */
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return Array.from(vistos);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
post(origen, cuerpo) {
|
|
65
|
+
return new Promise((resolve) => {
|
|
66
|
+
let url;
|
|
67
|
+
try {
|
|
68
|
+
url = new URL('/devices/report-version', origen);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
return resolve(null);
|
|
71
|
+
}
|
|
72
|
+
const datos = Buffer.from(JSON.stringify(cuerpo));
|
|
73
|
+
const cliente = url.protocol === 'https:' ? https : http;
|
|
74
|
+
const req = cliente.request(
|
|
75
|
+
url,
|
|
76
|
+
{
|
|
77
|
+
method: 'POST',
|
|
78
|
+
headers: {
|
|
79
|
+
'content-type': 'application/json',
|
|
80
|
+
'content-length': datos.length,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
(res) => {
|
|
84
|
+
let body = '';
|
|
85
|
+
res.setEncoding('utf8');
|
|
86
|
+
res.on('data', (chunk) => (body += chunk));
|
|
87
|
+
res.on('end', () => {
|
|
88
|
+
if (res.statusCode < 200 || res.statusCode >= 300) {
|
|
89
|
+
console.warn(`[version] ${origen} respondió ${res.statusCode}`);
|
|
90
|
+
return resolve(null);
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
resolve(JSON.parse(body));
|
|
94
|
+
} catch (error) {
|
|
95
|
+
resolve(null);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
req.setTimeout(TIMEOUT_MS, () => {
|
|
101
|
+
req.destroy();
|
|
102
|
+
resolve(null);
|
|
103
|
+
});
|
|
104
|
+
// Un equipo sin red, o con la API caída, es lo normal en este parque: se
|
|
105
|
+
// registra en el log y se reintenta en el ciclo siguiente. Nunca rompe la app.
|
|
106
|
+
req.on('error', (error) => {
|
|
107
|
+
console.warn(`[version] no se pudo reportar a ${origen}: ${error.message}`);
|
|
108
|
+
resolve(null);
|
|
109
|
+
});
|
|
110
|
+
req.end(datos);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async reportar() {
|
|
115
|
+
let uuid;
|
|
116
|
+
try {
|
|
117
|
+
uuid = userData.getUUID();
|
|
118
|
+
} catch (error) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const origenes = this.origenes();
|
|
122
|
+
if (origenes.length === 0) return;
|
|
123
|
+
|
|
124
|
+
const cuerpo = { uuid, version: packageJson.version };
|
|
125
|
+
for (const origen of origenes) {
|
|
126
|
+
const respuesta = await this.post(origen, cuerpo);
|
|
127
|
+
if (respuesta && typeof respuesta.desiredVersion === 'string') {
|
|
128
|
+
this.guardarDesiredVersion(respuesta.desiredVersion);
|
|
129
|
+
// Con el primer servidor que conteste alcanza: todos miran la misma base.
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Se escribe solo si cambió: userData reescribe el archivo entero en cada set.
|
|
136
|
+
guardarDesiredVersion(valor) {
|
|
137
|
+
const limpio = valor.trim();
|
|
138
|
+
// Acotado a lo que el updater sabe interpretar. Cualquier otra cosa se ignora en
|
|
139
|
+
// vez de guardarse: un valor raro acá deja al equipo sin actualizarse y sin decir
|
|
140
|
+
// por qué, que es exactamente el fallo del que venimos.
|
|
141
|
+
const aceptable = limpio === 'lastest' || limpio === 'latest' || /^\d+\.\d+\.\d+/.test(limpio);
|
|
142
|
+
if (!aceptable) {
|
|
143
|
+
console.warn(`[version] desiredVersion ignorado por ilegible: ${JSON.stringify(limpio)}`);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
if (userData.get('desiredVersion') === limpio) return;
|
|
148
|
+
console.log(`[version] desiredVersion: ${limpio}`);
|
|
149
|
+
userData.set('desiredVersion', limpio);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error('[version] no se pudo guardar desiredVersion:', error.message);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = VersionReport;
|