2021-05-09 13:49:40 +02:00
|
|
|
"use strict"
|
|
|
|
|
|
2021-05-29 17:58:05 +02:00
|
|
|
import { ClientEvent, EncodedGame, GameEvent, ReplayData } from '../common/Types'
|
2021-05-29 15:36:03 +02:00
|
|
|
import Util, { logger } from '../common/Util'
|
2021-05-17 00:27:47 +02:00
|
|
|
import Protocol from './../common/Protocol'
|
2020-11-09 01:54:05 +01:00
|
|
|
|
2021-05-15 20:04:30 +02:00
|
|
|
const log = logger('Communication.js')
|
|
|
|
|
|
|
|
|
|
const CODE_GOING_AWAY = 1001
|
|
|
|
|
const CODE_CUSTOM_DISCONNECT = 4000
|
|
|
|
|
|
|
|
|
|
const CONN_STATE_NOT_CONNECTED = 0 // not connected yet
|
|
|
|
|
const CONN_STATE_DISCONNECTED = 1 // not connected, but was connected before
|
|
|
|
|
const CONN_STATE_CONNECTED = 2 // connected
|
|
|
|
|
const CONN_STATE_CONNECTING = 3 // connecting
|
|
|
|
|
const CONN_STATE_CLOSED = 4 // not connected (closed on purpose)
|
|
|
|
|
|
2021-05-17 00:27:47 +02:00
|
|
|
let ws: WebSocket
|
2021-05-29 17:58:05 +02:00
|
|
|
let changesCallback = (msg: Array<any>) => {
|
|
|
|
|
// empty
|
|
|
|
|
}
|
|
|
|
|
let connectionStateChangeCallback = (state: number) => {
|
|
|
|
|
// empty
|
|
|
|
|
}
|
2020-11-09 01:54:05 +01:00
|
|
|
|
2021-05-15 17:40:04 +02:00
|
|
|
// TODO: change these to something like on(EVT, cb)
|
2021-05-29 17:58:05 +02:00
|
|
|
function onServerChange(callback: (msg: Array<any>) => void): void {
|
2020-11-09 01:54:05 +01:00
|
|
|
changesCallback = callback
|
|
|
|
|
}
|
2021-05-29 17:58:05 +02:00
|
|
|
function onConnectionStateChange(callback: (state: number) => void): void {
|
2021-05-15 20:04:30 +02:00
|
|
|
connectionStateChangeCallback = callback
|
2021-05-15 17:40:04 +02:00
|
|
|
}
|
2020-11-09 01:54:05 +01:00
|
|
|
|
2021-05-15 20:04:30 +02:00
|
|
|
let connectionState = CONN_STATE_NOT_CONNECTED
|
2021-05-29 17:58:05 +02:00
|
|
|
const setConnectionState = (state: number): void => {
|
2021-05-17 00:27:47 +02:00
|
|
|
if (connectionState !== state) {
|
|
|
|
|
connectionState = state
|
|
|
|
|
connectionStateChangeCallback(state)
|
2021-05-15 20:04:30 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-05-29 17:58:05 +02:00
|
|
|
function send(message: ClientEvent): void {
|
2021-05-15 20:04:30 +02:00
|
|
|
if (connectionState === CONN_STATE_CONNECTED) {
|
|
|
|
|
try {
|
|
|
|
|
ws.send(JSON.stringify(message))
|
|
|
|
|
} catch (e) {
|
|
|
|
|
log.info('unable to send message.. maybe because ws is invalid?')
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-17 21:46:56 +01:00
|
|
|
}
|
|
|
|
|
|
2021-05-15 20:04:30 +02:00
|
|
|
|
2021-05-17 00:27:47 +02:00
|
|
|
let clientSeq: number
|
2021-05-29 17:58:05 +02:00
|
|
|
let events: Record<number, GameEvent>
|
2021-05-17 00:27:47 +02:00
|
|
|
|
|
|
|
|
function connect(
|
|
|
|
|
address: string,
|
|
|
|
|
gameId: string,
|
|
|
|
|
clientId: string
|
2021-05-29 15:36:03 +02:00
|
|
|
): Promise<EncodedGame> {
|
2020-11-17 21:46:56 +01:00
|
|
|
clientSeq = 0
|
|
|
|
|
events = {}
|
2021-05-15 20:04:30 +02:00
|
|
|
setConnectionState(CONN_STATE_CONNECTING)
|
2021-05-09 21:43:35 +02:00
|
|
|
return new Promise(resolve => {
|
2021-05-15 20:04:30 +02:00
|
|
|
ws = new WebSocket(address, clientId + '|' + gameId)
|
2021-05-29 17:58:05 +02:00
|
|
|
ws.onopen = () => {
|
2021-05-15 20:04:30 +02:00
|
|
|
setConnectionState(CONN_STATE_CONNECTED)
|
|
|
|
|
send([Protocol.EV_CLIENT_INIT])
|
|
|
|
|
}
|
|
|
|
|
ws.onmessage = (e) => {
|
|
|
|
|
const msg = JSON.parse(e.data)
|
2020-11-17 21:46:56 +01:00
|
|
|
const msgType = msg[0]
|
|
|
|
|
if (msgType === Protocol.EV_SERVER_INIT) {
|
|
|
|
|
const game = msg[1]
|
2021-05-09 21:43:35 +02:00
|
|
|
resolve(game)
|
2020-11-17 21:46:56 +01:00
|
|
|
} else if (msgType === Protocol.EV_SERVER_EVENT) {
|
2020-11-17 22:34:15 +01:00
|
|
|
const msgClientId = msg[1]
|
|
|
|
|
const msgClientSeq = msg[2]
|
|
|
|
|
if (msgClientId === clientId && events[msgClientSeq]) {
|
|
|
|
|
delete events[msgClientSeq]
|
2020-11-17 22:47:55 +01:00
|
|
|
// we have already calculated that change locally. probably
|
|
|
|
|
return
|
2020-11-17 22:34:15 +01:00
|
|
|
}
|
2020-11-17 21:46:56 +01:00
|
|
|
changesCallback(msg)
|
2021-05-09 21:43:35 +02:00
|
|
|
} else {
|
|
|
|
|
throw `[ 2021-05-09 invalid connect msgType ${msgType} ]`
|
2020-11-09 01:54:05 +01:00
|
|
|
}
|
2021-05-15 20:04:30 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-29 17:58:05 +02:00
|
|
|
ws.onerror = () => {
|
2021-05-15 20:04:30 +02:00
|
|
|
setConnectionState(CONN_STATE_DISCONNECTED)
|
|
|
|
|
throw `[ 2021-05-15 onerror ]`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ws.onclose = (e) => {
|
|
|
|
|
if (e.code === CODE_CUSTOM_DISCONNECT || e.code === CODE_GOING_AWAY) {
|
|
|
|
|
setConnectionState(CONN_STATE_CLOSED)
|
|
|
|
|
} else {
|
|
|
|
|
setConnectionState(CONN_STATE_DISCONNECTED)
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-09 01:54:05 +01:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-29 12:40:46 +02:00
|
|
|
async function requestReplayData(
|
|
|
|
|
gameId: string,
|
2021-05-29 11:44:55 +02:00
|
|
|
offset: number,
|
|
|
|
|
size: number
|
2021-05-29 15:36:03 +02:00
|
|
|
): Promise<ReplayData> {
|
|
|
|
|
const args = { gameId, offset, size }
|
|
|
|
|
const res = await fetch(`/api/replay-data${Util.asQueryArgs(args)}`)
|
|
|
|
|
const json: ReplayData = await res.json()
|
2021-05-29 12:40:46 +02:00
|
|
|
return json
|
2020-12-22 22:35:09 +01:00
|
|
|
}
|
|
|
|
|
|
2021-05-17 00:27:47 +02:00
|
|
|
function disconnect(): void {
|
2021-05-15 20:04:30 +02:00
|
|
|
if (ws) {
|
|
|
|
|
ws.close(CODE_CUSTOM_DISCONNECT)
|
2021-05-13 22:45:55 +02:00
|
|
|
}
|
|
|
|
|
clientSeq = 0
|
|
|
|
|
events = {}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-29 17:58:05 +02:00
|
|
|
function sendClientEvent(evt: GameEvent): void {
|
2020-11-17 21:46:56 +01:00
|
|
|
// when sending event, increase number of sent events
|
|
|
|
|
// and add the event locally
|
|
|
|
|
clientSeq++;
|
2021-05-09 21:43:35 +02:00
|
|
|
events[clientSeq] = evt
|
2020-11-17 21:46:56 +01:00
|
|
|
send([Protocol.EV_CLIENT_EVENT, clientSeq, events[clientSeq]])
|
2020-11-09 01:54:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
connect,
|
2021-05-29 11:44:55 +02:00
|
|
|
requestReplayData,
|
2021-05-13 22:45:55 +02:00
|
|
|
disconnect,
|
2020-11-17 21:46:56 +01:00
|
|
|
sendClientEvent,
|
2021-05-15 17:40:04 +02:00
|
|
|
onServerChange,
|
2021-05-15 20:04:30 +02:00
|
|
|
onConnectionStateChange,
|
|
|
|
|
CODE_CUSTOM_DISCONNECT,
|
|
|
|
|
|
|
|
|
|
CONN_STATE_NOT_CONNECTED,
|
|
|
|
|
CONN_STATE_DISCONNECTED,
|
|
|
|
|
CONN_STATE_CLOSED,
|
|
|
|
|
CONN_STATE_CONNECTED,
|
|
|
|
|
CONN_STATE_CONNECTING,
|
2020-11-09 01:54:05 +01:00
|
|
|
}
|