xonecode 0.38.4 → 0.38.11
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/apps/web/dist/assets/{EditorDeFichero-ClGfUHp0.js → EditorDeFichero-C_95A4sB.js} +1 -1
- package/apps/web/dist/assets/index-CAqQp65A.js +506 -0
- package/apps/web/dist/assets/index-tzWrUZYU.css +1 -0
- package/apps/web/dist/assets/{php-DFC2MqmC.js → php-CkVQ0jw6.js} +1 -1
- package/apps/web/dist/assets/{ruby-BfhTj9bK.js → ruby-m3xVWkBq.js} +1 -1
- package/apps/web/dist/index.html +2 -2
- package/dist/agent/config/settingsEnDisco.js +44 -4
- package/dist/agent/config/settingsEnDisco.js.map +1 -1
- package/dist/agent/tareas/tareasEnDisco.js +23 -1
- package/dist/agent/tareas/tareasEnDisco.js.map +1 -1
- package/dist/core/dispositivoDeSesion.js +2 -7
- package/dist/core/dispositivoDeSesion.js.map +1 -1
- package/dist/core/dispositivoElegido.js +22 -0
- package/dist/core/dispositivoElegido.js.map +1 -0
- package/dist/core/puertosDeAvd.js +53 -8
- package/dist/core/puertosDeAvd.js.map +1 -1
- package/dist/core/settings.js +21 -1
- package/dist/core/settings.js.map +1 -1
- package/dist/core/tareas.js +29 -0
- package/dist/core/tareas.js.map +1 -1
- package/dist/web/servidor/arranque.js +192 -12
- package/dist/web/servidor/arranque.js.map +1 -1
- package/dist/web/servidor/corredorDeTareas.js +27 -5
- package/dist/web/servidor/corredorDeTareas.js.map +1 -1
- package/dist/web/servidor/transporte.js.map +1 -1
- package/dist/web/servidor/vestibulo.js +26 -1
- package/dist/web/servidor/vestibulo.js.map +1 -1
- package/package.json +1 -1
- package/skills/xone-hotswap/SKILL.md +4 -2
- package/skills/xone-hotswap/lib/dispositivo.mjs +106 -1
- package/skills/xone-hotswap/scripts/xone-desplegar-android +3 -1
- package/skills/xone-hotswap/scripts/xone-hotswap +4 -1
- package/skills/xone-hotswap/scripts/xone-reiniciar-android +3 -1
- package/apps/web/dist/assets/index-BKbTb9C_.js +0 -506
- package/apps/web/dist/assets/index-QE7QDed9.css +0 -1
|
@@ -179,9 +179,55 @@ export function ajusteDelAvd(avd, { casa = homedir(), leer = (r) => readFileSync
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
+
/** La forma de un serial de adb. Copia de `core/puertosDeAvd.ts#FORMA_DE_SERIE`. */
|
|
183
|
+
export const FORMA_DE_SERIE = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
184
|
+
|
|
185
|
+
const puertoValido = (p) => Number.isInteger(p) && p >= 1024 && p <= 65535;
|
|
186
|
+
|
|
187
|
+
/** `dispositivos` de `~/.xonecode/settings.json`, o `{}`. Se lee en CADA ejecución, como el resto. */
|
|
188
|
+
function ajustesDeDispositivos({ casa = homedir(), leer = (r) => readFileSync(r, "utf8") } = {}) {
|
|
189
|
+
try {
|
|
190
|
+
const d = JSON.parse(leer(join(casa, ".xonecode", "settings.json")))?.dispositivos;
|
|
191
|
+
return typeof d === "object" && d !== null ? d : {};
|
|
192
|
+
} catch {
|
|
193
|
+
return {};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Los puertos ya guardados, de AVD y de físicos, con el MISMO filtro que `core/settings.ts`. */
|
|
198
|
+
function puertosGuardados(d) {
|
|
199
|
+
const usados = new Set();
|
|
200
|
+
const de = (tabla, forma) => {
|
|
201
|
+
if (typeof tabla !== "object" || tabla === null) return;
|
|
202
|
+
for (const [clave, valor] of Object.entries(tabla)) {
|
|
203
|
+
if (forma.test(clave) && typeof valor === "object" && valor !== null && puertoValido(valor.puerto)) usados.add(valor.puerto);
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
de(d.avds, FORMA_DE_NOMBRE_DE_AVD);
|
|
207
|
+
de(d.fisicos, FORMA_DE_SERIE);
|
|
208
|
+
return usados;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* El puerto de un móvil FÍSICO (IXCODE-32): el guardado para su serie o, sin él, el primero libre
|
|
213
|
+
* desde el 8443. Antes era siempre el 8443, el mismo que el primer AVD, y el último `adb forward`
|
|
214
|
+
* se quedaba el puerto: la sesión del móvil hablaba con el emulador sin error. Copia de
|
|
215
|
+
* `core/puertosDeAvd.ts#puertoDeFisico` (un test compara las dos).
|
|
216
|
+
*/
|
|
217
|
+
export function puertoDeFisico(serie, deps = {}) {
|
|
218
|
+
const d = ajustesDeDispositivos(deps);
|
|
219
|
+
const guardado = FORMA_DE_SERIE.test(serie ?? "") ? d.fisicos?.[serie]?.puerto : undefined;
|
|
220
|
+
if (puertoValido(guardado)) return guardado;
|
|
221
|
+
const usados = puertosGuardados(d);
|
|
222
|
+
let candidato = PUERTO_DEL_HOTSWAP;
|
|
223
|
+
while (usados.has(candidato)) candidato++;
|
|
224
|
+
return candidato;
|
|
225
|
+
}
|
|
226
|
+
|
|
182
227
|
/**
|
|
183
228
|
* El puerto LOCAL del túnel. De más explícito a menos: `--puerto`, el guardado del AVD de esta
|
|
184
|
-
* serie, 8443. Misma regla que `core/puertosDeAvd.ts#
|
|
229
|
+
* serie (o el del físico), 8443. Misma regla que `core/puertosDeAvd.ts#puertoDeDispositivo`
|
|
230
|
+
* (un test compara las dos).
|
|
185
231
|
*/
|
|
186
232
|
export function puertoAndroid(explicito, serie, deps = {}) {
|
|
187
233
|
return puertoConMotivo(explicito, serie, deps).puerto;
|
|
@@ -196,6 +242,7 @@ export function puertoAndroid(explicito, serie, deps = {}) {
|
|
|
196
242
|
export function puertoConMotivo(explicito, serie, deps = {}) {
|
|
197
243
|
const n = Number(explicito);
|
|
198
244
|
if (explicito !== undefined && Number.isInteger(n) && n >= 1024 && n <= 65535) return { puerto: n };
|
|
245
|
+
if (serie !== undefined && !serie.startsWith("emulator-")) return { puerto: puertoDeFisico(serie, deps) };
|
|
199
246
|
const avd = avdDeLaSerie(serie, deps);
|
|
200
247
|
const guardado = ajusteDelAvd(avd, deps).puerto;
|
|
201
248
|
if (guardado !== undefined) return { puerto: guardado };
|
|
@@ -205,6 +252,64 @@ export function puertoConMotivo(explicito, serie, deps = {}) {
|
|
|
205
252
|
return { puerto: PUERTO_DEL_HOTSWAP };
|
|
206
253
|
}
|
|
207
254
|
|
|
255
|
+
/** De la salida de `adb forward --list`, la serie que tiene el puerto local `tcp:<puerto>`, o `undefined`. Pura. */
|
|
256
|
+
export function duenoDelPuerto(salidaDeForwardList, puerto) {
|
|
257
|
+
for (const linea of String(salidaDeForwardList).split(/\r?\n/)) {
|
|
258
|
+
const [serie, local] = linea.trim().split(/\s+/);
|
|
259
|
+
if (local === `tcp:${puerto}` && serie) return serie;
|
|
260
|
+
}
|
|
261
|
+
return undefined;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* ¿De quién es AHORA el túnel de este puerto? (IXCODE-32). La tabla de `adb forward` es de toda la
|
|
266
|
+
* máquina: si otra sesión, una tarea o una consola le hizo un forward a OTRO aparato en el mismo
|
|
267
|
+
* puerto, los comandos de ésta irían a ese aparato sin error y el script seguiría diciendo
|
|
268
|
+
* «dispositivo: el de la sesión». Comprobar la SERIE no basta; hay que comprobar el puerto.
|
|
269
|
+
*
|
|
270
|
+
* `propio` (es suyo), `libre` (nadie lo tiene), `ajeno` (con `dueno`) o `desconocido` (adb no
|
|
271
|
+
* contestó: no se puede afirmar nada y quien llama sigue como antes).
|
|
272
|
+
*/
|
|
273
|
+
export function estadoDelTunel(serie, puerto, { entorno = process.env, ejecutar = ejecutarAdb } = {}) {
|
|
274
|
+
let salida;
|
|
275
|
+
try {
|
|
276
|
+
salida = ejecutar(rutaDeAdb(entorno), ["forward", "--list"]);
|
|
277
|
+
} catch {
|
|
278
|
+
return { estado: "desconocido" };
|
|
279
|
+
}
|
|
280
|
+
const dueno = duenoDelPuerto(salida, puerto);
|
|
281
|
+
if (dueno === undefined) return { estado: "libre" };
|
|
282
|
+
return dueno === serie ? { estado: "propio" } : { estado: "ajeno", dueno };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Comprueba el túnel antes de usarlo, y lo pone si NADIE lo tiene: sale con 2 si es de otro
|
|
287
|
+
* aparato, y con adb mudo no afirma nada. Devuelve el estado que encontró. `poner` es falso para
|
|
288
|
+
* quien va a poner el túnel él mismo justo después (desplegar, reiniciar).
|
|
289
|
+
*/
|
|
290
|
+
export function asegurarTunel(serie, puerto, { entorno = process.env, ejecutar = ejecutarAdb, negar = negarYSalir, poner = true } = {}) {
|
|
291
|
+
const t = estadoDelTunel(serie, puerto, { entorno, ejecutar });
|
|
292
|
+
if (t.estado === "ajeno") return negar(textoDeTunelAjeno(serie, puerto, t.dueno));
|
|
293
|
+
if (t.estado === "libre" && poner) {
|
|
294
|
+
try {
|
|
295
|
+
ejecutar(rutaDeAdb(entorno), ["-s", serie, "forward", `tcp:${puerto}`, `tcp:${PUERTO_DEL_HOTSWAP}`]);
|
|
296
|
+
process.stderr.write(`túnel: no estaba puesto; ahora 127.0.0.1:${puerto} → ${serie}\n`);
|
|
297
|
+
} catch {
|
|
298
|
+
// Sin túnel la conexión fallará y lo dirá; aquí no hay nada más que afirmar.
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return t;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** Lo que se dice cuando el puerto lo tiene otro aparato: cuál, y que no se le quita. */
|
|
305
|
+
export function textoDeTunelAjeno(serie, puerto, dueno) {
|
|
306
|
+
return (
|
|
307
|
+
`El túnel 127.0.0.1:${puerto} lleva a ${dueno}, no a ${serie}: otra sesión, una tarea o un adb forward a mano ` +
|
|
308
|
+
"se lo quedó. No se le quita, porque dejaría al otro hablando con este aparato. " +
|
|
309
|
+
"Comprueba los puertos en Ajustes → Dispositivos o, si ese aparato ya no se usa, desconéctalo."
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
208
313
|
/**
|
|
209
314
|
* Retira de los argumentos las opciones que llevan valor (`--puerto 9000`), estén donde estén, y
|
|
210
315
|
* deja el resto INTACTO (incluidos `--` y los `clave=valor`). Solo quita lo que ESTÁ: con un
|
|
@@ -49,7 +49,7 @@ import { execFileSync } from "node:child_process";
|
|
|
49
49
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
50
50
|
import { basename, join, relative, sep } from "node:path";
|
|
51
51
|
import { deflateRawSync } from "node:zlib";
|
|
52
|
-
import { serieAndroid, rutaDeAdb, NODE, dormir, PUERTO_DEL_HOTSWAP, puertoConMotivo } from "../lib/dispositivo.mjs";
|
|
52
|
+
import { serieAndroid, rutaDeAdb, NODE, dormir, PUERTO_DEL_HOTSWAP, puertoConMotivo, asegurarTunel } from "../lib/dispositivo.mjs";
|
|
53
53
|
|
|
54
54
|
const PAQUETE = "com.xone.android.framework";
|
|
55
55
|
const ACTIVIDAD = `${PAQUETE}/com.xone.android.hotswap.activities.SetupActivity`;
|
|
@@ -353,6 +353,8 @@ function exigirAparato() {
|
|
|
353
353
|
|
|
354
354
|
exigirAparato();
|
|
355
355
|
console.log(`1/5 túnel: 127.0.0.1:${PUERTO} → ${PUERTO_DEL_HOTSWAP} del aparato`);
|
|
356
|
+
// Antes de ponerlo, que no sea de OTRO aparato (IXCODE-32): quitárselo dejaría al otro hablando con éste.
|
|
357
|
+
if (serie !== undefined) asegurarTunel(serie, PUERTO, { poner: false });
|
|
356
358
|
adb("forward", `tcp:${PUERTO}`, `tcp:${PUERTO_DEL_HOTSWAP}`);
|
|
357
359
|
|
|
358
360
|
console.log("2/5 empaquetando el proyecto (sin .xonecode ni .git)");
|
|
@@ -56,7 +56,7 @@ process.on("warning", (aviso) => {
|
|
|
56
56
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
57
57
|
import { join } from "node:path";
|
|
58
58
|
import { guardarGeometria } from "../lib/geometria.mjs";
|
|
59
|
-
import { dispositivoDeLaSesion, puertoConMotivo, retirarOpciones, serieAndroid, PUERTO_DEL_HOTSWAP } from "../lib/dispositivo.mjs";
|
|
59
|
+
import { asegurarTunel, dispositivoDeLaSesion, puertoConMotivo, retirarOpciones, serieAndroid, PUERTO_DEL_HOTSWAP } from "../lib/dispositivo.mjs";
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* La URL cuando nadie dice `HOTSWAP_URL`: el puerto LOCAL del túnel es del aparato, no un 8443
|
|
@@ -69,6 +69,9 @@ function urlPorOmision(puertoPedido, seriePedida) {
|
|
|
69
69
|
const { serie, porque } = serieAndroid(seriePedida);
|
|
70
70
|
const { puerto, porque: porquePuerto } = puertoConMotivo(puertoPedido, serie);
|
|
71
71
|
if (porquePuerto !== undefined) process.stderr.write(`puerto: ${puerto} (${porquePuerto})\n`);
|
|
72
|
+
// El puerto puede ser de OTRO aparato aunque la serie sea la buena (IXCODE-32): la tabla de
|
|
73
|
+
// `adb forward` es de toda la máquina. Se comprueba antes de hablar; con `--puerto` manda quien lo pasó.
|
|
74
|
+
if (serie !== undefined && puertoPedido === undefined) asegurarTunel(serie, puerto);
|
|
72
75
|
return `wss://127.0.0.1:${puerto}/hotswap`;
|
|
73
76
|
}
|
|
74
77
|
const TOPE_MS = Number(process.env.HOTSWAP_TOPE_MS ?? 40_000);
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import { execFileSync } from "node:child_process";
|
|
24
24
|
import { join } from "node:path";
|
|
25
|
-
import { serieAndroid, rutaDeAdb, NODE, dormir, PUERTO_DEL_HOTSWAP, puertoConMotivo } from "../lib/dispositivo.mjs";
|
|
25
|
+
import { serieAndroid, rutaDeAdb, NODE, dormir, PUERTO_DEL_HOTSWAP, puertoConMotivo, asegurarTunel } from "../lib/dispositivo.mjs";
|
|
26
26
|
|
|
27
27
|
const PAQUETE = "com.xone.android.framework";
|
|
28
28
|
const ACTIVIDAD = `${PAQUETE}/com.xone.android.hotswap.activities.SetupActivity`;
|
|
@@ -102,6 +102,8 @@ exigirAparato();
|
|
|
102
102
|
console.log(`1/3 túnel (127.0.0.1:${PUERTO} → ${PUERTO_DEL_HOTSWAP} del aparato) y parada de ${PAQUETE}`);
|
|
103
103
|
// El túnel PRIMERO y sin quitarlo después: hay que reaplicarlo tras cada reconexión del cable,
|
|
104
104
|
// así que quitarlo dejaría al siguiente hablando con nadie.
|
|
105
|
+
// Antes de ponerlo, que no sea de OTRO aparato (IXCODE-32): quitárselo dejaría al otro hablando con éste.
|
|
106
|
+
if (serie !== undefined) asegurarTunel(serie, PUERTO, { poner: false });
|
|
105
107
|
adb("forward", `tcp:${PUERTO}`, `tcp:${PUERTO_DEL_HOTSWAP}`);
|
|
106
108
|
adb("shell", "am", "force-stop", PAQUETE);
|
|
107
109
|
|