bastienrobert/la-ferme

View on GitHub
packages/server/app/stores/connections.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { UUID } from '@la-ferme/shared/typings'
import Emitter from '@bastienrobert/events'
import merge from 'lodash.merge'

import ConnectionModel from '@/app/models/Connection'
import UserModel from '@/app/models/User'

import getPlayer from '@/app/helpers/getPlayer'

export interface Connection {
  boxID: UUID | null
  gameUUID: UUID | null
  playerUUID: UUID | null
  ready: boolean
}

export type ConnectionsCollection = Map<UUID, Connection>

const DEFAULT_VALUE = {
  boxID: null,
  gameUUID: null,
  playerUUID: null,
  ready: false
}

class Connections extends Emitter {
  _connections: ConnectionsCollection = new Map()

  protected static async saveDisconnect(user: UserModel) {
    const connections = await user
      .connections()
      .orderBy('connected_at', 'DESC')
      .fetchOne()
    connections.disconnect().save()
  }

  protected static async surrenderPlayer(user: UserModel) {
    const player = getPlayer(user)
    if (!player) return false
    await player.surrender().save()
    return true
  }

  async connect(key: UUID) {
    const user = await UserModel.findByUUID(key)
    new ConnectionModel({ user_id: user.id }).save()
    const res = this.reset(key)
    this.emit('connect', key, this.get(key))
    return res
  }

  get(key: UUID) {
    return this._connections.get(key)
  }

  set(key: UUID, value: Connection) {
    return this._connections.set(key, value)
  }

  reset(key: UUID) {
    return this._connections.set(key, { ...DEFAULT_VALUE })
  }

  merge(userUUID, newState) {
    const state = this._connections.get(userUUID)
    return this._connections.set(userUUID, merge(state, newState))
  }

  setReady(userUUID: UUID) {
    return this.merge(userUUID, { ready: true })
  }

  getByBoxID(id: UUID) {
    return new Map([...this._connections].filter(({ 1: v }) => v.boxID === id))
  }

  async disconnect(key: UUID) {
    const value = this.get(key)
    if (!value) return
    this.emit('disconnecting', key, value)
    const user = await UserModel.findByUUID(key, {
      withRelated: [{ players: qb => qb.orderBy('created_at') }]
    })
    await Promise.all([
      Connections.saveDisconnect(user),
      Connections.surrenderPlayer(user)
    ])
    const res = this._connections.delete(key)
    this.emit('disconnect', key)
    return res
  }
}

export default new Connections()