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

add new end game api

parent 6f08f5af
......@@ -3,12 +3,13 @@
#/////////////////////////////////////////////////////////////////////////////
node_modules/
# dist/
dist/
build/
library/
temp/
local/
package-lock.json
.env
#/////////////////////////////////////////////////////////////////////////////
# npm files
......
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const CONFIG = {
GAMEID: {
HUNGQUA: 1000,
},
STATE: {
WATING: 'WATING',
PLAYING: 'PLAYING',
END: 'END',
SELECT: 'SELECT',
},
TIME: {
COUNTDOWN: 10,
SELECT_PLAYER: 5,
PLAY: 60
},
EVT: {
CREATE_ROOM: '100',
JOIN_ROOM: '101',
LEAVE_ROOM: '103',
ROOM_MESSAGE: '104',
START_GAME: '200',
UPDATE_STATE: '201',
UPDATE_SCORE: '202',
UPDATE_TIME_REMAINING: '203',
END_GAME: '204',
SPAWN_TOWER: '205',
CLOSE_QR_VIEW: '206',
SPAWN_ITEM: '205',
PASS_TOWER: '207',
HISTORY: '208',
GAME_MESSAGE: '300',
RECONNECT: '500',
REQUEST_START_GAME: '600',
REQUEST_PASS_TOWER: '601',
REQUEST_SPAWN_TOWER: '602',
REQUEST_HISTORY: '603',
},
HTTP_RESPONSE: {
SUCCESS: {
code: 200,
message: "Success!",
},
ERROR: {
code: 500,
message: "Error!",
}
},
};
exports.default = CONFIG;
......@@ -9,13 +9,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.startGameApi = startGameApi;
exports.endGameApi = endGameApi;
const URL = 'https://dev.gamee.vn/api/web';
exports.startGameApiCtrl = startGameApiCtrl;
exports.endGameApiCtrl = endGameApiCtrl;
const URL = process.env.URL || 'https://dev.gamee.vn/api/web';
const URL_START_GAME = `${URL}/game/start`;
const URL_END_GAME = `${URL}/game/end`;
const GAME_CODE = 'flip-jump';
let token = 'eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MTI1LCJ1c2VybmFtZSI6IlFIU18wMUpEVkZHOE5DUEdBNEtFRUhLWDA4RUJWOCIsImRpc3BsYXlOYW1lIjoiVFJBTiBEVUMgS0hBTkgiLCJlbmFibGVkM'
let tokenTest = 'eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MTI1LCJ1c2VybmFtZSI6IlFIU18wMUpEVkZHOE5DUEdBNEtFRUhLWDA4RUJWOCIsImRpc3BsYXlOYW1lIjoiVFJBTiBEVUMgS0hBTkgiLCJlbmFibGVkM'
+ 'kZBIjpmYWxzZSwibGFzdExvZ2luVGltZSI6IjIwMjUtMDgtMDhUMTQ6MTc6MDcuNzczMTEyMjUzIiwicmVmZXJlbmNlQ29kZSI6IklRVEtUQzRkbGk4NiIsImdlbmRlciI6Ik1BTEUiLCJ2dG1BY2NvdW50'
+ 'SWQiOiIwMUpEVkZHOE5DUEdBNEtFRUhLWDA4RUJWOCIsImRvYiI6IjE5OTktMDItMTciLCJjb2RlIjoiMTIzNDU2NzYiLCJzdWIiOiIxMjUiLCJpYXQiOjE3NTQ2Mzc0MjcsImV4cCI6MTc2MzI3NzQyN30.'
+ 'Wf7PDX2rgqRPajkTL8oHHeYFwZrLpTKmuBO8Va9OGMs';
......@@ -23,7 +23,7 @@ let timeStart = 0;
let userId = 0;
let matchId = '';
let eventId = null;
function startGameApi(data) {
function startGameApiCtrl(data, user) {
return __awaiter(this, void 0, void 0, function* () {
try {
timeStart = new Date().getTime();
......@@ -33,7 +33,7 @@ function startGameApi(data) {
matchId,
gameCode: GAME_CODE,
};
const result = yield callApi(URL_START_GAME, 'POST', data);
const result = yield callApi(URL_START_GAME, 'POST', data, user.token);
return result;
}
catch (error) {
......@@ -41,7 +41,7 @@ function startGameApi(data) {
}
});
}
function endGameApi(user) {
function endGameApiCtrl(user) {
return __awaiter(this, void 0, void 0, function* () {
try {
const playedSeconds = (new Date().getTime() - timeStart) / 1e3;
......@@ -60,7 +60,7 @@ function endGameApi(user) {
gameLevel: user.towerNumber - 1,
details
};
const res = yield callApi(URL_END_GAME, 'POST', params);
const res = yield callApi(URL_END_GAME, 'POST', params, user.token);
return res;
}
catch (error) {
......@@ -68,16 +68,18 @@ function endGameApi(user) {
}
});
}
function callApi(url, method, data) {
function callApi(url, method, data, token) {
return __awaiter(this, void 0, void 0, function* () {
try {
const body = JSON.stringify(data);
let res = yield fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
'X-INTERNAL-KEY': 'X7pL9qW3zT2mK8vR5nY4bJ6hF1cD0aE'
},
body: JSON.stringify(data),
body,
});
const result = yield res.json();
return (result === null || result === void 0 ? void 0 : result.code) == 'success';
......
......@@ -22,6 +22,8 @@ class User {
this.timeStart = 0;
this.isStartGame = true;
this.history = [];
this.isBlacklist = false;
this.connectionTime = new Date();
this.token = user.token;
this.id = user.id;
this.towerNumber = user.towerNumber || 0;
......@@ -38,6 +40,13 @@ class User {
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);
}
isSameHour() {
const now = new Date();
return this.connectionTime.getFullYear() === now.getFullYear() &&
this.connectionTime.getMonth() === now.getMonth() &&
this.connectionTime.getDate() === now.getDate() &&
this.connectionTime.getHours() === now.getHours();
}
reset() {
this.score = 0;
this.totalScore = 0;
......
......@@ -13,15 +13,16 @@ var __importDefault = (this && this.__importDefault) || function (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 admin_ui_1 = require("@socket.io/admin-ui");
require('dotenv').config();
const server_1 = __importDefault(require("./server"));
const socket_1 = require("./socket");
const PORT = process.env.PORT || 6636;
const REDIS_URL = "redis://default:Myreview123@123a@127.0.0.1:6379";
// const REDIS_URL = "redis://127.0.0.1:6379";
const REDIS_URL = process.env.REDIS_URL || "redis://127.0.0.1:6379";
const PATH = '/socketws/socket.io';
exports.redis = (0, redis_1.createClient)({ url: REDIS_URL });
function initRedis() {
......@@ -38,7 +39,28 @@ const io = new socket_io_1.Server(server, {
path: PATH,
cors: {
methods: ["GET", "POST"],
origin: "*"
// origin: "*",
// origin: [
// "https://admin.socket.io",
// "https://play.gamee.vn",
// "https://dev.gamee.vn",
// "http://localhost:7456"
// ],
origin: (origin, callback) => {
const allowedOrigins = [
"https://admin.socket.io",
"https://play.gamee.vn",
"https://dev.gamee.vn",
"http://localhost:7456"
];
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
}
else {
callback(new Error("Not allowed by CORS"));
}
},
credentials: true,
}
});
const pubClient = (0, redis_1.createClient)({ url: REDIS_URL });
......@@ -46,6 +68,11 @@ 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");
// http://localhost:6636/admin
(0, admin_ui_1.instrument)(io, {
auth: false,
readonly: true,
});
});
(0, socket_1.setupSocket)(io);
server.listen(PORT, () => {
......
......@@ -11,7 +11,10 @@ app.use(express_1.default.json());
app.get('/', (req, res, next) => {
res.send('Hello World');
});
app.get('/socketws/dev', (req, res, next) => {
res.send('dev');
app.get('/socketws/online', (req, res, next) => {
// const data = getDataStatistical();
// const result = Array.from(data.values());
// res.json(result);
res.send('online');
});
exports.default = app;
This diff is collapsed.
......@@ -23,10 +23,9 @@ export async function endGameCtrl(socket: Socket, user: User) {
}
}
export async function startGameCtrl(socket: Socket, data: any, user: User) {
try {
const result = await startGameApiCtrl(data);
const result = await startGameApiCtrl(data, user);
if (result && user.isStartGame) {
user.reset();
......
import User from "../Model/User";
const URL = 'https://dev.gamee.vn/api/web';
const URL = process.env.URL || 'https://dev.gamee.vn/api/web';
const URL_START_GAME = `${URL}/game/start`;
const URL_END_GAME = `${URL}/game/end`;
const GAME_CODE = 'flip-jump';
let token = 'eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MTI1LCJ1c2VybmFtZSI6IlFIU18wMUpEVkZHOE5DUEdBNEtFRUhLWDA4RUJWOCIsImRpc3BsYXlOYW1lIjoiVFJBTiBEVUMgS0hBTkgiLCJlbmFibGVkM'
let tokenTest = 'eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MTI1LCJ1c2VybmFtZSI6IlFIU18wMUpEVkZHOE5DUEdBNEtFRUhLWDA4RUJWOCIsImRpc3BsYXlOYW1lIjoiVFJBTiBEVUMgS0hBTkgiLCJlbmFibGVkM'
+ 'kZBIjpmYWxzZSwibGFzdExvZ2luVGltZSI6IjIwMjUtMDgtMDhUMTQ6MTc6MDcuNzczMTEyMjUzIiwicmVmZXJlbmNlQ29kZSI6IklRVEtUQzRkbGk4NiIsImdlbmRlciI6Ik1BTEUiLCJ2dG1BY2NvdW50'
+ 'SWQiOiIwMUpEVkZHOE5DUEdBNEtFRUhLWDA4RUJWOCIsImRvYiI6IjE5OTktMDItMTciLCJjb2RlIjoiMTIzNDU2NzYiLCJzdWIiOiIxMjUiLCJpYXQiOjE3NTQ2Mzc0MjcsImV4cCI6MTc2MzI3NzQyN30.'
+ 'Wf7PDX2rgqRPajkTL8oHHeYFwZrLpTKmuBO8Va9OGMs';
......@@ -14,7 +13,7 @@ let userId = 0;
let matchId = '';
let eventId: string | null = null;
export async function startGameApiCtrl(data: any) {
export async function startGameApiCtrl(data: any, user: User) {
try {
timeStart = new Date().getTime();
userId = (Math.random() * 100 >> 0) + 10;
......@@ -24,7 +23,7 @@ export async function startGameApiCtrl(data: any) {
matchId,
gameCode: GAME_CODE,
};
const result = await callApi(URL_START_GAME, 'POST', data);
const result = await callApi(URL_START_GAME, 'POST', data, user.token);
return result;
} catch (error) {
console.log('error', error)
......@@ -51,22 +50,24 @@ export async function endGameApiCtrl(user: User) {
details
}
const res = await callApi(URL_END_GAME, 'POST', params);
const res = await callApi(URL_END_GAME, 'POST', params, user.token);
return res;
} catch (error) {
console.log('error', error)
}
}
async function callApi(url: string, method: string, data: any) {
async function callApi(url: string, method: string, data: any, token: string) {
try {
const body = JSON.stringify(data);
let res = await fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
'X-INTERNAL-KEY': 'X7pL9qW3zT2mK8vR5nY4bJ6hF1cD0aE'
},
body: JSON.stringify(data),
body,
});
const result = await res.json();
return result?.code == 'success';
......
......@@ -4,9 +4,9 @@ import { users } from "../socket";
const ONLINE_KEY = 'socket:online';
const VISITS_KEY = 'socket:visits';
const CONNECT = 'connect';
const DISCONNECT = 'disconnect';
const FIVE_MINUTE_EX = 2 * 60 * 60;
const CONNECT = 'socket:connect';
const DISCONNECT = 'socket:disconnect';
const HOUR_EX = 2 * 60 * 60;
export function setDataStatistical() {
......@@ -17,20 +17,63 @@ export function getDataStatistical() {
};
export function connectedUserCtrl() {
const {today, hour, minute} = getTime5Minute();
const connected5MinuteKey = `${CONNECT}:${today}:${hour}:${minute}`;
redis.incr(connected5MinuteKey);
const { today, hour } = getTime();
const connectedInHourKey = `${CONNECT}:${today}:${hour}`;
const onlineKey = `${ONLINE_KEY}:${today}:${hour}`;
redis.incr(connectedInHourKey);
redis.incr(onlineKey);
}
export function disconnectUserCtrl() {
const {today, hour, minute} = getTime5Minute();
const disconnected5MinuteKey = `${CONNECT}:${today}:${hour}:${minute}`;
redis.incr(disconnected5MinuteKey);
const { today, hour } = getTime();
const disconnectedInHourKey = `${DISCONNECT}:${today}:${hour}`;
const onlineKey = `${ONLINE_KEY}:${today}:${hour}`;
redis.incr(disconnectedInHourKey);
redis.decr(onlineKey);
}
function getTime5Minute() {
function getTime() {
const today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
const hour = new Date().getHours() + 1; // 1-24
const minute = Math.floor(new Date().getMinutes() / 5) * 5; // 0-59
return { today, hour, minute };
return { today, hour };
}
function startAtNextHour() {
console.log('startAtNextHour', 1)
const now = new Date();
// mốc giờ tiếp theo
const nextHour = new Date(now);
nextHour.setHours(now.getHours() + 1, 0, 0, 0);
// số ms còn lại tới đầu giờ tiếp theo
const delay = nextHour.getTime() - now.getTime();
console.log(`Sẽ chạy lần đầu sau ${delay / 1000}s`);
// mốc phút tiếp theo
const nextMinute = new Date(now);
nextMinute.setSeconds(0, 0); // reset giây & ms
nextMinute.setMinutes(now.getMinutes() + 1);
// số ms còn lại tới đầu phút tiếp theo
const delayMinite = nextMinute.getTime() - now.getTime();
setTimeout(() => {
runJob(); // chạy ngay tại đầu giờ
// sau đó lặp lại mỗi 1 giờ (3600000 ms)
setInterval(runJob, 60 * 60 * 1000);
}, delayMinite);
}
function runJob() {
const now = new Date();
console.log("Run job at:", now.toISOString());
// TODO: logic của bạn ở đây
}
// gọi khởi động
// startAtNextHour();
\ No newline at end of file
......@@ -20,6 +20,7 @@ class User {
public isStartGame: boolean = true;
public history: History[] = [];
public isBlacklist: boolean = false;
public connectionTime: Date = new Date();
constructor(user: User) {
this.token = user.token;
......@@ -42,6 +43,14 @@ class User {
this.position = new v2(user.position?.x || 0, user.position?.y || 0);
}
public isSameHour() {
const now = new Date();
return this.connectionTime.getFullYear() === now.getFullYear() &&
this.connectionTime.getMonth() === now.getMonth() &&
this.connectionTime.getDate() === now.getDate() &&
this.connectionTime.getHours() === now.getHours();
}
public reset() {
this.score = 0;
this.totalScore = 0;
......
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";
import { instrument } from "@socket.io/admin-ui";
require('dotenv').config();
import app from "./server";
import { setupSocket } from "./socket";
const PORT = process.env.PORT || 6636;
// const REDIS_URL = "redis://default:Myreview123@123a@127.0.0.1:6379";
const REDIS_URL = "redis://127.0.0.1:6379";
const REDIS_URL = process.env.REDIS_URL || "redis://127.0.0.1:6379";
const PATH = '/socketws/socket.io';
export const redis = createClient({ url: REDIS_URL });
......@@ -28,8 +29,13 @@ const io = new Server(server, {
path: PATH,
cors: {
methods: ["GET", "POST"],
origin: "*",
// origin: ["https://admin.socket.io", "http://localhost:8080"],
// origin: "*",
origin: [
"https://admin.socket.io",
"https://play.gamee.vn",
"https://dev.gamee.vn",
"http://localhost:7456"
],
credentials: true,
}
});
......@@ -41,6 +47,7 @@ Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
io.adapter(createAdapter(pubClient, subClient));
console.log("✅ Socket.IO Redis adapter connected");
// http://localhost:6636/admin
instrument(io, {
auth: false,
readonly: true,
......
import express, { Request, Response, NextFunction } from 'express'
import cors from 'cors';
import { getDataStatistical } from './Controller/statisticalCtrl';
const app = express();
app.use(cors());
......
......@@ -3,6 +3,7 @@ import User, { IRequestPassTower } from "./Model/User";
import { redis } from ".";
import { endGameCtrl, getHistory, passTowerCtrl, startGameCtrl } from "./Controller/gameCtrl";
import CONFIG from "./Config/config";
import { connectedUserCtrl, disconnectUserCtrl } from "./Controller/statisticalCtrl";
export const users: Map<string, User> = new Map<string, User>();
......@@ -24,7 +25,7 @@ export async function setupSocket(io: Server) {
const userJson = await redis.get(`user:${userId}`);
const user = userJson ? JSON.parse(userJson) : null;
const newUser = new User(user || { token, id: userId, isBlacklist} as User);
const newUser = new User(user || { token, id: userId } as User);
newUser.isBlacklist = isBlacklist;
users.set(userId, newUser);
......@@ -44,11 +45,13 @@ export async function setupSocket(io: Server) {
const userId = String(socket.handshake.query.userId);
const user = users.get(userId)!;
if (!user.isSameHour()) {
connectedUserCtrl();
}
socket.on(CONFIG.EVT.START_GAME, (data: string) => startGameCtrl(socket, data, user));
socket.on(CONFIG.EVT.PASS_TOWER, async (data: IRequestPassTower) => await passTowerCtrl(socket, data, user));
socket.on(CONFIG.EVT.HISTORY, async () => await getHistory(socket, user));
socket.on(CONFIG.EVT.END_GAME, () => endGameCtrl(socket, user));
socket.on("disconnect", async () => await onDisconnect(socket, user));
......@@ -61,7 +64,9 @@ export async function setupSocket(io: Server) {
async function onDisconnect(socket: Socket, user: User) {
try {
console.log(`🔴 Client disconnected: ${socket.id}`)
if (!user.isSameHour()) {
disconnectUserCtrl();
}
await redis.set(`user:${user.id}`, JSON.stringify(user));
await redis.expire(`user:${user.id}`, TIME_EX);
users.delete(user.id);
......
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