2022-05-12 09:31:31 +03:00
import { MessageType , SocketEvent } from '../interfaces/socket-events' ;
2022-05-03 08:13:36 +03:00
2022-05-12 09:31:31 +03:00
export interface SocketMessage {
2022-05-04 00:17:05 +03:00
type : MessageType ;
2022-05-03 03:45:22 +03:00
data : any ;
}
export default class WebsocketService {
websocket : WebSocket ;
accessToken : string ;
path : string ;
websocketReconnectTimer : ReturnType < typeof setTimeout > ;
2022-05-12 09:31:31 +03:00
handleMessage ? : ( message : SocketEvent ) = > void ;
2022-05-03 08:13:36 +03:00
2022-05-03 03:45:22 +03:00
constructor ( accessToken , path ) {
this . accessToken = accessToken ;
2022-05-03 08:13:36 +03:00
this . path = path ;
2022-05-03 03:45:22 +03:00
// this.websocketReconnectTimer = null;
// this.accessToken = accessToken;
// this.websocketConnectedListeners = [];
// this.websocketDisconnectListeners = [];
// this.rawMessageListeners = [];
// this.send = this.send.bind(this);
// this.createAndConnect = this.createAndConnect.bind(this);
// this.scheduleReconnect = this.scheduleReconnect.bind(this);
// this.shutdown = this.shutdown.bind(this);
// this.isShutdown = false;
this . createAndConnect ( ) ;
}
createAndConnect() {
2022-10-10 07:16:46 +03:00
const url = new URL ( window . location . toString ( ) ) ;
url . protocol = window . location . protocol === 'https:' ? 'wss:' : 'ws:' ;
url . pathname = '/ws' ;
url . port = window . location . port === '3000' ? '8080' : window . location . port ;
2022-05-03 03:45:22 +03:00
url . searchParams . append ( 'accessToken' , this . accessToken ) ;
2022-05-29 04:43:28 +03:00
console . debug ( 'connecting to ' , url . toString ( ) ) ;
2022-05-03 03:45:22 +03:00
const ws = new WebSocket ( url . toString ( ) ) ;
ws . onopen = this . onOpen . bind ( this ) ;
// ws.onclose = this.onClose.bind(this);
ws . onerror = this . onError . bind ( this ) ;
ws . onmessage = this . onMessage . bind ( this ) ;
this . websocket = ws ;
}
onOpen() {
if ( this . websocketReconnectTimer ) {
clearTimeout ( this . websocketReconnectTimer ) ;
}
}
// On ws error just close the socket and let it re-connect again for now.
onError ( e ) {
2022-05-03 23:01:50 +03:00
console . error ( e ) ;
2022-05-03 08:13:36 +03:00
handleNetworkingError ( ` Socket error: ${ e } ` ) ;
2022-05-03 03:45:22 +03:00
this . websocket . close ( ) ;
// if (!this.isShutdown) {
// this.scheduleReconnect();
// }
}
/ *
onMessage is fired when an inbound object comes across the websocket .
If the message is of type ` PING ` we send a ` PONG ` back and do not
pass it along to listeners .
* /
onMessage ( e : SocketMessage ) {
// Optimization where multiple events can be sent within a
// single websocket message. So split them if needed.
const messages = e . data . split ( '\n' ) ;
2022-05-26 23:52:04 +03:00
let socketEvent : SocketEvent ;
2022-05-03 03:45:22 +03:00
// eslint-disable-next-line no-plusplus
for ( let i = 0 ; i < messages . length ; i ++ ) {
try {
2022-05-26 23:52:04 +03:00
socketEvent = JSON . parse ( messages [ i ] ) ;
2022-05-03 08:13:36 +03:00
if ( this . handleMessage ) {
2022-05-26 23:52:04 +03:00
this . handleMessage ( socketEvent ) ;
2022-05-03 08:13:36 +03:00
}
2022-10-10 07:16:46 +03:00
} catch ( err ) {
console . error ( err , err . data ) ;
2022-05-03 03:45:22 +03:00
return ;
}
2022-05-26 23:52:04 +03:00
if ( ! socketEvent . type ) {
console . error ( 'No type provided' , socketEvent ) ;
2022-05-03 03:45:22 +03:00
return ;
}
// Send PONGs
2022-05-26 23:52:04 +03:00
if ( socketEvent . type === MessageType . PING ) {
2022-05-03 03:45:22 +03:00
this . sendPong ( ) ;
return ;
}
}
}
2022-05-26 23:52:04 +03:00
isConnected ( ) : boolean {
return this . websocket ? . readyState === this . websocket ? . OPEN ;
}
2022-05-03 03:45:22 +03:00
// Outbound: Other components can pass an object to `send`.
2022-05-26 23:52:04 +03:00
send ( socketEvent : any ) {
2022-05-03 03:45:22 +03:00
// Sanity check that what we're sending is a valid type.
2022-05-26 23:52:04 +03:00
if ( ! socketEvent . type || ! MessageType [ socketEvent . type ] ) {
console . warn ( ` Outbound message: Unknown socket message type: " ${ socketEvent . type } " sent. ` ) ;
2022-05-03 03:45:22 +03:00
}
2022-05-26 23:52:04 +03:00
const messageJSON = JSON . stringify ( socketEvent ) ;
2022-05-03 03:45:22 +03:00
this . websocket . send ( messageJSON ) ;
}
// Reply to a PING as a keep alive.
sendPong() {
2022-05-04 00:17:05 +03:00
const pong = { type : MessageType . PONG } ;
2022-05-03 03:45:22 +03:00
this . send ( pong ) ;
}
}
function handleNetworkingError ( error ) {
console . error (
2022-05-03 08:13:36 +03:00
` Chat has been disconnected and is likely not working for you. It's possible you were removed from chat. If this is a server configuration issue, visit troubleshooting steps to resolve. https://owncast.online/docs/troubleshooting/#chat-is-disabled: ${ error } ` ,
2022-05-03 03:45:22 +03:00
) ;
2022-05-03 08:13:36 +03:00
}