@fuzionx/framework 0.1.28 → 0.1.29
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/cli/index.js +66 -53
- package/cli/templates/app/database/models/User.js +9 -0
- package/cli/templates/app/fuzionx.yaml.tpl +3 -3
- package/cli/templates/app/locales/en.json +52 -0
- package/cli/templates/app/locales/ko.json +52 -0
- package/cli/templates/app/package.json.tpl +2 -1
- package/cli/templates/app/shared/events/userEvents.js +10 -0
- package/cli/templates/app/shared/jobs/CleanupJob.js +18 -0
- package/cli/templates/app/shared/jobs/EmailTask.js +17 -0
- package/cli/templates/app/shared/jobs/VideoPreviewTask.js +47 -0
- package/cli/templates/app/shared/workers/heavy.js +18 -0
- package/cli/templates/app/tester/controllers/FileController.js +288 -0
- package/cli/templates/app/tester/controllers/HomeController.js +36 -0
- package/cli/templates/app/tester/controllers/UserController.js +43 -0
- package/cli/templates/app/tester/middleware/RequestLogger.js +13 -0
- package/cli/templates/app/tester/routes/api.js +397 -0
- package/cli/templates/app/tester/routes/web.js +8 -0
- package/cli/templates/app/tester/services/UserService.js +52 -0
- package/cli/templates/app/tester/views/default/errors/404.html +15 -0
- package/cli/templates/app/tester/views/default/errors/500.html +14 -0
- package/cli/templates/app/tester/views/default/layouts/main.html +82 -0
- package/cli/templates/app/tester/views/default/pages/home.html +56 -0
- package/cli/templates/app/tester/views/default/pages/i18n.html +104 -0
- package/cli/templates/app/tester/views/default/pages/upload.html +149 -0
- package/cli/templates/app/tester/views/default/pages/websocket.html +239 -0
- package/cli/templates/app/tester/views/default/partials/footer.html +8 -0
- package/cli/templates/app/tester/views/default/partials/header.html +20 -0
- package/cli/templates/app/tester/ws/ChatHandler.js +98 -0
- package/lib/core/Application.js +1 -1
- package/lib/helpers/Logger.js +6 -6
- package/package.json +2 -2
- /package/cli/templates/app/{controllers → fuzionx/controllers}/HomeController.js +0 -0
- /package/cli/templates/app/{routes → fuzionx/routes}/api.js.tpl +0 -0
- /package/cli/templates/app/{routes → fuzionx/routes}/web.js.tpl +0 -0
- /package/cli/templates/app/{views → fuzionx/views}/default/errors/404.html +0 -0
- /package/cli/templates/app/{views → fuzionx/views}/default/errors/500.html +0 -0
- /package/cli/templates/app/{views → fuzionx/views}/default/layouts/main.html +0 -0
- /package/cli/templates/app/{views → fuzionx/views}/default/pages/home.html +0 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { WsHandler } from '@fuzionx/framework';
|
|
2
|
+
|
|
3
|
+
/** 채팅 WebSocket 핸들러 */
|
|
4
|
+
export default class ChatHandler extends WsHandler {
|
|
5
|
+
static namespace = '/chat';
|
|
6
|
+
static middleware = [];
|
|
7
|
+
|
|
8
|
+
static events(e) {
|
|
9
|
+
e.on('message', ChatHandler.prototype.handleMessage);
|
|
10
|
+
e.on('broadcast', ChatHandler.prototype.handleBroadcast);
|
|
11
|
+
e.on('typing', ChatHandler.prototype.handleTyping);
|
|
12
|
+
e.on('userlist', ChatHandler.prototype.handleUserList);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** 접속자 목록 브로드캐스트 헬퍼 */
|
|
16
|
+
_broadcastUserList(socket) {
|
|
17
|
+
try {
|
|
18
|
+
const count = socket.onlineCount;
|
|
19
|
+
const sessions = socket.sessionIds;
|
|
20
|
+
const payload = JSON.stringify({
|
|
21
|
+
type: 'userlist',
|
|
22
|
+
data: { count, sessions: sessions.map(s => s.slice(0, 8)) },
|
|
23
|
+
});
|
|
24
|
+
socket.broadcast(payload);
|
|
25
|
+
} catch (e) {
|
|
26
|
+
console.error('[Chat] userlist error:', e.message);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async onConnect(socket) {
|
|
31
|
+
const sid = socket.sessionId;
|
|
32
|
+
console.log(`[Chat] 연결: ${sid.slice(0,8)}`);
|
|
33
|
+
// 전체 알림: 새 사용자 입장
|
|
34
|
+
socket.broadcastExcluding(JSON.stringify({
|
|
35
|
+
type: 'system',
|
|
36
|
+
data: { text: `사용자(${sid.slice(0,8)}) 입장`, timestamp: Date.now() },
|
|
37
|
+
}));
|
|
38
|
+
// 접속자 목록 갱신
|
|
39
|
+
this._broadcastUserList(socket);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** message — 본인 제외 전체 전송 */
|
|
43
|
+
async handleMessage(socket, data) {
|
|
44
|
+
const sid = socket.sessionId;
|
|
45
|
+
console.log(`[Chat] msg(${sid.slice(0,8)}): ${JSON.stringify(data)}`);
|
|
46
|
+
const payload = JSON.stringify({
|
|
47
|
+
type: 'message',
|
|
48
|
+
data: { user: sid.slice(0,8), text: data.text || data, timestamp: Date.now() },
|
|
49
|
+
});
|
|
50
|
+
// 본인 제외 전체 전송 (본인은 UI에서 이미 sent로 표시)
|
|
51
|
+
socket.broadcastExcluding(payload);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** broadcast — 본인 제외 전체 전송 (공지) */
|
|
55
|
+
async handleBroadcast(socket, data) {
|
|
56
|
+
const sid = socket.sessionId;
|
|
57
|
+
console.log(`[Chat] broadcast(${sid.slice(0,8)}): ${JSON.stringify(data)}`);
|
|
58
|
+
const payload = JSON.stringify({
|
|
59
|
+
type: 'broadcast',
|
|
60
|
+
data: { user: sid.slice(0,8), text: data.text || data, timestamp: Date.now() },
|
|
61
|
+
});
|
|
62
|
+
socket.broadcastExcluding(payload);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** typing — 본인 제외 전체 전송 */
|
|
66
|
+
async handleTyping(socket, data) {
|
|
67
|
+
const sid = socket.sessionId;
|
|
68
|
+
socket.broadcastExcluding(JSON.stringify({
|
|
69
|
+
type: 'typing',
|
|
70
|
+
data: { user: sid.slice(0,8) },
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** userlist 요청 — 접속자 목록 반환 */
|
|
75
|
+
async handleUserList(socket, data) {
|
|
76
|
+
try {
|
|
77
|
+
const count = socket.onlineCount;
|
|
78
|
+
const sessions = socket.sessionIds;
|
|
79
|
+
return {
|
|
80
|
+
type: 'userlist',
|
|
81
|
+
data: { count, sessions: sessions.map(s => s.slice(0, 8)) },
|
|
82
|
+
};
|
|
83
|
+
} catch (e) {
|
|
84
|
+
return { type: 'userlist', data: { count: 0, sessions: [] } };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async onDisconnect(socket, code, reason) {
|
|
89
|
+
const sid = socket.sessionId;
|
|
90
|
+
console.log(`[Chat] 해제: ${sid.slice(0,8)} code=${code}`);
|
|
91
|
+
socket.broadcastExcluding(JSON.stringify({
|
|
92
|
+
type: 'system',
|
|
93
|
+
data: { text: `사용자(${sid.slice(0,8)}) 퇴장`, timestamp: Date.now() },
|
|
94
|
+
}));
|
|
95
|
+
// 접속자 목록 갱신
|
|
96
|
+
this._broadcastUserList(socket);
|
|
97
|
+
}
|
|
98
|
+
}
|
package/lib/core/Application.js
CHANGED
package/lib/helpers/Logger.js
CHANGED
|
@@ -53,12 +53,12 @@ export default class Logger {
|
|
|
53
53
|
_log(level, message, context) {
|
|
54
54
|
if (this._levels[level] > this._minLevel) return;
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
// Error 객체면 전체 스택 포함
|
|
57
|
+
const isErr = message instanceof Error;
|
|
58
|
+
const text = isErr ? (message.stack || `${message}`) : `${message}`;
|
|
59
|
+
const msg = context ? `${text} ${JSON.stringify(context)}` : text;
|
|
59
60
|
|
|
60
61
|
// ── Bridge N-API 위임 ──
|
|
61
|
-
// Core logger.js 참조: bridge.logInfo(target, msg), bridge.logWarn(target, msg, location?)
|
|
62
62
|
if (this._bridge) {
|
|
63
63
|
try {
|
|
64
64
|
if (level === 'info' && typeof this._bridge.logInfo === 'function') {
|
|
@@ -88,13 +88,13 @@ export default class Logger {
|
|
|
88
88
|
timestamp,
|
|
89
89
|
level,
|
|
90
90
|
target: this._prefix,
|
|
91
|
-
message,
|
|
91
|
+
message: msg,
|
|
92
92
|
...(context || {}),
|
|
93
93
|
};
|
|
94
94
|
console[level === 'debug' ? 'log' : level](JSON.stringify(entry));
|
|
95
95
|
} else {
|
|
96
96
|
const levelTag = level.toUpperCase().padEnd(5);
|
|
97
|
-
const fullMsg = `${timestamp} ${levelTag} [${this._prefix}] ${
|
|
97
|
+
const fullMsg = `${timestamp} ${levelTag} [${this._prefix}] ${msg}`;
|
|
98
98
|
if (context && Object.keys(context).length > 0) {
|
|
99
99
|
console[level === 'debug' ? 'log' : level](fullMsg, context);
|
|
100
100
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fuzionx/framework",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.29",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Full-stack MVC framework built on @fuzionx/core — Controller, Service, Model, Middleware, DI, EventBus",
|
|
6
6
|
"main": "index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"url": "https://github.com/saytohenry/fuzionx"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@fuzionx/core": "^0.1.
|
|
37
|
+
"@fuzionx/core": "^0.1.29",
|
|
38
38
|
"better-sqlite3": "^12.8.0",
|
|
39
39
|
"knex": "^3.2.5",
|
|
40
40
|
"mongoose": "^9.3.2",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|