2020-03-30 11:44:18 +00:00
import {
AbstractServerConnection ,
CommandOptionDefaults ,
CommandOptions ,
2020-04-09 13:10:14 +00:00
ConnectionStateListener ,
voice
2020-03-30 11:44:18 +00:00
} from "tc-shared/connection/ConnectionBase" ;
import { ConnectionHandler , ConnectionState , DisconnectReason } from "tc-shared/ConnectionHandler" ;
import { ServerAddress } from "tc-shared/ui/server" ;
import { HandshakeHandler } from "tc-shared/connection/HandshakeHandler" ;
import { ConnectionCommandHandler , ServerConnectionCommandBoss } from "tc-shared/connection/CommandHandler" ;
import { CommandResult } from "tc-shared/connection/ServerConnectionDeclaration" ;
import { settings , Settings } from "tc-shared/settings" ;
import * as log from "tc-shared/log" ;
2020-04-09 13:10:14 +00:00
import { LogCategory } from "tc-shared/log" ;
2020-03-30 11:44:18 +00:00
import { Regex } from "tc-shared/ui/modal/ModalConnect" ;
import { AbstractCommandHandlerBoss } from "tc-shared/connection/AbstractCommandHandler" ;
import * as elog from "tc-shared/ui/frames/server_log" ;
import { VoiceConnection } from "../voice/VoiceHandler" ;
2020-04-09 13:10:14 +00:00
import AbstractVoiceConnection = voice . AbstractVoiceConnection ;
2020-03-30 11:44:18 +00:00
2019-02-23 13:15:22 +00:00
class ReturnListener < T > {
resolve : ( value? : T | PromiseLike < T > ) = > void ;
reject : ( reason? : any ) = > void ;
code : string ;
timeout : NodeJS.Timer ;
}
2020-03-30 11:44:18 +00:00
export class ServerConnection extends AbstractServerConnection {
private _remote_address : ServerAddress ;
private _handshakeHandler : HandshakeHandler ;
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
private _command_boss : ServerConnectionCommandBoss ;
private _command_handler_default : ConnectionCommandHandler ;
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
private _socket_connected : WebSocket ;
2019-11-23 22:41:37 +00:00
2020-03-30 11:44:18 +00:00
private _connect_timeout_timer : NodeJS.Timer = undefined ;
2019-11-23 22:41:37 +00:00
2020-03-30 11:44:18 +00:00
private _connected : boolean = false ;
private _retCodeIdx : number ;
private _retListener : ReturnListener < CommandResult > [ ] ;
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
private _connection_state_listener : ConnectionStateListener ;
private _voice_connection : VoiceConnection ;
2019-04-04 19:47:52 +00:00
2020-03-30 11:44:18 +00:00
private _ping = {
thread_id : 0 ,
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
last_request : 0 ,
last_response : 0 ,
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
request_id : 0 ,
interval : 5000 ,
timeout : 7500 ,
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
value : 0 ,
value_native : 0 /* ping value for native (WS) */
} ;
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
constructor ( client : ConnectionHandler ) {
super ( client ) ;
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
this . _retCodeIdx = 0 ;
this . _retListener = [ ] ;
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
this . _command_boss = new ServerConnectionCommandBoss ( this ) ;
this . _command_handler_default = new ConnectionCommandHandler ( this ) ;
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
this . _command_boss . register_handler ( this . _command_handler_default ) ;
this . command_helper . initialize ( ) ;
2019-04-04 19:47:52 +00:00
2020-03-30 11:44:18 +00:00
if ( ! settings . static_global ( Settings . KEY_DISABLE_VOICE , false ) )
this . _voice_connection = new VoiceConnection ( this ) ;
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
destroy() {
this . disconnect ( "handle destroyed" ) . catch ( error = > {
log . warn ( LogCategory . NETWORKING , tr ( "Failed to disconnect on server connection destroy: %o" ) , error ) ;
} ) . then ( ( ) = > {
clearInterval ( this . _ping . thread_id ) ;
clearTimeout ( this . _connect_timeout_timer ) ;
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
for ( const listener of this . _retListener ) {
try {
listener . reject ( "handler destroyed" ) ;
} catch ( error ) {
log . warn ( LogCategory . NETWORKING , tr ( "Failed to reject command promise: %o" ) , error ) ;
2019-08-21 08:00:01 +00:00
}
2020-03-30 11:44:18 +00:00
}
this . _retListener = undefined ;
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
this . command_helper . destroy ( ) ;
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
this . _command_handler_default && this . _command_boss . unregister_handler ( this . _command_handler_default ) ;
this . _command_handler_default = undefined ;
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
this . _voice_connection && this . _voice_connection . destroy ( ) ;
this . _voice_connection = undefined ;
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
this . _command_boss && this . _command_boss . destroy ( ) ;
this . _command_boss = undefined ;
} ) ;
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
private generateReturnCode ( ) : string {
return ( this . _retCodeIdx ++ ) . toString ( ) ;
}
2019-11-23 22:41:37 +00:00
2020-03-30 11:44:18 +00:00
async connect ( address : ServerAddress , handshake : HandshakeHandler , timeout? : number ) : Promise < void > {
timeout = typeof ( timeout ) === "number" ? timeout : 5000 ;
2019-11-23 22:41:37 +00:00
2020-03-30 11:44:18 +00:00
try {
await this . disconnect ( )
} catch ( error ) {
log . error ( LogCategory . NETWORKING , tr ( "Failed to close old connection properly. Error: %o" ) , error ) ;
throw "failed to cleanup old connection" ;
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
this . updateConnectionState ( ConnectionState . CONNECTING ) ;
this . _remote_address = address ;
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
this . _handshakeHandler = handshake ;
this . _handshakeHandler . setConnection ( this ) ;
2019-11-23 22:41:37 +00:00
2020-03-30 11:44:18 +00:00
/* The direct one connect directly to the target address. The other via the .con-gate.work */
let local_direct_socket : WebSocket ;
let local_proxy_socket : WebSocket ;
let connected_socket : WebSocket ;
let local_timeout_timer : NodeJS.Timer ;
2019-11-23 22:41:37 +00:00
2020-03-30 11:44:18 +00:00
/* setting up an timeout */
local_timeout_timer = setTimeout ( async ( ) = > {
log . error ( LogCategory . NETWORKING , tr ( "Connect timeout triggered. Aborting connect attempt!" ) ) ;
2019-11-23 22:41:37 +00:00
try {
2020-03-30 11:44:18 +00:00
await this . disconnect ( ) ;
} catch ( error ) {
log . warn ( LogCategory . NETWORKING , tr ( "Failed to close connection after timeout had been triggered! (%o)" ) , error ) ;
}
2019-11-22 20:51:26 +00:00
2020-03-30 11:44:18 +00:00
error_cleanup ( ) ;
this . client . handleDisconnect ( DisconnectReason . CONNECT_FAILURE ) ;
} , timeout ) ;
this . _connect_timeout_timer = local_timeout_timer ;
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
const error_cleanup = ( ) = > {
try { local_direct_socket . close ( ) ; } catch ( ex ) { }
try { local_proxy_socket . close ( ) ; } catch ( ex ) { }
clearTimeout ( local_timeout_timer ) ;
} ;
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
try {
let proxy_host ;
if ( Regex . IP_V4 . test ( address . host ) )
proxy_host = address . host . replace ( /\./g , "-" ) + ".con-gate.work" ;
else if ( Regex . IP_V6 . test ( address . host ) )
proxy_host = address . host . replace ( /\[(.*)]/ , "$1" ) . replace ( /:/g , "_" ) + ".con-gate.work" ;
if ( proxy_host && ! settings . static_global ( Settings . KEY_CONNECT_NO_DNSPROXY ) )
local_proxy_socket = new WebSocket ( 'wss://' + proxy_host + ":" + address . port ) ;
local_direct_socket = new WebSocket ( 'wss://' + address . host + ":" + address . port ) ;
connected_socket = await new Promise < WebSocket > ( resolve = > {
let pending = 0 , succeed = false ;
if ( local_proxy_socket ) {
pending ++ ;
local_proxy_socket . onerror = event = > {
-- pending ;
if ( this . _connect_timeout_timer != local_timeout_timer )
log . trace ( LogCategory . NETWORKING , tr ( "Proxy socket send an error while connecting. Pending sockets: %d. Any succeed: %s" ) , pending , succeed ? tr ( "yes" ) : tr ( "no" ) ) ;
if ( ! succeed && pending == 0 )
resolve ( undefined ) ;
} ;
local_proxy_socket . onopen = event = > {
-- pending ;
if ( this . _connect_timeout_timer != local_timeout_timer )
log . trace ( LogCategory . NETWORKING , tr ( "Proxy socket connected. Pending sockets: %d. Any succeed before: %s" ) , pending , succeed ? tr ( "yes" ) : tr ( "no" ) ) ;
if ( ! succeed ) {
succeed = true ;
resolve ( local_proxy_socket ) ;
}
} ;
}
2019-11-23 22:41:37 +00:00
2020-03-30 11:44:18 +00:00
if ( local_direct_socket ) {
pending ++ ;
local_direct_socket . onerror = event = > {
-- pending ;
if ( this . _connect_timeout_timer != local_timeout_timer )
log . trace ( LogCategory . NETWORKING , tr ( "Direct socket send an error while connecting. Pending sockets: %d. Any succeed: %s" ) , pending , succeed ? tr ( "yes" ) : tr ( "no" ) ) ;
if ( ! succeed && pending == 0 )
resolve ( undefined ) ;
} ;
local_direct_socket . onopen = event = > {
-- pending ;
if ( this . _connect_timeout_timer != local_timeout_timer )
log . trace ( LogCategory . NETWORKING , tr ( "Direct socket connected. Pending sockets: %d. Any succeed before: %s" ) , pending , succeed ? tr ( "yes" ) : tr ( "no" ) ) ;
if ( ! succeed ) {
succeed = true ;
resolve ( local_direct_socket ) ;
2019-11-23 22:41:37 +00:00
}
2020-03-30 11:44:18 +00:00
} ;
2019-08-21 08:00:01 +00:00
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
if ( local_proxy_socket && local_proxy_socket . readyState == WebSocket . OPEN )
local_proxy_socket . onopen ( undefined ) ;
if ( local_direct_socket && local_direct_socket . readyState == WebSocket . OPEN )
local_direct_socket . onopen ( undefined ) ;
} ) ;
if ( ! connected_socket ) {
//We failed to connect. Lets test if we're still relevant
2019-11-23 22:41:37 +00:00
if ( this . _connect_timeout_timer != local_timeout_timer ) {
2020-03-30 11:44:18 +00:00
log . trace ( LogCategory . NETWORKING , tr ( "Failed to connect to %s, but we're already obsolete." ) , address . host + ":" + address . port ) ;
error_cleanup ( ) ;
} else {
try {
await this . disconnect ( ) ;
} catch ( error ) {
log . warn ( LogCategory . NETWORKING , tr ( "Failed to cleanup connection after unsuccessful connect attempt: %o" ) , error ) ;
}
2019-11-23 22:41:37 +00:00
error_cleanup ( ) ;
2020-03-30 11:44:18 +00:00
this . client . handleDisconnect ( DisconnectReason . CONNECT_FAILURE ) ;
2019-11-23 22:41:37 +00:00
}
2020-03-30 11:44:18 +00:00
return ;
}
if ( this . _connect_timeout_timer != local_timeout_timer ) {
log . trace ( LogCategory . NETWORKING , tr ( "Successfully connected to %s, but we're already obsolete. Closing connections" ) , address . host + ":" + address . port ) ;
error_cleanup ( ) ;
return ;
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
clearTimeout ( local_timeout_timer ) ;
this . _connect_timeout_timer = undefined ;
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
if ( connected_socket == local_proxy_socket ) {
log . debug ( LogCategory . NETWORKING , tr ( "Established a TCP connection to %s via proxy to %s" ) , address . host + ":" + address . port , proxy_host ) ;
this . _remote_address . host = proxy_host ;
} else {
log . debug ( LogCategory . NETWORKING , tr ( "Established a TCP connection to %s directly" ) , address . host + ":" + address . port ) ;
}
2019-11-23 22:41:37 +00:00
2020-03-30 11:44:18 +00:00
this . _socket_connected = connected_socket ;
this . _socket_connected . onclose = event = > {
if ( this . _socket_connected != connected_socket ) return ; /* this socket isn't from interest anymore */
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
this . client . handleDisconnect ( this . _connected ? DisconnectReason.CONNECTION_CLOSED : DisconnectReason.CONNECT_FAILURE , {
code : event.code ,
reason : event.reason ,
event : event
} ) ;
} ;
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
this . _socket_connected . onerror = e = > {
if ( this . _socket_connected != connected_socket ) return ; /* this socket isn't from interest anymore */
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
log . warn ( LogCategory . NETWORKING , tr ( "Received web socket error: (%o)" ) , e ) ;
} ;
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
this . _socket_connected . onmessage = msg = > {
if ( this . _socket_connected != connected_socket ) return ; /* this socket isn't from interest anymore */
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
this . handle_socket_message ( msg . data ) ;
} ;
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
this . _connected = true ;
this . start_handshake ( ) ;
} catch ( error ) {
error_cleanup ( ) ;
if ( this . _socket_connected != connected_socket && this . _connect_timeout_timer != local_timeout_timer )
return ; /* we're not from interest anymore */
2019-11-23 22:41:37 +00:00
2020-03-30 11:44:18 +00:00
log . warn ( LogCategory . NETWORKING , tr ( "Received unexpected error while connecting: %o" ) , error ) ;
try {
await this . disconnect ( ) ;
} catch ( error ) {
log . warn ( LogCategory . NETWORKING , tr ( "Failed to cleanup connection after unsuccessful connect attempt: %o" ) , error ) ;
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
this . client . handleDisconnect ( DisconnectReason . CONNECT_FAILURE , error ) ;
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
private start_handshake() {
this . updateConnectionState ( ConnectionState . INITIALISING ) ;
this . client . log . log ( elog . Type . CONNECTION_LOGIN , { } ) ;
this . _handshakeHandler . initialize ( ) ;
this . _handshakeHandler . startHandshake ( ) ;
}
2019-11-23 22:41:37 +00:00
2020-03-30 11:44:18 +00:00
async disconnect ( reason? : string ) : Promise < void > {
2020-04-09 13:10:14 +00:00
this . updateConnectionState ( ConnectionState . DISCONNECTING ) ;
try {
clearTimeout ( this . _connect_timeout_timer ) ;
this . _connect_timeout_timer = undefined ;
2019-08-21 08:00:01 +00:00
2020-04-09 13:10:14 +00:00
clearTimeout ( this . _ping . thread_id ) ;
this . _ping . thread_id = undefined ;
2019-02-23 13:15:22 +00:00
2020-04-09 13:10:14 +00:00
if ( typeof ( reason ) === "string" ) {
//TODO send disconnect reason
}
2019-08-21 08:00:01 +00:00
2019-11-23 22:41:37 +00:00
2020-04-09 13:10:14 +00:00
if ( this . _voice_connection )
this . _voice_connection . drop_rtp_session ( ) ;
2019-11-23 22:41:37 +00:00
2020-04-09 13:10:14 +00:00
if ( this . _socket_connected ) {
this . _socket_connected . close ( 3000 + 0xFF , tr ( "request disconnect" ) ) ;
this . _socket_connected = undefined ;
}
2019-02-23 13:15:22 +00:00
2020-04-09 13:10:14 +00:00
for ( let future of this . _retListener )
future . reject ( tr ( "Connection closed" ) ) ;
this . _retListener = [ ] ;
2019-04-04 19:47:52 +00:00
2020-04-09 13:10:14 +00:00
this . _connected = false ;
this . _retCodeIdx = 0 ;
} finally {
this . updateConnectionState ( ConnectionState . UNCONNECTED ) ;
}
2020-03-30 11:44:18 +00:00
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
private handle_socket_message ( data ) {
if ( typeof ( data ) === "string" ) {
let json ;
try {
json = JSON . parse ( data ) ;
} catch ( e ) {
log . warn ( LogCategory . NETWORKING , tr ( "Could not parse message json!" ) ) ;
alert ( e ) ; // error in the above string (in this case, yes)!
return ;
}
if ( json [ "type" ] === undefined ) {
log . warn ( LogCategory . NETWORKING , tr ( "Missing data type in message!" ) ) ;
return ;
}
if ( json [ "type" ] === "command" ) {
let group = log . group ( log . LogType . DEBUG , LogCategory . NETWORKING , tr ( "Handling command '%s'" ) , json [ "command" ] ) ;
group . log ( tr ( "Handling command '%s'" ) , json [ "command" ] ) ;
group . group ( log . LogType . TRACE , tr ( "Json:" ) ) . collapsed ( true ) . log ( "%o" , json ) . end ( ) ;
this . _command_boss . invoke_handle ( {
command : json [ "command" ] ,
arguments : json [ "data" ]
} ) ;
if ( json [ "command" ] === "initserver" ) {
this . _ping . thread_id = setInterval ( ( ) = > this . do_ping ( ) , this . _ping . interval ) as any ;
this . do_ping ( ) ;
this . updateConnectionState ( ConnectionState . CONNECTED ) ;
2019-04-04 19:47:52 +00:00
if ( this . _voice_connection )
2020-03-30 11:44:18 +00:00
this . _voice_connection . start_rtc_session ( ) ; /* FIXME: Move it to a handler boss and not here! */
}
group . end ( ) ;
} else if ( json [ "type" ] === "WebRTC" ) {
if ( this . _voice_connection )
this . _voice_connection . handleControlPacket ( json ) ;
else
log . warn ( LogCategory . NETWORKING , tr ( "Dropping WebRTC command packet, because we haven't a bridge." ) )
} else if ( json [ "type" ] === "ping" ) {
this . sendData ( JSON . stringify ( {
type : 'pong' ,
payload : json [ "payload" ]
} ) ) ;
} else if ( json [ "type" ] === "pong" ) {
const id = parseInt ( json [ "payload" ] ) ;
if ( id != this . _ping . request_id ) {
log . warn ( LogCategory . NETWORKING , tr ( "Received pong which is older than the last request. Delay may over %oms? (Index: %o, Current index: %o)" ) , this . _ping . timeout , id , this . _ping . request_id ) ;
2019-08-21 08:00:01 +00:00
} else {
2020-03-30 11:44:18 +00:00
this . _ping . last_response = 'now' in performance ? performance . now ( ) : Date . now ( ) ;
this . _ping . value = this . _ping . last_response - this . _ping . last_request ;
this . _ping . value_native = parseInt ( json [ "ping_native" ] ) / 1000 ; /* we're getting it in microseconds and not milliseconds */
log . debug ( LogCategory . NETWORKING , tr ( "Received new pong. Updating ping to: JS: %o Native: %o" ) , this . _ping . value . toFixed ( 3 ) , this . _ping . value_native . toFixed ( 3 ) ) ;
2019-02-23 13:15:22 +00:00
}
} else {
2020-03-30 11:44:18 +00:00
log . warn ( LogCategory . NETWORKING , tr ( "Unknown command type %o" ) , json [ "type" ] ) ;
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
} else {
log . warn ( LogCategory . NETWORKING , tr ( "Received unknown message of type %s. Dropping message" ) , typeof ( data ) ) ;
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
sendData ( data : any ) {
if ( ! this . _socket_connected || this . _socket_connected . readyState != 1 ) {
log . warn ( LogCategory . NETWORKING , tr ( "Tried to send on a invalid socket (%s)" ) , this . _socket_connected ? "invalid state (" + this . _socket_connected . readyState + ")" : "invalid socket" ) ;
return ;
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
this . _socket_connected . send ( data ) ;
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
private commandiefy ( input : any ) : string {
return JSON . stringify ( input , ( key , value ) = > {
switch ( typeof value ) {
case "boolean" : return value == true ? "1" : "0" ;
case "function" : return value ( ) ;
default :
return value ;
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
} ) ;
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
}
2019-04-18 11:19:08 +00:00
2020-03-30 11:44:18 +00:00
send_command ( command : string , data? : any | any [ ] , _options? : CommandOptions ) : Promise < CommandResult > {
if ( ! this . _socket_connected || ! this . connected ( ) ) {
log . warn ( LogCategory . NETWORKING , tr ( "Tried to send a command without a valid connection." ) ) ;
return Promise . reject ( tr ( "not connected" ) ) ;
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
const options : CommandOptions = { } ;
Object . assign ( options , CommandOptionDefaults ) ;
Object . assign ( options , _options ) ;
data = $ . isArray ( data ) ? data : [ data || { } ] ;
if ( data . length == 0 ) /* we require min one arg to append return_code */
data . push ( { } ) ;
const _this = this ;
let result = new Promise < CommandResult > ( ( resolve , failed ) = > {
let _data = $ . isArray ( data ) ? data : [ data ] ;
let retCode = _data [ 0 ] [ "return_code" ] !== undefined ? _data [ 0 ] . return_code : _this.generateReturnCode ( ) ;
_data [ 0 ] . return_code = retCode ;
let listener = new ReturnListener < CommandResult > ( ) ;
listener . resolve = resolve ;
listener . reject = failed ;
listener . code = retCode ;
listener . timeout = setTimeout ( ( ) = > {
_this . _retListener . remove ( listener ) ;
listener . reject ( "timeout" ) ;
} , 1500 ) ;
this . _retListener . push ( listener ) ;
this . _socket_connected . send ( this . commandiefy ( {
"type" : "command" ,
"command" : command ,
"data" : _data ,
"flags" : options . flagset . filter ( entry = > entry . length != 0 )
} ) ) ;
} ) ;
return this . _command_handler_default . proxy_command_promise ( result , options ) ;
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
connected ( ) : boolean {
return ! ! this . _socket_connected && this . _socket_connected . readyState == WebSocket . OPEN ;
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
support_voice ( ) : boolean {
return this . _voice_connection !== undefined ;
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
voice_connection ( ) : AbstractVoiceConnection | undefined {
return this . _voice_connection ;
}
2019-04-04 19:47:52 +00:00
2020-03-30 11:44:18 +00:00
command_handler_boss ( ) : AbstractCommandHandlerBoss {
return this . _command_boss ;
}
2019-04-04 19:47:52 +00:00
2019-04-15 13:33:51 +00:00
2020-03-30 11:44:18 +00:00
get onconnectionstatechanged ( ) : ConnectionStateListener {
return this . _connection_state_listener ;
}
set onconnectionstatechanged ( listener : ConnectionStateListener ) {
this . _connection_state_listener = listener ;
}
2019-04-15 13:33:51 +00:00
2020-03-30 11:44:18 +00:00
handshake_handler ( ) : HandshakeHandler {
return this . _handshakeHandler ;
}
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
remote_address ( ) : ServerAddress {
return this . _remote_address ;
}
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
private do_ping() {
if ( this . _ping . last_request + this . _ping . timeout < Date . now ( ) ) {
this . _ping . value = this . _ping . timeout ;
this . _ping . last_response = this . _ping . last_request + 1 ;
}
if ( this . _ping . last_response > this . _ping . last_request ) {
this . _ping . last_request = 'now' in performance ? performance . now ( ) : Date . now ( ) ;
this . sendData ( JSON . stringify ( {
type : 'ping' ,
payload : ( ++ this . _ping . request_id ) . toString ( )
} ) ) ;
2019-08-21 08:00:01 +00:00
}
2019-04-15 13:33:51 +00:00
}
2020-03-30 11:44:18 +00:00
ping ( ) : { native : number ; javascript? : number } {
return {
javascript : this._ping.value ,
native : this._ping.value_native
} ;
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
}
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
export function spawn_server_connection ( handle : ConnectionHandler ) : AbstractServerConnection {
return new ServerConnection ( handle ) ; /* will be overridden by the client */
}
export function destroy_server_connection ( handle : AbstractServerConnection ) {
if ( ! ( handle instanceof ServerConnection ) )
throw "invalid handle" ;
handle . destroy ( ) ;
2019-02-23 13:15:22 +00:00
}