import { EventEmitter } from "events" ; import { createSocket , RemoteInfo , Socket } from "dgram" ; import { addr2str } from "../util/misc" ; import { Packet , PacketType } from "./packets/packet" ; import { PolusBuffer } from "../util/polusBuffer" ; import { HelloPacketData } from "./packets/helloPacket" ; import { UnreliablePacketData } from "./packets/unreliablePacket" ; import { FreeWeekendState } from "./packets/subpackets/freeWeekend" ; import { Text } from "../util/text" ; import { Room } from "../../lib/util/room" ; export interface ClientData { nonce : number ; announceId : number ; language : number ; info : RemoteInfo ; } export interface AnnouncementConfig { address ? : string ; port ? : number ; defaultMessage : Text ; freeWeekend ? : FreeWeekendState ; } export interface Announce { message : Text ; freeWeekend ? : FreeWeekendState ; } export class AnnouncementServer extends EventEmitter { room : Room ; sock : Socket ; private clientMap : Map < string , ClientData > = new Map ( ) ; constructor ( public config ) { super ( ) ; config = Object . assign ( { defaultMessage : new Text ( "Set a message in the config!" ) , address : "0.0.0.0" , port : 22024 , freeWeekend : FreeWeekendState . NotFree , } , config ) ; this . sock = createSocket ( "udp4" ) ; this . room = new Room ( ) ; } listen ( ) { return new Promise ( ( res , rej ) => { this . sock . bind ( this . config . port , this . config . address , ( ) => { res ( ) ; this . sock . off ( "error" , rej ) ; this . sock . on ( "message" , ( buf , info ) => { let client = this . getClient ( info ) ; if ( ! client ) throw new Error ( "Could not get client" ) ; let packet = Packet . parse ( new PolusBuffer ( buf ) , this . room ) ; if ( packet . Reliable ) { if ( ! packet . Nonce ) throw new Error ( "Reliable packet missing Nonce" ) ; this . ack ( info , packet . Nonce ) ; } switch ( packet . Type ) { case PacketType . HelloPacket : let data = < HelloPacketData > packet . Data ; client . announceId = data . LastAnnouncement ; client . language = data . Language ; if ( this . listenerCount ( "connect" ) == 0 ) { const packets = [ { type : "AnnouncementData" , Id : this . generateId ( ) , Text : this . config . defaultMessage . text , } , ] ; if ( this . config . freeWeekend ) { packets . push ( { type : "FreeWeekend" , FreeState : this . config . freeWeekend , } ) ; } this . send ( packets , client ) ; } else { this . emit ( "connect" , client ) ; } break ; case PacketType . DisconnectPacket : } } ) ; } ) ; this . sock . once ( "error" , rej ) ; } ) ; } public sendAnnouncement ( announcement , client ) { this . send ( [ { type : "AnnouncementData" , Id : this . generateId ( ) , Text : announcement . message . text , } , { type : "FreeWeekend" , FreeState : announcement . freeWeekend , } , ] , client ) ; } public sendShouldCache ( client ) { this . send ( [ { type : "CacheAnnouncement" , } , ] , client ) ; } public send ( packets , client ) { let Nonce = this . incrementNonce ( client ) ; let i = 0 ; let interval ; let data = Packet . serialize ( { Type : PacketType . ReliablePacket , Reliable : true , Nonce , Data : { Packets : packets , } , } , this . room ) . buf ; let reliableSend = ( ) => { if ( i ++ > 6 ) { clearInterval ( interval ) ; } console . log ( data ) ; this . sock . send ( data , client . info . port , client . info . address , ( error ) => { if ( error ) this . emit ( "error" , error ) ; clearInterval ( interval ) ; } ) ; } ; interval = setInterval ( reliableSend , 1000 ) ; reliableSend ( ) ; } private getClient ( info ) { let addr = addr2str ( info ) ; if ( ! this . clientMap . has ( addr ) ) this . clientMap . set ( addr , { nonce : 0 , announceId : 0 , language : 0 , info , } ) ; return this . clientMap . get ( addr ) || null ; } private incrementNonce ( client ) { return client . nonce ++ ; } private generateId ( avoid = 0 ) { let id = avoid ; while ( id == avoid ) { id = Math . floor ( Math . random ( ) * 1000 ) ; } return id ; } private ack ( info , nonce ) { this . sock . send ( Packet . serialize ( { Type : PacketType . AcknowledgementPacket , Reliable : false , Nonce : nonce , } , this . room ) . buf , info . port , info . address ) ; } }