@pdc-test/chat-io 1.1.1 → 1.1.2
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/bin/cli.js +29 -2
- package/package.json +2 -2
- package/src/server/index.js +24 -10
package/bin/cli.js
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const WebSocket = require('ws');
|
|
3
3
|
const readline = require('readline');
|
|
4
|
+
const { exec } = require('child_process');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const pkgVersion = require('../package.json').version;
|
|
7
|
+
|
|
8
|
+
let soundsEnabled = true;
|
|
9
|
+
|
|
10
|
+
function playSound(type) {
|
|
11
|
+
if (!soundsEnabled) return;
|
|
12
|
+
if (type === 'ding') {
|
|
13
|
+
exec(`powershell -c (New-Object Media.SoundPlayer 'C:\\Windows\\Media\\Windows Notify Email.wav').PlaySync();`);
|
|
14
|
+
} else if (type === 'msg') {
|
|
15
|
+
exec(`powershell -c (New-Object Media.SoundPlayer 'C:\\Windows\\Media\\Windows Proximity Notification.wav').PlaySync();`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
4
18
|
|
|
5
19
|
// ============================================
|
|
6
20
|
// CLIENTE MODULAR RÁPIDO (Carga NATIVA JSON)
|
|
@@ -33,7 +47,7 @@ function clearTopLine() {
|
|
|
33
47
|
}
|
|
34
48
|
|
|
35
49
|
// Interfaz del Teclado Local
|
|
36
|
-
const commands = ['/users', '/flip', '/rps', '/tiendita', '/help', '/w', '/all', '/blink', '/exit', '/clear'];
|
|
50
|
+
const commands = ['/users', '/flip', '/rps', '/tiendita', '/help', '/w', '/all', '/blink', '/exit', '/clear', '/sound', '/v', '/version'];
|
|
37
51
|
let knownUsersList = [];
|
|
38
52
|
|
|
39
53
|
function completer(line) {
|
|
@@ -148,7 +162,7 @@ ws.on('message', (data) => {
|
|
|
148
162
|
break;
|
|
149
163
|
|
|
150
164
|
case "ding":
|
|
151
|
-
|
|
165
|
+
playSound('ding');
|
|
152
166
|
break;
|
|
153
167
|
|
|
154
168
|
case "users_list":
|
|
@@ -161,8 +175,10 @@ ws.on('message', (data) => {
|
|
|
161
175
|
if (res.isWhisper) {
|
|
162
176
|
const dir = res.from === myName ? `Private → ${res.to}` : `${res.emoji} Secreto de ${res.from}`;
|
|
163
177
|
printMessage(`\n[${getTime()}] 🔒 [${dir}]: \x1b[35m${safeMsg}\x1b[0m`);
|
|
178
|
+
if (res.from !== myName) playSound('ding');
|
|
164
179
|
} else {
|
|
165
180
|
printMessage(`\n[${getTime()}] 🌍 [${res.emoji} ${res.from}]: ${safeMsg}`);
|
|
181
|
+
if (res.from !== myName) playSound('msg');
|
|
166
182
|
}
|
|
167
183
|
break;
|
|
168
184
|
|
|
@@ -237,6 +253,15 @@ rl.on('line', (input) => {
|
|
|
237
253
|
}
|
|
238
254
|
|
|
239
255
|
// Local Helper Menú
|
|
256
|
+
if (line.toLowerCase() === "/version" || line.toLowerCase() === "/v") {
|
|
257
|
+
printMessage(`\nℹ️ Versión actual de Chat-IO: \x1b[1m\x1b[33m${pkgVersion}\x1b[0m\n`);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (line.toLowerCase().startsWith("/sound")) {
|
|
261
|
+
soundsEnabled = !soundsEnabled;
|
|
262
|
+
printMessage(`\n🔊 Sonidos ahora están: \x1b[1m\x1b[33m${soundsEnabled ? "ACTIVADOS" : "DESACTIVADOS"}\x1b[0m\n`);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
240
265
|
if (line.toLowerCase() === "/clear") { console.clear(); rl.setPrompt('> '); rl.prompt(true); return; }
|
|
241
266
|
if (line.toLowerCase() === "/exit") {
|
|
242
267
|
printMessage("\x1b[33mSaliendo...\x1b[0m");
|
|
@@ -253,6 +278,8 @@ rl.on('line', (input) => {
|
|
|
253
278
|
🌍 /all → Volver a la Sala Global Abierta
|
|
254
279
|
🏪 /tiendita → Letrero de Neón de colores acelerado
|
|
255
280
|
🧹 /clear → Limpia historial de consola
|
|
281
|
+
🔊 /sound → Activa y desactiva notificaciones y sonidos
|
|
282
|
+
🏷️ /version → Version del producto
|
|
256
283
|
❌ /exit → Salir del chat
|
|
257
284
|
ℹ️ /help → Te ayuda desde la memoria Caché
|
|
258
285
|
─────────────────────────────────────────────\n`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pdc-test/chat-io",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"chat-io": "bin/cli.js"
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"start": "node src/server/index.js"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@pdc-test/chat-io": "^1.1.
|
|
12
|
+
"@pdc-test/chat-io": "^1.1.2",
|
|
13
13
|
"crypto-js": "^4.2.0",
|
|
14
14
|
"ws": "^8.0.0"
|
|
15
15
|
}
|
package/src/server/index.js
CHANGED
|
@@ -41,6 +41,7 @@ function getExactName(name) {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
// State para Tiping
|
|
44
|
+
// typingMap trackea timeouts y a quién se le está escribiendo
|
|
44
45
|
let typingMap = new Map();
|
|
45
46
|
|
|
46
47
|
function broadcastUsers() {
|
|
@@ -56,8 +57,18 @@ function broadcastUsers() {
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
function broadcastTyping() {
|
|
59
|
-
const
|
|
60
|
-
|
|
60
|
+
for (const [s, data] of sessions.entries()) {
|
|
61
|
+
if (s.readyState === WebSocket.OPEN && data.name) {
|
|
62
|
+
const visibleTypers = [];
|
|
63
|
+
for (const [typerName, typeData] of typingMap.entries()) {
|
|
64
|
+
// Si está escribiendo en público (target == null) o le escribe directo a este usuario
|
|
65
|
+
if (!typeData.target || typeData.target.toLowerCase() === data.name.toLowerCase()) {
|
|
66
|
+
visibleTypers.push(typerName);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
try { s.send(JSON.stringify({ type: "typing_event", users: visibleTypers })); } catch(e) {}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
61
72
|
}
|
|
62
73
|
|
|
63
74
|
wss.on("connection", (ws) => {
|
|
@@ -97,7 +108,7 @@ wss.on("connection", (ws) => {
|
|
|
97
108
|
// Limpiar typing automático si envía un mensaje real
|
|
98
109
|
if (req.type === "chat" || req.type === "command") {
|
|
99
110
|
if (typingMap.has(myName)) {
|
|
100
|
-
clearTimeout(typingMap.get(myName));
|
|
111
|
+
clearTimeout(typingMap.get(myName).timer);
|
|
101
112
|
typingMap.delete(myName);
|
|
102
113
|
broadcastTyping();
|
|
103
114
|
}
|
|
@@ -105,17 +116,20 @@ wss.on("connection", (ws) => {
|
|
|
105
116
|
|
|
106
117
|
switch (req.type) {
|
|
107
118
|
case "typing":
|
|
108
|
-
if (typingMap.has(myName)) clearTimeout(typingMap.get(myName));
|
|
109
|
-
typingMap.set(myName,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
119
|
+
if (typingMap.has(myName)) clearTimeout(typingMap.get(myName).timer);
|
|
120
|
+
typingMap.set(myName, {
|
|
121
|
+
target: user.privateTarget,
|
|
122
|
+
timer: setTimeout(() => {
|
|
123
|
+
typingMap.delete(myName);
|
|
124
|
+
broadcastTyping();
|
|
125
|
+
}, 5000)
|
|
126
|
+
});
|
|
113
127
|
broadcastTyping();
|
|
114
128
|
break;
|
|
115
129
|
|
|
116
130
|
case "typing_stop":
|
|
117
131
|
if (typingMap.has(myName)) {
|
|
118
|
-
clearTimeout(typingMap.get(myName));
|
|
132
|
+
clearTimeout(typingMap.get(myName).timer);
|
|
119
133
|
typingMap.delete(myName);
|
|
120
134
|
broadcastTyping();
|
|
121
135
|
}
|
|
@@ -218,7 +232,7 @@ wss.on("connection", (ws) => {
|
|
|
218
232
|
if (u && u.name) {
|
|
219
233
|
broadcast({ type: "system", msg: `🔴 [\x1b[31m${u.emoji} ${u.name}\x1b[0m] abandonó la sala.` }, ws);
|
|
220
234
|
if (typingMap.has(u.name)) {
|
|
221
|
-
clearTimeout(typingMap.get(u.name));
|
|
235
|
+
clearTimeout(typingMap.get(u.name).timer);
|
|
222
236
|
typingMap.delete(u.name);
|
|
223
237
|
broadcastTyping(); // Notificamos de inmediato al mundo para que eliminen su typing UI
|
|
224
238
|
}
|