ts-game-decorators 1.0.4 β 1.0.6
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/dist/index.d.ts +0 -2
- package/dist/index.js +0 -2
- package/dist/lib/config/redis.d.ts +7 -0
- package/dist/lib/config/redis.js +126 -0
- package/dist/lib/db/couchbaseClient.d.ts +4 -0
- package/dist/lib/db/couchbaseClient.js +52 -0
- package/dist/lib/db/lowdbClient.d.ts +5 -0
- package/dist/lib/db/lowdbClient.js +8 -0
- package/dist/lib/decorators/autoRouter.d.ts +7 -0
- package/dist/lib/decorators/autoRouter.js +69 -0
- package/dist/lib/decorators/initServer.d.ts +19 -0
- package/dist/lib/decorators/initServer.js +87 -0
- package/dist/lib/decorators/socketDecorators.d.ts +8 -0
- package/dist/lib/decorators/socketDecorators.js +101 -0
- package/dist/lib/index.d.ts +13 -0
- package/dist/lib/index.js +35 -0
- package/dist/lib/middleware/auth.d.ts +4 -0
- package/dist/lib/middleware/auth.js +56 -0
- package/dist/lib/types/index.d.ts +22 -0
- package/dist/lib/types/index.js +2 -0
- package/dist/lib/utils/utils.d.ts +5 -0
- package/dist/lib/utils/utils.js +38 -0
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -6,8 +6,6 @@ export * from './db/couchbaseClient';
|
|
|
6
6
|
export * from './db/lowdbClient';
|
|
7
7
|
export * from './config/redis';
|
|
8
8
|
export * from './utils/collisionDetector';
|
|
9
|
-
export * from './utils/discordConnector';
|
|
10
|
-
export * from './utils/teleConnector';
|
|
11
9
|
export * from './utils/utils';
|
|
12
10
|
export * from './types';
|
|
13
11
|
export * from './types/map';
|
package/dist/index.js
CHANGED
|
@@ -27,8 +27,6 @@ __exportStar(require("./db/lowdbClient"), exports);
|
|
|
27
27
|
__exportStar(require("./config/redis"), exports);
|
|
28
28
|
// Utils
|
|
29
29
|
__exportStar(require("./utils/collisionDetector"), exports);
|
|
30
|
-
__exportStar(require("./utils/discordConnector"), exports);
|
|
31
|
-
__exportStar(require("./utils/teleConnector"), exports);
|
|
32
30
|
__exportStar(require("./utils/utils"), exports);
|
|
33
31
|
// Types
|
|
34
32
|
__exportStar(require("./types"), exports);
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.closeRedisConnections = exports.getRedisClients = exports.getRedisAdapter = exports.createRedisAdapter = void 0;
|
|
7
|
+
const redis_1 = require("redis");
|
|
8
|
+
const redis_adapter_1 = require("@socket.io/redis-adapter");
|
|
9
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
10
|
+
dotenv_1.default.config();
|
|
11
|
+
const REDIS_URL = process.env.REDIS_URL || 'redis://localhost:6379';
|
|
12
|
+
const REDIS_USERNAME = process.env.REDIS_USERNAME;
|
|
13
|
+
const REDIS_PASSWORD = process.env.REDIS_PASSWORD;
|
|
14
|
+
// Redis client instances for reuse
|
|
15
|
+
let pubClient = null;
|
|
16
|
+
let subClient = null;
|
|
17
|
+
let redisAdapter = null;
|
|
18
|
+
const createRedisAdapter = async () => {
|
|
19
|
+
try {
|
|
20
|
+
console.log('π Connecting to Redis...');
|
|
21
|
+
// Build Redis client configuration
|
|
22
|
+
const redisConfig = {
|
|
23
|
+
url: REDIS_URL,
|
|
24
|
+
socket: {
|
|
25
|
+
reconnectStrategy: (retries) => {
|
|
26
|
+
if (retries > 10) {
|
|
27
|
+
console.error('β Redis: Too many retries, giving up');
|
|
28
|
+
return new Error('Too many retries');
|
|
29
|
+
}
|
|
30
|
+
console.log(`π Redis: Retrying connection (${retries}/10)`);
|
|
31
|
+
return Math.min(retries * 100, 3000);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
// Only add authentication if credentials are provided
|
|
36
|
+
if (REDIS_USERNAME) {
|
|
37
|
+
redisConfig.username = REDIS_USERNAME;
|
|
38
|
+
}
|
|
39
|
+
if (REDIS_PASSWORD) {
|
|
40
|
+
redisConfig.password = REDIS_PASSWORD;
|
|
41
|
+
}
|
|
42
|
+
console.log(`π Redis config: ${REDIS_URL} ${REDIS_USERNAME ? `(username: ${REDIS_USERNAME})` : ''} ${REDIS_PASSWORD ? '(password: ***)' : '(no auth)'}`);
|
|
43
|
+
// Create publisher client
|
|
44
|
+
pubClient = (0, redis_1.createClient)(redisConfig);
|
|
45
|
+
// Create subscriber client (duplicate of publisher)
|
|
46
|
+
subClient = pubClient.duplicate();
|
|
47
|
+
// Error handling for publisher
|
|
48
|
+
pubClient.on('error', (err) => {
|
|
49
|
+
console.error('β Redis Publisher Error:', err);
|
|
50
|
+
});
|
|
51
|
+
pubClient.on('connect', () => {
|
|
52
|
+
console.log('β
Redis Publisher connected');
|
|
53
|
+
});
|
|
54
|
+
pubClient.on('reconnecting', () => {
|
|
55
|
+
console.log('π Redis Publisher reconnecting...');
|
|
56
|
+
});
|
|
57
|
+
// Error handling for subscriber
|
|
58
|
+
subClient.on('error', (err) => {
|
|
59
|
+
console.error('β Redis Subscriber Error:', err);
|
|
60
|
+
});
|
|
61
|
+
subClient.on('connect', () => {
|
|
62
|
+
console.log('β
Redis Subscriber connected');
|
|
63
|
+
});
|
|
64
|
+
subClient.on('reconnecting', () => {
|
|
65
|
+
console.log('π Redis Subscriber reconnecting...');
|
|
66
|
+
});
|
|
67
|
+
// Connect both clients
|
|
68
|
+
await Promise.all([pubClient.connect(), subClient.connect()]);
|
|
69
|
+
// Create Socket.IO Redis adapter
|
|
70
|
+
redisAdapter = (0, redis_adapter_1.createAdapter)(pubClient, subClient, {
|
|
71
|
+
key: 'socket.io',
|
|
72
|
+
requestsTimeout: 5000
|
|
73
|
+
});
|
|
74
|
+
console.log('β
Redis adapter created successfully');
|
|
75
|
+
return redisAdapter;
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
console.error('β Failed to create Redis adapter:', error);
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
exports.createRedisAdapter = createRedisAdapter;
|
|
83
|
+
// Function to get Redis adapter instance
|
|
84
|
+
const getRedisAdapter = () => {
|
|
85
|
+
return redisAdapter;
|
|
86
|
+
};
|
|
87
|
+
exports.getRedisAdapter = getRedisAdapter;
|
|
88
|
+
// Function to get Redis clients for direct operations
|
|
89
|
+
const getRedisClients = () => {
|
|
90
|
+
return { pubClient, subClient };
|
|
91
|
+
};
|
|
92
|
+
exports.getRedisClients = getRedisClients;
|
|
93
|
+
// Graceful shutdown for Redis connections
|
|
94
|
+
const closeRedisConnections = async () => {
|
|
95
|
+
try {
|
|
96
|
+
console.log('π Closing Redis connections...');
|
|
97
|
+
if (pubClient && pubClient.isOpen) {
|
|
98
|
+
try {
|
|
99
|
+
await pubClient.quit();
|
|
100
|
+
console.log('β
Redis Publisher connection closed');
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
console.error('β Error closing Redis Publisher connection:', error);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else if (pubClient) {
|
|
107
|
+
console.log('β οΈ Redis Publisher was already closed');
|
|
108
|
+
}
|
|
109
|
+
if (subClient && subClient.isOpen) {
|
|
110
|
+
try {
|
|
111
|
+
await subClient.quit();
|
|
112
|
+
console.log('β
Redis Subscriber connection closed');
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
console.error('β Error closing Redis Subscriber connection:', error);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else if (subClient) {
|
|
119
|
+
console.log('β οΈ Redis Subscriber was already closed');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
console.error('β Error closing Redis connections:', error);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
exports.closeRedisConnections = closeRedisConnections;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.connectToCouchbase = connectToCouchbase;
|
|
7
|
+
exports.queryData = queryData;
|
|
8
|
+
exports.getCouchbaseUsersCollection = getCouchbaseUsersCollection;
|
|
9
|
+
const couchbase_1 = require("couchbase");
|
|
10
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
11
|
+
dotenv_1.default.config();
|
|
12
|
+
let cluster;
|
|
13
|
+
let bucket;
|
|
14
|
+
let dataCollection;
|
|
15
|
+
async function connectToCouchbase() {
|
|
16
|
+
try {
|
|
17
|
+
// KαΊΏt nα»i vα»i Couchbase Cluster
|
|
18
|
+
cluster = await couchbase_1.Cluster.connect(`couchbase://${process.env.COUCHBASE_URL || '165.22.240.52'}`, {
|
|
19
|
+
username: process.env.COUCHBASE_USERNAME || 'nhat.huy.7996@gmail.com',
|
|
20
|
+
password: process.env.COUCHBASE_PASSWORD || 'oc3qKtHXELXL',
|
|
21
|
+
});
|
|
22
|
+
// LαΊ₯y bucket tα»« cluster
|
|
23
|
+
bucket = cluster.bucket(process.env.COUCHBASE_BUCKET || 'buildAnArmy');
|
|
24
|
+
//Get collection
|
|
25
|
+
dataCollection = bucket.collection('users');
|
|
26
|
+
console.log('β
Connected to Couchbase');
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
console.error('β Failed to connect to Couchbase:', err);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/*
|
|
33
|
+
* query Data from couchbase
|
|
34
|
+
* @param query: string
|
|
35
|
+
* @returns array of rows
|
|
36
|
+
*/
|
|
37
|
+
async function queryData(query) {
|
|
38
|
+
try {
|
|
39
|
+
const result = await cluster.query(query);
|
|
40
|
+
return result.rows; // Return array of rows
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
console.error('Error executing query:', err);
|
|
44
|
+
throw new Error('Failed to fetch top users');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function getCouchbaseUsersCollection() {
|
|
48
|
+
if (!dataCollection) {
|
|
49
|
+
throw new Error('Couchbase is not connected. Call connectToCouchbase first.');
|
|
50
|
+
}
|
|
51
|
+
return dataCollection;
|
|
52
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.db = void 0;
|
|
4
|
+
const lowdb_1 = require("lowdb");
|
|
5
|
+
const node_1 = require("lowdb/node");
|
|
6
|
+
// File lΖ°u dα»― liα»u
|
|
7
|
+
const adapter = new node_1.JSONFile("db.json");
|
|
8
|
+
exports.db = new lowdb_1.Low(adapter, { users: [] });
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { Express } from 'express';
|
|
3
|
+
export declare function RouterController(basePath?: string): ClassDecorator;
|
|
4
|
+
export declare function Get(path: string): MethodDecorator;
|
|
5
|
+
export declare function Post(path: string): MethodDecorator;
|
|
6
|
+
export declare function Authen(): MethodDecorator & ClassDecorator;
|
|
7
|
+
export declare function registerRoutes(app: Express, authMiddleware: any, ...controllers: any[]): void;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RouterController = RouterController;
|
|
4
|
+
exports.Get = Get;
|
|
5
|
+
exports.Post = Post;
|
|
6
|
+
exports.Authen = Authen;
|
|
7
|
+
exports.registerRoutes = registerRoutes;
|
|
8
|
+
require("reflect-metadata");
|
|
9
|
+
const express_1 = require("express");
|
|
10
|
+
const ROUTER_META = Symbol('router');
|
|
11
|
+
const ROUTES_META = Symbol('routes');
|
|
12
|
+
const AUTHEN_META = Symbol('authen');
|
|
13
|
+
function RouterController(basePath = '') {
|
|
14
|
+
return (target) => {
|
|
15
|
+
Reflect.defineMetadata(ROUTER_META, basePath, target);
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function Get(path) {
|
|
19
|
+
return (target, propertyKey) => {
|
|
20
|
+
const routes = Reflect.getMetadata(ROUTES_META, target.constructor) || [];
|
|
21
|
+
routes.push({ method: 'get', path, handler: propertyKey });
|
|
22
|
+
Reflect.defineMetadata(ROUTES_META, routes, target.constructor);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function Post(path) {
|
|
26
|
+
return (target, propertyKey) => {
|
|
27
|
+
const routes = Reflect.getMetadata(ROUTES_META, target.constructor) || [];
|
|
28
|
+
routes.push({ method: 'post', path, handler: propertyKey });
|
|
29
|
+
Reflect.defineMetadata(ROUTES_META, routes, target.constructor);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function Authen() {
|
|
33
|
+
return (target, propertyKey) => {
|
|
34
|
+
if (propertyKey) {
|
|
35
|
+
// Method
|
|
36
|
+
const authenMethods = Reflect.getMetadata(AUTHEN_META, target.constructor) || [];
|
|
37
|
+
authenMethods.push(propertyKey);
|
|
38
|
+
Reflect.defineMetadata(AUTHEN_META, authenMethods, target.constructor);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
// Class
|
|
42
|
+
Reflect.defineMetadata(AUTHEN_META, true, target);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function registerRoutes(app, authMiddleware, ...controllers) {
|
|
47
|
+
controllers.forEach(Controller => {
|
|
48
|
+
const basePath = Reflect.getMetadata(ROUTER_META, Controller) || '';
|
|
49
|
+
const routes = Reflect.getMetadata(ROUTES_META, Controller) || [];
|
|
50
|
+
const classAuthen = Reflect.getMetadata(AUTHEN_META, Controller);
|
|
51
|
+
const instance = new Controller();
|
|
52
|
+
const router = (0, express_1.Router)();
|
|
53
|
+
routes.forEach((route) => {
|
|
54
|
+
const handler = (req, res, next) => {
|
|
55
|
+
Promise.resolve(instance[route.handler](req, res, next)).catch(next);
|
|
56
|
+
};
|
|
57
|
+
const methodAuthenArr = Reflect.getMetadata(AUTHEN_META, Controller) || [];
|
|
58
|
+
const methodAuthen = Array.isArray(methodAuthenArr) && methodAuthenArr.includes(route.handler);
|
|
59
|
+
const routeMethod = route.method;
|
|
60
|
+
if (classAuthen || methodAuthen) {
|
|
61
|
+
router[routeMethod](route.path, authMiddleware, handler);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
router[routeMethod](route.path, handler);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
app.use(basePath, router);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Express } from 'express';
|
|
2
|
+
import { Server as HTTPServer } from 'http';
|
|
3
|
+
import { Server as SocketIOServer } from 'socket.io';
|
|
4
|
+
export interface InitOptions {
|
|
5
|
+
port: number;
|
|
6
|
+
apiControllers?: any[];
|
|
7
|
+
socketServices?: any[];
|
|
8
|
+
authAPIMiddleware?: any;
|
|
9
|
+
onReady?: (app: Express, io: SocketIOServer, httpServer: HTTPServer) => void;
|
|
10
|
+
publicPath?: string;
|
|
11
|
+
expressConfig?: (app: Express) => void;
|
|
12
|
+
socketConfig?: (io: SocketIOServer) => void;
|
|
13
|
+
createRedisAdapter?: () => Promise<any>;
|
|
14
|
+
}
|
|
15
|
+
export declare function initServer(options: InitOptions): Promise<{
|
|
16
|
+
app: import("express-serve-static-core").Express;
|
|
17
|
+
io: SocketIOServer<import("socket.io").DefaultEventsMap, import("socket.io").DefaultEventsMap, import("socket.io").DefaultEventsMap, any>;
|
|
18
|
+
httpServer: HTTPServer;
|
|
19
|
+
}>;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.initServer = initServer;
|
|
7
|
+
const express_1 = __importDefault(require("express"));
|
|
8
|
+
const http_1 = require("http");
|
|
9
|
+
const socket_io_1 = require("socket.io");
|
|
10
|
+
const autoRouter_1 = require("./autoRouter");
|
|
11
|
+
const socketDecorators_1 = require("./socketDecorators");
|
|
12
|
+
async function initServer(options) {
|
|
13
|
+
const app = (0, express_1.default)();
|
|
14
|
+
const httpServer = (0, http_1.createServer)(app);
|
|
15
|
+
const io = new socket_io_1.Server(httpServer, {
|
|
16
|
+
cors: {
|
|
17
|
+
origin: '*',
|
|
18
|
+
methods: ['GET', 'POST']
|
|
19
|
+
},
|
|
20
|
+
transports: ['websocket', 'polling'],
|
|
21
|
+
allowUpgrades: true,
|
|
22
|
+
connectTimeout: 45000,
|
|
23
|
+
pingTimeout: 60000,
|
|
24
|
+
pingInterval: 25000,
|
|
25
|
+
cookie: {
|
|
26
|
+
name: 'io',
|
|
27
|
+
httpOnly: true,
|
|
28
|
+
secure: true,
|
|
29
|
+
sameSite: 'none',
|
|
30
|
+
maxAge: 24 * 60 * 60 * 1000
|
|
31
|
+
},
|
|
32
|
+
connectionStateRecovery: {
|
|
33
|
+
maxDisconnectionDuration: 2 * 60 * 1000,
|
|
34
|
+
skipMiddlewares: true,
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
// Redis adapter support
|
|
38
|
+
if (options.createRedisAdapter) {
|
|
39
|
+
try {
|
|
40
|
+
const redisAdapter = await options.createRedisAdapter();
|
|
41
|
+
if (redisAdapter) {
|
|
42
|
+
io.adapter(redisAdapter);
|
|
43
|
+
console.log('β
Socket.IO Redis adapter configured');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
console.warn('β οΈ Redis adapter failed to initialize, using default adapter:', err);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Express config
|
|
51
|
+
app.use(express_1.default.json());
|
|
52
|
+
app.use((req, res, next) => {
|
|
53
|
+
res.header('Access-Control-Allow-Origin', '*');
|
|
54
|
+
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
|
|
55
|
+
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
56
|
+
res.header('Access-Control-Allow-Credentials', 'true');
|
|
57
|
+
next();
|
|
58
|
+
});
|
|
59
|
+
if (options.publicPath) {
|
|
60
|
+
app.use(express_1.default.static(options.publicPath));
|
|
61
|
+
}
|
|
62
|
+
if (options.expressConfig) {
|
|
63
|
+
options.expressConfig(app);
|
|
64
|
+
}
|
|
65
|
+
// Register API controllers
|
|
66
|
+
if (options.apiControllers && options.apiControllers.length > 0) {
|
|
67
|
+
(0, autoRouter_1.registerRoutes)(app, options.authAPIMiddleware, ...options.apiControllers);
|
|
68
|
+
}
|
|
69
|
+
// Register socket services
|
|
70
|
+
if (options.socketServices && options.socketServices.length > 0) {
|
|
71
|
+
(0, socketDecorators_1.registerSocketServices)(io, ...options.socketServices);
|
|
72
|
+
}
|
|
73
|
+
if (options.socketConfig) {
|
|
74
|
+
options.socketConfig(io);
|
|
75
|
+
}
|
|
76
|
+
// Error handling
|
|
77
|
+
app.use((err, req, res, next) => {
|
|
78
|
+
console.error('Error:', err);
|
|
79
|
+
res.status(500).json({ error: 'Something went wrong!', details: err.message });
|
|
80
|
+
});
|
|
81
|
+
httpServer.listen(options.port, () => {
|
|
82
|
+
console.log(`Server is running on http://localhost:${options.port}`);
|
|
83
|
+
if (options.onReady)
|
|
84
|
+
options.onReady(app, io, httpServer);
|
|
85
|
+
});
|
|
86
|
+
return { app, io, httpServer };
|
|
87
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { Server } from 'socket.io';
|
|
3
|
+
export declare function AuthenSocket(): MethodDecorator & ClassDecorator;
|
|
4
|
+
export declare function SocketService(): ClassDecorator;
|
|
5
|
+
export declare function OnEvent(event: string): MethodDecorator;
|
|
6
|
+
export declare function OnDisconnect(): MethodDecorator;
|
|
7
|
+
export declare function OnError(): MethodDecorator;
|
|
8
|
+
export declare function registerSocketServices(io: Server, ...serviceClasses: any[]): void;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuthenSocket = AuthenSocket;
|
|
4
|
+
exports.SocketService = SocketService;
|
|
5
|
+
exports.OnEvent = OnEvent;
|
|
6
|
+
exports.OnDisconnect = OnDisconnect;
|
|
7
|
+
exports.OnError = OnError;
|
|
8
|
+
exports.registerSocketServices = registerSocketServices;
|
|
9
|
+
require("reflect-metadata");
|
|
10
|
+
const SOCKET_SERVICE_META = Symbol('socket_service');
|
|
11
|
+
const SOCKET_EVENTS_META = Symbol('socket_events');
|
|
12
|
+
const SOCKET_AUTHEN_META = Symbol('socket_authen');
|
|
13
|
+
// Decorator cho xΓ‘c thα»±c socket
|
|
14
|
+
function AuthenSocket() {
|
|
15
|
+
return (target, propertyKey) => {
|
|
16
|
+
if (propertyKey) {
|
|
17
|
+
// Method
|
|
18
|
+
const authenMethods = Reflect.getMetadata(SOCKET_AUTHEN_META, target.constructor) || [];
|
|
19
|
+
authenMethods.push(propertyKey);
|
|
20
|
+
Reflect.defineMetadata(SOCKET_AUTHEN_META, authenMethods, target.constructor);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
// Class
|
|
24
|
+
Reflect.defineMetadata(SOCKET_AUTHEN_META, true, target);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function SocketService() {
|
|
29
|
+
return (target) => {
|
|
30
|
+
Reflect.defineMetadata(SOCKET_SERVICE_META, true, target);
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function OnEvent(event) {
|
|
34
|
+
return (target, propertyKey) => {
|
|
35
|
+
const events = Reflect.getMetadata(SOCKET_EVENTS_META, target.constructor) || [];
|
|
36
|
+
events.push({ type: 'event', event, handler: propertyKey });
|
|
37
|
+
Reflect.defineMetadata(SOCKET_EVENTS_META, events, target.constructor);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function OnDisconnect() {
|
|
41
|
+
return (target, propertyKey) => {
|
|
42
|
+
const events = Reflect.getMetadata(SOCKET_EVENTS_META, target.constructor) || [];
|
|
43
|
+
events.push({ type: 'disconnect', handler: propertyKey });
|
|
44
|
+
Reflect.defineMetadata(SOCKET_EVENTS_META, events, target.constructor);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function OnError() {
|
|
48
|
+
return (target, propertyKey) => {
|
|
49
|
+
const events = Reflect.getMetadata(SOCKET_EVENTS_META, target.constructor) || [];
|
|
50
|
+
events.push({ type: 'error', handler: propertyKey });
|
|
51
|
+
Reflect.defineMetadata(SOCKET_EVENTS_META, events, target.constructor);
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function registerSocketServices(io, ...serviceClasses) {
|
|
55
|
+
// Import middleware xΓ‘c thα»±c socket
|
|
56
|
+
const { authSocketToken } = require('../middleware/auth');
|
|
57
|
+
io.on('connection', (socket) => {
|
|
58
|
+
serviceClasses.forEach(ServiceClass => {
|
|
59
|
+
if (!Reflect.getMetadata(SOCKET_SERVICE_META, ServiceClass))
|
|
60
|
+
return;
|
|
61
|
+
// NαΊΏu class nhαΊn io α» constructor thΓ¬ truyα»n vΓ o
|
|
62
|
+
let instance;
|
|
63
|
+
try {
|
|
64
|
+
instance = new ServiceClass(io);
|
|
65
|
+
}
|
|
66
|
+
catch (_a) {
|
|
67
|
+
instance = new ServiceClass();
|
|
68
|
+
}
|
|
69
|
+
const events = Reflect.getMetadata(SOCKET_EVENTS_META, ServiceClass) || [];
|
|
70
|
+
const classAuthen = Reflect.getMetadata(SOCKET_AUTHEN_META, ServiceClass);
|
|
71
|
+
const methodAuthenArr = Reflect.getMetadata(SOCKET_AUTHEN_META, ServiceClass) || [];
|
|
72
|
+
events.forEach((evt) => {
|
|
73
|
+
const methodAuthen = Array.isArray(methodAuthenArr) && methodAuthenArr.includes(evt.handler);
|
|
74
|
+
const needAuth = classAuthen || methodAuthen;
|
|
75
|
+
const handler = (...args) => {
|
|
76
|
+
Promise.resolve(instance[evt.handler](socket, ...args)).catch(console.error);
|
|
77
|
+
};
|
|
78
|
+
if (evt.type === 'event') {
|
|
79
|
+
socket.on(evt.event, (...args) => {
|
|
80
|
+
if (needAuth) {
|
|
81
|
+
authSocketToken(socket, (err) => {
|
|
82
|
+
if (err)
|
|
83
|
+
return socket.emit('server:error', err.message);
|
|
84
|
+
handler(...args);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
handler(...args);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
else if (evt.type === 'disconnect') {
|
|
93
|
+
socket.on('disconnect', (...args) => handler(...args));
|
|
94
|
+
}
|
|
95
|
+
else if (evt.type === 'error') {
|
|
96
|
+
socket.on('error', (...args) => handler(...args));
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from './decorators/autoRouter';
|
|
2
|
+
export * from './decorators/socketDecorators';
|
|
3
|
+
export * from './decorators/initServer';
|
|
4
|
+
export * from './middleware/auth';
|
|
5
|
+
export * from './db/couchbaseClient';
|
|
6
|
+
export * from './db/lowdbClient';
|
|
7
|
+
export * from './config/redis';
|
|
8
|
+
export * from '../utils/collisionDetector';
|
|
9
|
+
export * from './utils/discordConnector';
|
|
10
|
+
export * from './utils/teleConnector';
|
|
11
|
+
export * from './utils/utils';
|
|
12
|
+
export * from './types';
|
|
13
|
+
export * from '../types/map';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// Decorators
|
|
18
|
+
__exportStar(require("./decorators/autoRouter"), exports);
|
|
19
|
+
__exportStar(require("./decorators/socketDecorators"), exports);
|
|
20
|
+
__exportStar(require("./decorators/initServer"), exports);
|
|
21
|
+
// Middleware
|
|
22
|
+
__exportStar(require("./middleware/auth"), exports);
|
|
23
|
+
// DB
|
|
24
|
+
__exportStar(require("./db/couchbaseClient"), exports);
|
|
25
|
+
__exportStar(require("./db/lowdbClient"), exports);
|
|
26
|
+
// Redis
|
|
27
|
+
__exportStar(require("./config/redis"), exports);
|
|
28
|
+
// Utils
|
|
29
|
+
__exportStar(require("../utils/collisionDetector"), exports);
|
|
30
|
+
__exportStar(require("./utils/discordConnector"), exports);
|
|
31
|
+
__exportStar(require("./utils/teleConnector"), exports);
|
|
32
|
+
__exportStar(require("./utils/utils"), exports);
|
|
33
|
+
// Types
|
|
34
|
+
__exportStar(require("./types"), exports);
|
|
35
|
+
__exportStar(require("../types/map"), exports);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Response, NextFunction } from 'express';
|
|
2
|
+
import { AuthenticatedRequest, AuthenticatedSocket } from '../types';
|
|
3
|
+
export declare const authAPIToken: (req: AuthenticatedRequest, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
|
|
4
|
+
export declare const authSocketToken: (socket: AuthenticatedSocket, next: (err?: Error) => void) => void;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.authSocketToken = exports.authAPIToken = void 0;
|
|
4
|
+
const utils_1 = require("../utils/utils");
|
|
5
|
+
const authAPIToken = (req, res, next) => {
|
|
6
|
+
// Skip authentication for OPTIONS requests (CORS preflight)
|
|
7
|
+
if (req.method === 'OPTIONS') {
|
|
8
|
+
console.log('π Skipping auth for OPTIONS request (CORS preflight)');
|
|
9
|
+
return next();
|
|
10
|
+
}
|
|
11
|
+
console.log('π Request method:', req.method);
|
|
12
|
+
console.log('π Request URL:', req.url);
|
|
13
|
+
const auth = req.headers.authorization; // "Bearer <token>"
|
|
14
|
+
const token = (auth === null || auth === void 0 ? void 0 : auth.startsWith("Bearer ")) ? auth.slice(7) : undefined;
|
|
15
|
+
console.log('π API authentication token:', token);
|
|
16
|
+
if (!token) {
|
|
17
|
+
return res.status(401).json({
|
|
18
|
+
success: false,
|
|
19
|
+
message: 'No token provided'
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const decoded = utils_1.utils.tokenDecode(token);
|
|
24
|
+
req.userId = decoded.userId;
|
|
25
|
+
console.log('β
API authenticated successfully for walletId:', decoded.walletId);
|
|
26
|
+
next();
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error(error);
|
|
30
|
+
return res.status(403).json({
|
|
31
|
+
success: false,
|
|
32
|
+
message: error
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
exports.authAPIToken = authAPIToken;
|
|
37
|
+
const authSocketToken = (socket, next) => {
|
|
38
|
+
console.log('π Socket authentication middleware triggered for socket:', socket.id);
|
|
39
|
+
try {
|
|
40
|
+
var token = socket.handshake.auth.token;
|
|
41
|
+
console.log(`π Socket authentication token: ${token ? 'Present' : 'Missing'}`);
|
|
42
|
+
// Temporarily allow connections without token for debugging
|
|
43
|
+
if (!token) {
|
|
44
|
+
console.log('β οΈ No token provided, but allowing connection for debugging');
|
|
45
|
+
token = socket.handshake.query.token;
|
|
46
|
+
}
|
|
47
|
+
const decoded = utils_1.utils.tokenDecode(token);
|
|
48
|
+
console.log(decoded);
|
|
49
|
+
socket.userId = decoded.userId;
|
|
50
|
+
next();
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
console.error('β Socket authentication error!');
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
exports.authSocketToken = authSocketToken;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Socket } from 'socket.io';
|
|
2
|
+
import { Request } from 'express';
|
|
3
|
+
export interface ApiResponse {
|
|
4
|
+
success: boolean;
|
|
5
|
+
message: string;
|
|
6
|
+
data?: any;
|
|
7
|
+
}
|
|
8
|
+
export interface AuthenticatedSocket extends Socket {
|
|
9
|
+
userId?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface AuthenticatedRequest extends Request {
|
|
12
|
+
userId?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface Vector3 {
|
|
15
|
+
x: number;
|
|
16
|
+
y: number;
|
|
17
|
+
z: number;
|
|
18
|
+
}
|
|
19
|
+
export interface Vector2 {
|
|
20
|
+
x: number;
|
|
21
|
+
y: number;
|
|
22
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.utils = void 0;
|
|
7
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
9
|
+
dotenv_1.default.config();
|
|
10
|
+
exports.utils = {
|
|
11
|
+
getMinutesPassed: function (startAt) {
|
|
12
|
+
const startDate = new Date(startAt);
|
|
13
|
+
const currentDate = new Date();
|
|
14
|
+
const diffInMilliseconds = currentDate.getTime() - startDate.getTime();
|
|
15
|
+
return Math.floor(diffInMilliseconds / (1000 * 60)); // Chuyα»n Δα»i tα»« milliseconds sang phΓΊt
|
|
16
|
+
},
|
|
17
|
+
tokenDecode(token) {
|
|
18
|
+
const secret = process.env.JWT_SECRET || 'your-secret-key';
|
|
19
|
+
console.log('π JWT Secret status:', process.env.JWT_SECRET ? 'Using environment JWT_SECRET' : 'Using default secret');
|
|
20
|
+
try {
|
|
21
|
+
const decoded = jsonwebtoken_1.default.verify(token, secret);
|
|
22
|
+
return decoded;
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
console.error('β JWT verification failed!');
|
|
26
|
+
console.error('π Token preview:', token.substring(0, 50) + '...');
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
tokenEncode(data) {
|
|
31
|
+
const secret = process.env.JWT_SECRET || 'your-secret-key';
|
|
32
|
+
console.log('π Creating JWT with secret:', process.env.JWT_SECRET ? 'Using environment JWT_SECRET' : 'Using default secret');
|
|
33
|
+
const token = jsonwebtoken_1.default.sign(data, secret, { expiresIn: '7d' });
|
|
34
|
+
console.log('β
JWT token created successfully');
|
|
35
|
+
console.log('π Token:', token);
|
|
36
|
+
return token;
|
|
37
|
+
}
|
|
38
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-game-decorators",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Express & Socket.IO decorators for auto routing and event handling. using for backend game development.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
"redis": "^4.6.7",
|
|
29
29
|
"@socket.io/redis-adapter": "^8.2.0",
|
|
30
30
|
"lowdb": "^6.0.1",
|
|
31
|
-
"couchbase": "^4.2.5"
|
|
31
|
+
"couchbase": "^4.2.5",
|
|
32
|
+
"jsonwebtoken": "^9.0.2"
|
|
32
33
|
},
|
|
33
34
|
"devDependencies": {
|
|
34
35
|
"typescript": "^5.0.0"
|