Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: payment status check #448

Merged
merged 4 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/website/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export default defineNuxtConfig({
},
scheduledTasks: {
'*/10 * * * *': ['game:leaderboard'],
'*/2 * * * *': ['payment:status'],
},
},
modules: [
Expand Down
353 changes: 192 additions & 161 deletions apps/website/server/api/websocket.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { CharacterEditionWithCharacter, GameObject, GameObjectPlayer, WebSocketEvents } from '@chat-game/types'
import type { CharacterEditionWithCharacter, GameObject, GameObjectPlayer, WebSocketConnect, WebSocketConnectAddon, WebSocketDestroyTree, WebSocketEvents, WebSocketMessage, WebSocketNewPlayerTarget } from '@chat-game/types'
import type { Peer } from 'crossws'
import type { WagonRoom } from '../core/rooms/wagon'
import { createId } from '@paralleldrive/cuid2'
import { dropFromTree } from '../core/inventory/drop'
Expand All @@ -7,15 +8,14 @@ import { AddonRoom } from '../core/rooms/addon'

const logger = useLogger('ws')

export function sendMessage(message: WebSocketEvents, token: string): void {
const rooms = activeRooms.filter((room) => room.token === token)

for (const room of rooms) {
const preparedMessage = JSON.stringify({ id: createId(), ...message })
if (room.server.peer?.id) {
room.server.peer.publish(room.id, preparedMessage)
}
export function sendMessage(message: WebSocketEvents, roomId: string) {
const room = activeRooms.find((room) => room.id === roomId)
if (!room || !room.server.peer?.id) {
return
}

const preparedMessage = JSON.stringify({ id: createId(), ...message })
room.server.peer.publish(room.id, preparedMessage)
}

export default defineWebSocketHandler({
Expand All @@ -24,172 +24,203 @@ export default defineWebSocketHandler({
},

async message(peer, message) {
if (message.text().includes('ping')) {
const text = message.text()
if (!text) {
return
}

if (text.includes('ping')) {
peer.send('pong')
return
}

const parsed = JSON.parse(message.text())
if (parsed?.id && parsed?.type) {
if (parsed.type === 'CONNECT') {
const client = parsed.data.client
const id = parsed.data.id

if (client === 'ADDON') {
const token = parsed.data.token
// Create if not exist
if (!activeRooms.find((room) => room.token === token)) {
activeRooms.push(new AddonRoom({ id, token }))
}

const activeRoom = activeRooms.find((room) => room.token === token) as AddonRoom

peer.subscribe(activeRoom.id)
logger.log(`Peer ${peer.id} subscribed to AddonRoom ${activeRoom.id}`)
}

if (client === 'TELEGRAM_CLIENT') {
if (!activeRooms.find((room) => room.id === id)) {
return
}

const activeRoom = activeRooms.find((room) => room.id === id) as WagonRoom

// add to objects
const wagon = activeRoom.objects.find((obj) => obj.type === 'WAGON')
const telegramProfile = await prisma.telegramProfile.findFirst({
where: { telegramId: parsed.data.token },
include: {
profile: true,
},
})
const activeEditionId = telegramProfile?.profile?.activeEditionId
const character = await prisma.characterEdition.findFirst({
where: { id: activeEditionId },
include: { character: true },
}) as CharacterEditionWithCharacter | null
if (!character) {
return
}

// Check, if already exists by Telegram
const playerExist = activeRoom.objects.find((obj) => obj.type === 'PLAYER' && obj.telegramId === parsed.data.token)
if (playerExist) {
return
}

const playerId = createId()

if (!activeRoom.players.find((player) => player.peerId === peer.id)) {
activeRoom.players.push({ id: playerId, peerId: peer.id })
}

activeRoom.addPlayer({ id: playerId, telegramId: parsed.data.token, x: wagon?.x ? wagon.x - 200 : 100, character })

peer.subscribe(activeRoom.id)
void sendMessage({ type: 'CONNECTED_TO_WAGON_ROOM', data: { type: 'PLAYER', roomId: activeRoom.id, id: playerId, objects: activeRoom.objects } }, activeRoom.token)

logger.log(`Telegram client ${parsed.data.token} subscribed to Wagon Room ${activeRoom.id}`, peer.id)
}

if (client === 'WAGON_CLIENT') {
const activeRoom = activeRooms.find((room) => room.id === id) as WagonRoom

const wagonId = createId()
if (!activeRoom.players.find((player) => player.peerId === peer.id)) {
activeRoom.players.push({ id: wagonId, peerId: peer.id })
}

peer.subscribe(activeRoom.id)
void sendMessage({ type: 'CONNECTED_TO_WAGON_ROOM', data: { type: 'WAGON', roomId: activeRoom.id, id: wagonId, objects: activeRoom.objects } }, activeRoom.token)

logger.log(`Wagon client subscribed to Wagon Room ${activeRoom.id}`, peer.id)
}

if (client === 'SERVER') {
const activeRoom = activeRooms.find((room) => room.id === id)
if (!activeRoom) {
return
}

activeRoom.server.peer = peer
peer.subscribe(activeRoom.id)
logger.log(`Server subscribed to Room ${activeRoom.id}`, peer.id)
}
}
if (parsed.type === 'DESTROY_TREE') {
const activeRoom = activeRooms.find((room) => room.players.find((player) => player.peerId === peer.id)) as WagonRoom
if (!activeRoom) {
return
}

const player = activeRoom.players.find((player) => player.peerId === peer.id)
if (!player) {
return
}

const tree = activeRoom.objects.find((obj) => obj.type === 'TREE' && obj.id === parsed.data.id)
if (tree) {
activeRoom.removeObject(tree.id)

const playerObject = activeRoom.objects.find((obj) => obj.type === 'PLAYER' && obj.id === player.id) as GameObject & GameObjectPlayer
if (playerObject) {
await dropFromTree(playerObject.telegramId)
}

peer.publish(activeRoom.id, JSON.stringify({ id: createId(), type: 'DESTROY_TREE', data: { id: tree.id } }))
}
}
if (parsed.type === 'NEW_PLAYER_TARGET') {
const activeRoom = activeRooms.find((room) => room.players.find((player) => player.peerId === peer.id)) as WagonRoom
if (!activeRoom) {
return
}

const player = activeRoom.players.find((player) => player.peerId === peer.id)
if (!player) {
return
}

// Update object
const playerObject = activeRoom.objects.find((obj) => obj.type === 'PLAYER' && obj.id === player.id)
if (playerObject) {
playerObject.x = parsed.data.x
}

peer.publish(activeRoom.id, JSON.stringify({ id: createId(), type: 'NEW_PLAYER_TARGET', data: { id: player.id, x: parsed.data.x } }))
}
const parsed = JSON.parse(text)
if (!parsed || !parsed?.id || !parsed?.type) {
return
}

return handleMessage(parsed as WebSocketMessage, peer)
},

close(peer, event) {
logger.log('close', peer.id, JSON.stringify(event))

// Remove peer from peers array
const room = activeRooms.find((room) => room.players.find((player) => player.peerId === peer.id))
if (room) {
// if player - remove from objects
if (room.type === 'WAGON') {
const wagonRoom = room as WagonRoom
return handleClose(peer)
},

error(peer, error) {
logger.error('error', peer.id, JSON.stringify(error))
},
})

const player = wagonRoom.players.find((player) => player.peerId === peer.id)
if (!player) {
return
}
async function handleMessage(message: WebSocketMessage, peer: Peer) {
switch (message.type) {
case 'CONNECT_ADDON':
return handleConnectAddon(message, peer)
case 'CONNECT':
return handleConnect(message, peer)
case 'DESTROY_TREE':
return handleDestroyTree(message, peer)
case 'NEW_PLAYER_TARGET':
return handleNewPlayerTarget(message, peer)
}
}

const playerObject = wagonRoom.objects.find((obj) => obj.type === 'PLAYER' && obj.id === player.id)
if (playerObject) {
wagonRoom.removeObject(playerObject.id)
}
function handleClose(peer: Peer) {
const room = activeRooms.find((room) => room.clients.find((c) => c.peerId === peer.id))
if (room) {
// if player - remove from objects
if (room.type === 'WAGON') {
const wagonRoom = room as WagonRoom

const player = wagonRoom.clients.find((c) => c.peerId === peer.id)
if (!player) {
return
}

void sendMessage({ type: 'DISCONNECTED_FROM_WAGON_ROOM', data: { id: player.id } }, room.token)
const playerObject = wagonRoom.objects.find((obj) => obj.type === 'PLAYER' && obj.id === player.id)
if (playerObject) {
wagonRoom.removeObject(playerObject.id)
}

room.players = room.players.filter((player) => player.peerId !== peer.id)
sendMessage({ type: 'DISCONNECTED_FROM_WAGON_ROOM', data: { id: player.id } }, room.id)
}
},

error(peer, error) {
logger.error('error', peer.id, JSON.stringify(error))
},
})
room.clients = room.clients.filter((c) => c.peerId !== peer.id)
}
}

function handleConnectAddon(message: WebSocketConnectAddon, peer: Peer) {
const token = message.data.token
// Create if not exist
if (!activeRooms.find((room) => room.id === token)) {
activeRooms.push(new AddonRoom({ token }))
}

const activeRoom = activeRooms.find((room) => room.id === token) as AddonRoom

peer.subscribe(activeRoom.id)
logger.log(`Peer ${peer.id} subscribed to AddonRoom ${activeRoom.id}`)
}

async function handleConnect(message: WebSocketConnect, peer: Peer) {
const client = message.data.client
const id = message.data.id

if (client === 'TELEGRAM_CLIENT') {
if (!message.data.telegramId) {
return
}

if (!activeRooms.find((room) => room.id === id)) {
return
}

const activeRoom = activeRooms.find((room) => room.id === id) as WagonRoom

// add to objects
const wagon = activeRoom.objects.find((obj) => obj.type === 'WAGON')
const telegramProfile = await prisma.telegramProfile.findFirst({
where: { telegramId: message.data.telegramId },
include: {
profile: true,
},
})
const activeEditionId = telegramProfile?.profile?.activeEditionId
const character = await prisma.characterEdition.findFirst({
where: { id: activeEditionId },
include: { character: true },
}) as CharacterEditionWithCharacter | null
if (!character) {
return
}

// Check, if already exists by Telegram
const playerExist = activeRoom.objects.find((obj) => obj.type === 'PLAYER' && obj.telegramId === message.data.telegramId)
if (playerExist) {
return
}

const playerId = createId()

if (!activeRoom.clients.find((c) => c.peerId === peer.id)) {
activeRoom.clients.push({ id: playerId, peerId: peer.id })
}

activeRoom.addPlayer({ id: playerId, telegramId: message.data.telegramId, x: wagon?.x ? wagon.x - 200 : 100, character })

peer.subscribe(activeRoom.id)
sendMessage({ type: 'CONNECTED_TO_WAGON_ROOM', data: { type: 'PLAYER', roomId: activeRoom.id, id: playerId, objects: activeRoom.objects } }, activeRoom.id)

logger.log(`Telegram client ${message.data.telegramId} subscribed to Wagon Room ${activeRoom.id}`, peer.id)
}

if (client === 'WAGON_CLIENT') {
const activeRoom = activeRooms.find((room) => room.id === id) as WagonRoom

const wagonId = createId()
if (!activeRoom.clients.find((c) => c.peerId === peer.id)) {
activeRoom.clients.push({ id: wagonId, peerId: peer.id })
}

peer.subscribe(activeRoom.id)
sendMessage({ type: 'CONNECTED_TO_WAGON_ROOM', data: { type: 'WAGON', roomId: activeRoom.id, id: wagonId, objects: activeRoom.objects } }, activeRoom.id)

logger.log(`Wagon client subscribed to Wagon Room ${activeRoom.id}`, peer.id)
}

if (client === 'SERVER') {
const activeRoom = activeRooms.find((room) => room.id === id)
if (!activeRoom) {
return
}

activeRoom.server.peer = peer
peer.subscribe(activeRoom.id)
logger.log(`Server subscribed to Room ${activeRoom.id}`, peer.id)
}
}

async function handleDestroyTree(message: WebSocketDestroyTree, peer: Peer) {
const activeRoom = activeRooms.find((room) => room.clients.find((c) => c.peerId === peer.id)) as WagonRoom
if (!activeRoom) {
return
}

const player = activeRoom.clients.find((c) => c.peerId === peer.id)
if (!player) {
return
}

const tree = activeRoom.objects.find((obj) => obj.type === 'TREE' && obj.id === message.data.id)
if (tree) {
activeRoom.removeObject(tree.id)

const playerObject = activeRoom.objects.find((obj) => obj.type === 'PLAYER' && obj.id === player.id) as GameObject & GameObjectPlayer
if (playerObject) {
await dropFromTree(playerObject.telegramId)
}

peer.publish(activeRoom.id, JSON.stringify({ id: createId(), type: 'DESTROY_TREE', data: { id: tree.id } }))
}
}

function handleNewPlayerTarget(message: WebSocketNewPlayerTarget, peer: Peer) {
const activeRoom = activeRooms.find((room) => room.clients.find((c) => c.peerId === peer.id)) as WagonRoom
if (!activeRoom) {
return
}

const player = activeRoom.clients.find((c) => c.peerId === peer.id)
if (!player) {
return
}

// Update object
const playerObject = activeRoom.objects.find((obj) => obj.type === 'PLAYER' && obj.id === player.id)
if (playerObject) {
playerObject.x = message.data.x
}

peer.publish(activeRoom.id, JSON.stringify({ id: createId(), type: 'NEW_PLAYER_TARGET', data: { id: player.id, x: message.data.x } }))
}
Loading
Loading