Move to Renderer V2

This commit is contained in:
duckietm
2024-04-03 09:27:56 +02:00
parent 110c3ad393
commit b3134ce50b
4080 changed files with 115593 additions and 66375 deletions
@@ -0,0 +1,261 @@
import { ICodec, IConnection, IMessageComposer, IMessageConfiguration, IMessageDataWrapper, IMessageEvent, WebSocketEventEnum } from '@nitrots/api';
import { GetEventDispatcher, NitroEvent, NitroEventType } from '@nitrots/events';
import { NitroLogger } from '@nitrots/utils';
import { EvaWireFormat } from './codec';
import { MessageClassManager } from './messages';
export class SocketConnection implements IConnection
{
private _socket: WebSocket = null;
private _messages: MessageClassManager = new MessageClassManager();
private _codec: ICodec = new EvaWireFormat();
private _dataBuffer: ArrayBuffer = null;
private _isReady: boolean = false;
private _pendingClientMessages: IMessageComposer<unknown[]>[] = [];
private _pendingServerMessages: IMessageDataWrapper[] = [];
private _isAuthenticated: boolean = false;
public init(socketUrl: string): void
{
if(!socketUrl || !socketUrl.length) return;
this._dataBuffer = new ArrayBuffer(0);
this._socket = new WebSocket(socketUrl);
this._socket.binaryType = 'arraybuffer';
this._socket.addEventListener(WebSocketEventEnum.CONNECTION_OPENED, event => GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.SOCKET_OPENED)));
this._socket.addEventListener(WebSocketEventEnum.CONNECTION_CLOSED, event => GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.SOCKET_CLOSED)));
this._socket.addEventListener(WebSocketEventEnum.CONNECTION_ERROR, event => GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.SOCKET_ERROR)));
this._socket.addEventListener(WebSocketEventEnum.CONNECTION_MESSAGE, (event: MessageEvent) =>
{
this._dataBuffer = this.concatArrayBuffers(this._dataBuffer, event.data);
this.processReceivedData();
});
}
public ready(): void
{
if(this._isReady) return;
this._isReady = true;
if(this._pendingServerMessages && this._pendingServerMessages.length) this.processWrappers(...this._pendingServerMessages);
if(this._pendingClientMessages && this._pendingClientMessages.length) this.send(...this._pendingClientMessages);
this._pendingServerMessages = [];
this._pendingClientMessages = [];
}
public authenticated(): void
{
this._isAuthenticated = true;
}
public send(...composers: IMessageComposer<unknown[]>[]): boolean
{
if(!composers) return false;
composers = [...composers];
if(this._isAuthenticated && !this._isReady)
{
this._pendingClientMessages.push(...composers);
return false;
}
for(const composer of composers)
{
if(!composer) continue;
const header = this._messages.getComposerId(composer);
if(header === -1)
{
NitroLogger.packets('Unknown Composer', composer.constructor.name);
continue;
}
const message = composer.getMessageArray();
const encoded = this._codec.encode(header, message);
if(!encoded)
{
NitroLogger.packets('Encoding Failed', composer.constructor.name);
continue;
}
NitroLogger.packets('OutgoingComposer', header, composer.constructor.name, message);
this.write(encoded.getBuffer());
}
return true;
}
private write(buffer: ArrayBuffer): void
{
if(this._socket.readyState !== WebSocket.OPEN) return;
this._socket.send(buffer);
}
public processReceivedData(): void
{
try
{
this.processData();
}
catch (err)
{
NitroLogger.error(err);
}
}
private processData(): void
{
const wrappers = this.splitReceivedMessages();
if(!wrappers || !wrappers.length) return;
if(this._isAuthenticated && !this._isReady)
{
if(!this._pendingServerMessages) this._pendingServerMessages = [];
this._pendingServerMessages.push(...wrappers);
return;
}
this.processWrappers(...wrappers);
}
private processWrappers(...wrappers: IMessageDataWrapper[]): void
{
if(!wrappers || !wrappers.length) return;
for(const wrapper of wrappers)
{
if(!wrapper) continue;
const messages = this.getMessagesForWrapper(wrapper);
if(!messages || !messages.length) continue;
NitroLogger.packets('IncomingMessage', wrapper.header, messages[0].constructor.name, messages[0].parser);
this.handleMessages(...messages);
}
}
private splitReceivedMessages(): IMessageDataWrapper[]
{
if(!this._dataBuffer || !this._dataBuffer.byteLength) return null;
return this._codec.decode(this);
}
private concatArrayBuffers(buffer1: ArrayBuffer, buffer2: ArrayBuffer): ArrayBuffer
{
const array = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
array.set(new Uint8Array(buffer1), 0);
array.set(new Uint8Array(buffer2), buffer1.byteLength);
return array.buffer;
}
private getMessagesForWrapper(wrapper: IMessageDataWrapper): IMessageEvent[]
{
if(!wrapper) return null;
const events = this._messages.getEvents(wrapper.header);
if(!events || !events.length)
{
NitroLogger.packets('IncomingMessage', wrapper.header, 'UNREGISTERED', wrapper);
return null;
}
try
{
//@ts-ignore
const parser = new events[0].parserClass();
if(!parser || !parser.flush() || !parser.parse(wrapper)) return null;
for(const event of events) (event.parser = parser);
}
catch (e)
{
NitroLogger.error('Error parsing message', e, events[0].constructor.name);
return null;
}
return events;
}
private handleMessages(...messages: IMessageEvent[]): void
{
messages = [...messages];
for(const message of messages)
{
if(!message) continue;
message.connection = this;
if(message.callBack) message.callBack(message);
}
}
public registerMessages(configuration: IMessageConfiguration): void
{
if(!configuration) return;
this._messages.registerMessages(configuration);
}
public addMessageEvent(event: IMessageEvent): void
{
if(!event || !this._messages) return;
this._messages.registerMessageEvent(event);
}
public removeMessageEvent(event: IMessageEvent): void
{
if(!event || !this._messages) return;
this._messages.removeMessageEvent(event);
}
public get isAuthenticated(): boolean
{
return this._isAuthenticated;
}
public get dataBuffer(): ArrayBuffer
{
return this._dataBuffer;
}
public set dataBuffer(buffer: ArrayBuffer)
{
this._dataBuffer = buffer;
}
}