Commit aa2e697c authored by Vũ Gia Vương's avatar Vũ Gia Vương

add redis

parent 61c5fdb7
......@@ -5,7 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
Object.defineProperty(exports, "__esModule", { value: true });
const v2_1 = __importDefault(require("./v2"));
class User {
constructor(token, id) {
constructor(user) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
this.id = '';
this.token = '';
this.towerNumber = 0;
......@@ -21,9 +22,21 @@ class User {
this.timeStart = 0;
this.isStartGame = true;
this.history = [];
this.token = token;
this.id = id;
this.reset();
this.token = user.token;
this.id = user.id;
this.towerNumber = user.towerNumber || 0;
this.direction = user.direction || 1;
this.distance2Tower = user.distance2Tower || 0;
this.score = user.score || 0;
this.totalScore = user.totalScore || 0;
this.combo = user.combo || 0;
this.timeStart = user.timeStart || 0;
this.isStartGame = user.isStartGame || true;
this.history = ((_a = user.history) === null || _a === void 0 ? void 0 : _a.map(h => new History(h.timeStart, h.timePlayed, h.totalScore, h.tower, h.score))) || [];
this.curBlock = new v2_1.default(((_b = user.curBlock) === null || _b === void 0 ? void 0 : _b.x) || 0, ((_c = user.curBlock) === null || _c === void 0 ? void 0 : _c.y) || 0);
this.nextBlock = new v2_1.default(((_d = user.nextBlock) === null || _d === void 0 ? void 0 : _d.x) || 0, ((_e = user.nextBlock) === null || _e === void 0 ? void 0 : _e.y) || 0);
this.screenPos = new v2_1.default(((_f = user.screenPos) === null || _f === void 0 ? void 0 : _f.x) || 0, ((_g = user.screenPos) === null || _g === void 0 ? void 0 : _g.y) || 0);
this.position = new v2_1.default(((_h = user.position) === null || _h === void 0 ? void 0 : _h.x) || 0, ((_j = user.position) === null || _j === void 0 ? void 0 : _j.y) || 0);
}
reset() {
this.score = 0;
......@@ -46,12 +59,17 @@ class User {
}
}
class History {
constructor() {
constructor(timeStart, timePlayed, totalScore, tower, score) {
this.timeStart = 0;
this.timePlayed = 0;
this.totalScore = 0;
this.tower = 0;
this.score = 0;
this.timeStart = timeStart;
this.timePlayed = timePlayed;
this.totalScore = totalScore;
this.tower = tower;
this.score = score;
}
}
exports.default = User;
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.redis = void 0;
const server_1 = __importDefault(require("./server"));
const http_1 = __importDefault(require("http"));
const socket_io_1 = require("socket.io");
const socket_1 = require("./socket");
const redis_adapter_1 = require("@socket.io/redis-adapter");
const redis_1 = require("redis");
const PORT = 3001;
const REDIS_URL = "redis://127.0.0.1:6379";
exports.redis = (0, redis_1.createClient)({ url: REDIS_URL });
function initRedis() {
return __awaiter(this, void 0, void 0, function* () {
yield exports.redis.connect();
console.log("✅ Redis connected");
});
}
initRedis().catch(err => {
console.error("Redis error:", err);
});
const server = http_1.default.createServer(server_1.default);
const io = new socket_io_1.Server(server, {
path: '/socket',
......@@ -18,21 +41,14 @@ const io = new socket_io_1.Server(server, {
"https://dev.gamee.vn",
"http://localhost:7456"
]
// origin: (origin, callback) => {
// const allowed = [
// "https://play.gamee.vn",
// "https://dev.gamee.vn",
// "http://localhost:7456"
// ];
// if (!origin || allowed.includes(origin)) {
// callback(null, origin);
// } else {
// callback(new Error("Not allowed by CORS"));
// }
// },
// credentials: true,
}
});
const pubClient = (0, redis_1.createClient)({ url: REDIS_URL });
const subClient = pubClient.duplicate();
Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
io.adapter((0, redis_adapter_1.createAdapter)(pubClient, subClient));
console.log("✅ Socket.IO Redis adapter connected");
});
(0, socket_1.setupSocket)(io);
server.listen(PORT, () => {
console.log(`Server is running on port ${PORT}!`);
......
......@@ -16,6 +16,7 @@ exports.setupSocket = setupSocket;
const User_1 = __importDefault(require("./Model/User"));
const v2_1 = __importDefault(require("./Model/v2"));
const networkCtrl_1 = require("./Controller/networkCtrl");
const _1 = require(".");
const users = new Map();
const Y_RADIO = 0.5560472;
const HALF_SIZE_TOWER = 56.43580423808985;
......@@ -36,36 +37,47 @@ const CONFIG = {
REQUEST_HISTORY: '603',
}
};
const TIME_EX = 24 * 60 * 60;
function setupSocket(io) {
try {
io.use((socket, next) => {
const token = String(socket.handshake.query.token);
const userId = String(socket.handshake.query.userId);
if (!token || !userId) {
return;
}
if (!users.has(userId)) {
users.set(userId, new User_1.default(token, userId));
}
next();
});
io.on("connection", (socket) => {
console.log(`🟢 Client connected: ${socket.id}`);
socket.on(CONFIG.EVT.START_GAME, (data) => startGame(socket, data));
socket.on(CONFIG.EVT.PASS_TOWER, (data) => __awaiter(this, void 0, void 0, function* () { return yield passTower(socket, data); }));
socket.on(CONFIG.EVT.HISTORY, () => __awaiter(this, void 0, void 0, function* () { return getHistory(socket); }));
socket.on(CONFIG.EVT.END_GAME, () => endGame(socket));
socket.on("disconnect", () => onDisconnect(socket));
});
}
catch (error) {
console.log('error', error);
}
return __awaiter(this, void 0, void 0, function* () {
try {
io.use((socket, next) => __awaiter(this, void 0, void 0, function* () {
const token = String(socket.handshake.query.token);
const userId = String(socket.handshake.query.userId);
if (!token || !userId) {
return;
}
const keys = yield _1.redis.keys("user:*");
console.log('keys', keys);
const userJson = yield _1.redis.get(`user:${userId}`);
const user = userJson ? JSON.parse(userJson) : null;
const newUser = new User_1.default(user || { token, id: userId });
users.set(userId, newUser);
if (!user) {
yield _1.redis.set(`user:${userId}`, JSON.stringify(user));
yield _1.redis.expire(`user:${user.id}`, TIME_EX);
}
next();
}));
io.on("connection", (socket) => {
console.log(`🟢 Client connected: ${socket.id}`);
const userId = String(socket.handshake.query.userId);
const user = users.get(userId);
socket.on(CONFIG.EVT.START_GAME, (data) => startGame(socket, data, user));
socket.on(CONFIG.EVT.PASS_TOWER, (data) => __awaiter(this, void 0, void 0, function* () { return yield passTower(socket, data, user); }));
socket.on(CONFIG.EVT.HISTORY, () => __awaiter(this, void 0, void 0, function* () { return yield getHistory(socket, user); }));
socket.on(CONFIG.EVT.END_GAME, () => endGame(socket, user));
socket.on("disconnect", () => __awaiter(this, void 0, void 0, function* () { return yield onDisconnect(socket, user); }));
});
}
catch (error) {
console.log('error', error);
}
});
}
function endGame(socket) {
function endGame(socket, user) {
return __awaiter(this, void 0, void 0, function* () {
try {
const user = getUserBySocket(socket);
yield (0, networkCtrl_1.endGameApi)(user);
user.reset();
}
......@@ -74,20 +86,27 @@ function endGame(socket) {
}
});
}
function onDisconnect(socket) {
console.log(`🔴 Client disconnected: ${socket.id}`);
// endGame(socket);
function onDisconnect(socket, user) {
return __awaiter(this, void 0, void 0, function* () {
try {
console.log(`🔴 Client disconnected: ${socket.id}`);
yield _1.redis.set(`user:${user.id}`, JSON.stringify(user));
yield _1.redis.expire(`user:${user.id}`, TIME_EX);
users.delete(user.id);
}
catch (error) {
console.log('error', error);
}
});
}
function getHistory(socket) {
function getHistory(socket, user) {
return __awaiter(this, void 0, void 0, function* () {
const user = getUserBySocket(socket);
socket.emit(CONFIG.EVT.REQUEST_HISTORY, user.history);
});
}
function startGame(socket, data) {
function startGame(socket, data, user) {
return __awaiter(this, void 0, void 0, function* () {
try {
const user = getUserBySocket(socket);
const result = yield (0, networkCtrl_1.startGameApi)(data);
if (result && user.isStartGame) {
user.reset();
......@@ -95,7 +114,7 @@ function startGame(socket, data) {
if (result) {
socket.emit(CONFIG.EVT.REQUEST_START_GAME, true);
user.isStartGame = true;
addBlock(socket);
addBlock(socket, user);
}
else {
console.log('start game fail');
......@@ -107,10 +126,9 @@ function startGame(socket, data) {
}
});
}
function passTower(socket, data) {
function passTower(socket, data, user) {
return __awaiter(this, void 0, void 0, function* () {
try {
const user = getUserBySocket(socket);
let xDistance_ = 0;
const { direction, nextBlock, towerNumber, position } = user;
if (towerNumber > MAX_TOWER) {
......@@ -174,7 +192,7 @@ function passTower(socket, data) {
user.position = target;
socket.emit(CONFIG.EVT.REQUEST_PASS_TOWER, dataSocket);
if (score > 0) {
addBlock(socket);
addBlock(socket, user);
}
else {
socket.emit(CONFIG.EVT.REQUEST_HISTORY, user.history);
......@@ -187,10 +205,9 @@ function passTower(socket, data) {
}
});
}
function addBlock(socket) {
function addBlock(socket, user) {
return __awaiter(this, void 0, void 0, function* () {
try {
const user = getUserBySocket(socket);
const towerNumber = ++user.towerNumber;
const xDistance = ((Math.min(towerNumber, 100) / 100 + 1) + Math.random() * (towerNumber <= 10 ? 0.5 : 1)) * 150;
const yDistance = xDistance * Y_RADIO;
......@@ -201,12 +218,9 @@ function addBlock(socket) {
user.nextBlock.x = user.curBlock.x + (xDistance * user.direction);
user.nextBlock.y = user.curBlock.y + yDistance;
user.distance2Tower = user.nextBlock.distanceTo(user.curBlock);
user.screenPos = user.nextBlock.add(user.curBlock).mul(0.5).sub(new v2_1.default(0, 100));
const data = {
nextBlock: user.nextBlock,
screenPos: user.screenPos,
direction: user.direction,
distance2Tower: user.distance2Tower,
towerNumber: user.towerNumber,
};
user.timeStart = Date.now();
......@@ -217,7 +231,3 @@ function addBlock(socket) {
}
});
}
function getUserBySocket(socket) {
const userId = String(socket.handshake.query.userId);
return users.get(userId);
}
This diff is collapsed.
......@@ -12,12 +12,15 @@
"author": "",
"license": "ISC",
"dependencies": {
"@socket.io/redis-adapter": "^8.3.0",
"@types/express": "^5.0.3",
"cors": "^2.8.5",
"express": "^5.1.0",
"http": "^0.0.1-security",
"nodemon": "^3.1.10",
"redis": "^5.8.1",
"socket.io": "^4.8.1",
"socket.io-redis": "^6.1.1",
"ts-node": "^10.9.2",
"typescript": "^5.9.2"
}
......
......@@ -20,10 +20,25 @@ class User {
public isStartGame: boolean = true;
public history: History[] = [];
constructor(token: string, id: string) {
this.token = token;
this.id = id;
this.reset();
constructor(user: User) {
this.token = user.token;
this.id = user.id;
this.towerNumber = user.towerNumber || 0;
this.direction = user.direction || 1;
this.distance2Tower = user.distance2Tower || 0;
this.score = user.score || 0;
this.totalScore = user.totalScore || 0;
this.combo = user.combo || 0;
this.timeStart = user.timeStart || 0;
this.isStartGame = user.isStartGame || true;
this.history = user.history?.map(h => new History(h.timeStart, h.timePlayed, h.totalScore, h.tower, h.score)) || [];
this.curBlock = new v2(user.curBlock?.x || 0, user.curBlock?.y || 0);
this.nextBlock = new v2(user.nextBlock?.x || 0, user.nextBlock?.y || 0);
this.screenPos = new v2(user.screenPos?.x || 0, user.screenPos?.y || 0);
this.position = new v2(user.position?.x || 0, user.position?.y || 0);
}
public reset() {
......@@ -53,6 +68,14 @@ class History {
public totalScore: number = 0;
public tower: number = 0;
public score: number = 0;
constructor(timeStart: number, timePlayed: number, totalScore: number, tower: number, score: number) {
this.timeStart = timeStart;
this.timePlayed = timePlayed;
this.totalScore = totalScore;
this.tower = tower;
this.score = score;
}
}
export interface IDataPassTower {
......@@ -65,9 +88,7 @@ export interface IDataPassTower {
export interface IDataSpawnTower {
nextBlock: v2,
screenPos: v2,
direction: number,
distance2Tower: number,
towerNumber: number,
}
......
......@@ -2,36 +2,44 @@ import app from "./server";
import http from 'http';
import { Server } from 'socket.io';
import { setupSocket } from "./socket";
import { createAdapter } from "@socket.io/redis-adapter";
import { createClient } from "redis";
const PORT = 3001;
const REDIS_URL = "redis://127.0.0.1:6379";
export const redis = createClient({ url: REDIS_URL });
async function initRedis() {
await redis.connect();
console.log("✅ Redis connected");
}
initRedis().catch(err => {
console.error("Redis error:", err);
});
const server = http.createServer(app);
const io = new Server(server, {
path: '/socket',
cors: {
methods: ["GET", "POST"],
origin:[
"https://play.gamee.vn",
"https://dev.gamee.vn",
"http://localhost:7456"
]
// origin: (origin, callback) => {
// const allowed = [
// "https://play.gamee.vn",
// "https://dev.gamee.vn",
// "http://localhost:7456"
// ];
// if (!origin || allowed.includes(origin)) {
// callback(null, origin);
// } else {
// callback(new Error("Not allowed by CORS"));
// }
// },
// credentials: true,
origin: [
"https://play.gamee.vn",
"https://dev.gamee.vn",
"http://localhost:7456"
]
}
});
const pubClient = createClient({ url: REDIS_URL });
const subClient = pubClient.duplicate();
Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
io.adapter(createAdapter(pubClient, subClient));
console.log("✅ Socket.IO Redis adapter connected");
});
setupSocket(io);
......
......@@ -2,8 +2,10 @@ import { Server, Socket } from "socket.io";
import User, { IDataPassTower, IDataSpawnTower, IRequestPassTower } from "./Model/User";
import v2 from "./Model/v2";
import { endGameApi, startGameApi } from "./Controller/networkCtrl";
import { redis } from ".";
const users: Map<string, User> = new Map<string, User>();
const Y_RADIO: number = 0.5560472;
const HALF_SIZE_TOWER: number = 56.43580423808985;
const INIT_SPEED: number = 300;
......@@ -25,39 +27,52 @@ const CONFIG = {
}
};
export function setupSocket(io: Server) {
const TIME_EX = 24 * 60 * 60;
export async function setupSocket(io: Server) {
try {
io.use((socket: Socket, next) => {
io.use(async (socket: Socket, next) => {
const token = String(socket.handshake.query.token);
const userId = String(socket.handshake.query.userId);
if (!token || !userId) {
return;
}
if (!users.has(userId)) {
users.set(userId, new User(token, userId));
const keys = await redis.keys("user:*");
console.log('keys', keys)
const userJson = await redis.get(`user:${userId}`);
const user = userJson ? JSON.parse(userJson) : null;
const newUser = new User(user || { token, id: userId } as User);
users.set(userId, newUser);
if (!user) {
await redis.set(`user:${userId}`, JSON.stringify(user));
await redis.expire(`user:${user.id}`, TIME_EX);
}
next();
});
io.on("connection", (socket: Socket) => {
console.log(`🟢 Client connected: ${socket.id}`);
const userId = String(socket.handshake.query.userId);
const user = users.get(userId)!;
socket.on(CONFIG.EVT.START_GAME, (data: string) => startGame(socket, data));
socket.on(CONFIG.EVT.PASS_TOWER, async (data: IRequestPassTower) => await passTower(socket, data));
socket.on(CONFIG.EVT.HISTORY, async () => getHistory(socket));
socket.on(CONFIG.EVT.START_GAME, (data: string) => startGame(socket, data, user));
socket.on(CONFIG.EVT.PASS_TOWER, async (data: IRequestPassTower) => await passTower(socket, data, user));
socket.on(CONFIG.EVT.HISTORY, async () => await getHistory(socket, user));
socket.on(CONFIG.EVT.END_GAME, () => endGame(socket));
socket.on(CONFIG.EVT.END_GAME, () => endGame(socket, user));
socket.on("disconnect", () => onDisconnect(socket));
socket.on("disconnect", async () => await onDisconnect(socket, user));
});
} catch (error) {
console.log('error', error)
}
}
async function endGame(socket: Socket) {
async function endGame(socket: Socket, user: User) {
try {
const user = getUserBySocket(socket);
await endGameApi(user);
user.reset();
} catch (error) {
......@@ -65,19 +80,24 @@ async function endGame(socket: Socket) {
}
}
function onDisconnect(socket: Socket): void {
console.log(`🔴 Client disconnected: ${socket.id}`)
// endGame(socket);
async function onDisconnect(socket: Socket, user: User) {
try {
console.log(`🔴 Client disconnected: ${socket.id}`)
await redis.set(`user:${user.id}`, JSON.stringify(user));
await redis.expire(`user:${user.id}`, TIME_EX);
users.delete(user.id);
} catch (error) {
console.log('error', error)
}
}
async function getHistory(socket: Socket) {
const user = getUserBySocket(socket);
async function getHistory(socket: Socket, user: User) {
socket.emit(CONFIG.EVT.REQUEST_HISTORY, user.history);
}
async function startGame(socket: Socket, data: any) {
async function startGame(socket: Socket, data: any, user: User) {
try {
const user = getUserBySocket(socket);
const result = await startGameApi(data);
if (result && user.isStartGame) {
......@@ -87,7 +107,7 @@ async function startGame(socket: Socket, data: any) {
if (result) {
socket.emit(CONFIG.EVT.REQUEST_START_GAME, true);
user.isStartGame = true;
addBlock(socket);
addBlock(socket, user);
} else {
console.log('start game fail');
socket.emit(CONFIG.EVT.REQUEST_START_GAME, false);
......@@ -97,13 +117,12 @@ async function startGame(socket: Socket, data: any) {
}
}
async function passTower(socket: Socket, data: IRequestPassTower) {
async function passTower(socket: Socket, data: IRequestPassTower, user: User) {
try {
const user = getUserBySocket(socket);
let xDistance_ = 0;
const { direction, nextBlock, towerNumber, position } = user;
if (towerNumber > MAX_TOWER) {
let speed = INIT_SPEED;
// data.step = Math.min(data.step, 150);
......@@ -176,7 +195,7 @@ async function passTower(socket: Socket, data: IRequestPassTower) {
socket.emit(CONFIG.EVT.REQUEST_PASS_TOWER, dataSocket);
if (score > 0) {
addBlock(socket);
addBlock(socket, user);
} else {
socket.emit(CONFIG.EVT.REQUEST_HISTORY, user.history);
await endGameApi(user);
......@@ -187,9 +206,8 @@ async function passTower(socket: Socket, data: IRequestPassTower) {
}
}
async function addBlock(socket: Socket) {
async function addBlock(socket: Socket, user: User) {
try {
const user = getUserBySocket(socket);
const towerNumber = ++user.towerNumber;
const xDistance = ((Math.min(towerNumber, 100) / 100 + 1) + Math.random() * (towerNumber <= 10 ? 0.5 : 1)) * 150;
......@@ -202,13 +220,10 @@ async function addBlock(socket: Socket) {
user.nextBlock.x = user.curBlock.x + (xDistance * user.direction);
user.nextBlock.y = user.curBlock.y + yDistance;
user.distance2Tower = user.nextBlock.distanceTo(user.curBlock);
user.screenPos = user.nextBlock.add(user.curBlock).mul(0.5).sub(new v2(0, 100));
const data: IDataSpawnTower = {
nextBlock: user.nextBlock,
screenPos: user.screenPos,
direction: user.direction,
distance2Tower: user.distance2Tower,
towerNumber: user.towerNumber,
};
user.timeStart = Date.now();
......@@ -216,9 +231,4 @@ async function addBlock(socket: Socket) {
} catch (error) {
console.log('error', error)
}
}
function getUserBySocket(socket: Socket) {
const userId = String(socket.handshake.query.userId);
return users.get(userId)!;
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment