Skip to content

Commit d44417d

Browse files
committed
refactor(unity-messaging): replace message handlers with event emitters
Replace direct message handler registration with typed event emitters for better type safety and maintainability. This includes: - Adding specific event emitters for test-related messages - Moving JSON parsing logic into the messaging client - Simplifying message handling in test provider
1 parent 2d0e31d commit d44417d

File tree

3 files changed

+180
-112
lines changed

3 files changed

+180
-112
lines changed

src/unityMessagingClient.ts

Lines changed: 158 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as dgram from 'dgram';
22
import * as net from 'net';
33
import { UnityBinaryManager, UnityDetectionEvent } from './unityBinaryManager';
44
import { logWithLimit } from './utils';
5-
import { EventEmitter } from './eventEmitter';
5+
import { EventEmitter, VoidEventEmitter } from './eventEmitter';
66
import { wait } from './asyncUtils';
77

88
export enum MessageType {
@@ -68,6 +68,11 @@ export interface TestAdaptorContainer {
6868
TestAdaptors: TestAdaptor[];
6969
}
7070

71+
export interface TestListRetrievedData {
72+
testMode: 'EditMode' | 'PlayMode';
73+
testContainer: TestAdaptorContainer;
74+
}
75+
7176
export enum TestStatusAdaptor {
7277
Passed = 0,
7378
Skipped = 1,
@@ -166,11 +171,7 @@ export class UnityMessagingClient {
166171
*/
167172
private unityAddress: string = '127.0.0.1';
168173

169-
/**
170-
* Map of message type handlers for processing incoming Unity messages
171-
* @private
172-
*/
173-
private messageHandlers: Map<MessageType, (message: UnityMessage) => void> = new Map();
174+
174175

175176
/**
176177
* Rate limiting configuration - maps MessageType to minimum interval in milliseconds
@@ -316,6 +317,48 @@ export class UnityMessagingClient {
316317
*/
317318
public readonly onErrorMessage = new EventEmitter<string>();
318319

320+
/**
321+
* Event emitter for test list retrieved messages
322+
* @public
323+
*/
324+
public readonly onTestListRetrieved = new EventEmitter<TestListRetrievedData>();
325+
326+
/**
327+
* Event emitter for test started messages
328+
* @public
329+
*/
330+
public readonly onTestStarted = new EventEmitter<TestAdaptorContainer>();
331+
332+
/**
333+
* Event emitter for test finished messages
334+
* @public
335+
*/
336+
public readonly onTestFinished = new EventEmitter<TestResultAdaptorContainer>();
337+
338+
/**
339+
* Event emitter for test run started messages
340+
* @public
341+
*/
342+
public readonly onRunStarted = new VoidEventEmitter();
343+
344+
/**
345+
* Event emitter for test run finished messages
346+
* @public
347+
*/
348+
public readonly onRunFinished = new VoidEventEmitter();
349+
350+
/**
351+
* Event emitter for execute tests confirmation messages
352+
* @public
353+
*/
354+
public readonly onExecuteTests = new EventEmitter<string>();
355+
356+
/**
357+
* Event emitter for compilation finished messages
358+
* @public
359+
*/
360+
public readonly onCompilationFinished = new VoidEventEmitter();
361+
319362
constructor(unityBinaryManager: UnityBinaryManager) {
320363
this.unityBinaryManager = unityBinaryManager;
321364
this.setupSocket();
@@ -590,10 +633,16 @@ export class UnityMessagingClient {
590633
}
591634

592635
/**
593-
* Register message handler for specific message type
636+
* Helper method to safely parse JSON strings
637+
* @param value The string value to parse
638+
* @returns Parsed object or the original string if parsing fails
594639
*/
595-
onMessage(type: MessageType, handler: (message: UnityMessage) => void): void {
596-
this.messageHandlers.set(type, handler);
640+
private tryParseJson<T>(value: string): T | string {
641+
try {
642+
return JSON.parse(value) as T;
643+
} catch {
644+
return value;
645+
}
597646
}
598647

599648
/**
@@ -617,62 +666,109 @@ export class UnityMessagingClient {
617666
console.log(`UnityMessagingClient: Received message - Type: ${message.type} (${MessageType[message.type] || 'Unknown'}), payload is ${message.value}`);
618667
}
619668

620-
// Handle Unity online/offline state changes
621-
let messageHandledInternally = false;
622-
623-
if (message.type === MessageType.Online) {
624-
messageHandledInternally = true;
625-
console.log('UnityMessagingClient: Unity online');
626-
this.isUnityOnline = true;
627-
this.onOnlineStatus.emit(true);
628-
629-
this.handleFirstResponse();
630-
} else if (message.type === MessageType.Offline) {
631-
messageHandledInternally = true;
632-
console.log('UnityMessagingClient: Unity went offline');
633-
this.isUnityOnline = false;
634-
this.onOnlineStatus.emit(false);
635-
} else if (message.type === MessageType.Pong) {
636-
messageHandledInternally = true;
637-
// Pong response indicates Unity is online and responding
638-
if (!this.isUnityOnline) {
639-
console.log('UnityMessagingClient: Unity online (pong received)');
669+
switch (message.type) {
670+
case MessageType.Online:
671+
console.log('UnityMessagingClient: Unity online');
640672
this.isUnityOnline = true;
641673
this.onOnlineStatus.emit(true);
642-
643-
}
644-
this.handleFirstResponse();
645-
} else if (message.type === MessageType.PackageName) {
646-
messageHandledInternally = true;
647-
if (message.value) {
648-
this.packageName = message.value;
649-
console.log(`UnityMessagingClient: Detected Unity package: ${this.packageName}`);
674+
this.handleFirstResponse();
675+
break;
676+
case MessageType.Offline:
677+
console.log('UnityMessagingClient: Unity went offline');
678+
this.isUnityOnline = false;
679+
this.onOnlineStatus.emit(false);
680+
break;
681+
case MessageType.Pong:
682+
// Pong response indicates Unity is online and responding
683+
if (!this.isUnityOnline) {
684+
console.log('UnityMessagingClient: Unity online (pong received)');
685+
this.isUnityOnline = true;
686+
this.onOnlineStatus.emit(true);
687+
}
688+
this.handleFirstResponse();
689+
break;
690+
case MessageType.PackageName:
691+
if (message.value) {
692+
this.packageName = message.value;
693+
console.log(`UnityMessagingClient: Detected Unity package: ${this.packageName}`);
694+
}
695+
break;
696+
case MessageType.Info:
697+
this.onInfoMessage.emit(message.value);
698+
break;
699+
case MessageType.Warning:
700+
this.onWarningMessage.emit(message.value);
701+
break;
702+
case MessageType.Error:
703+
this.onErrorMessage.emit(message.value);
704+
break;
705+
case MessageType.IsPlaying: {
706+
const isPlaying = message.value === 'true';
707+
console.log(`UnityMessagingClient: Unity play mode changed - IsPlaying: ${isPlaying}`);
708+
this.isUnityEditorPlaying = isPlaying;
709+
this.onPlayStatus.emit(isPlaying);
710+
break;
650711
}
651-
} else if (message.type === MessageType.Info) {
652-
messageHandledInternally = true;
653-
this.onInfoMessage.emit(message.value);
654-
} else if (message.type === MessageType.Warning) {
655-
messageHandledInternally = true;
656-
this.onWarningMessage.emit(message.value);
657-
} else if (message.type === MessageType.Error) {
658-
messageHandledInternally = true;
659-
this.onErrorMessage.emit(message.value);
660-
} else if (message.type === MessageType.IsPlaying) {
661-
messageHandledInternally = true;
662-
const isPlaying = message.value === 'true';
663-
console.log(`UnityMessagingClient: Unity play mode changed - IsPlaying: ${isPlaying}`);
664-
this.isUnityEditorPlaying = isPlaying;
665-
this.onPlayStatus.emit(isPlaying);
666-
} else if (message.type === MessageType.Tcp) {
667-
messageHandledInternally = true;
668-
this.handleTcpMessage(message);
669-
}
670-
671-
const handler = this.messageHandlers.get(message.type);
672-
if (handler) {
673-
handler(message);
674-
} else if (!messageHandledInternally) {
675-
console.log(`UnityMessagingClient: No handler registered for message type ${message.type} (${MessageType[message.type] || 'Unknown'})`);
712+
case MessageType.Tcp:
713+
this.handleTcpMessage(message);
714+
break;
715+
case MessageType.TestListRetrieved:
716+
if (this.onTestListRetrieved.hasListeners) {
717+
// Parse TestListRetrieved format: "TestMode:JsonData"
718+
const colonIndex = message.value.indexOf(':');
719+
if (colonIndex > 0) {
720+
const testMode = message.value.substring(0, colonIndex);
721+
const jsonData = message.value.substring(colonIndex + 1);
722+
const testData = this.tryParseJson<TestAdaptorContainer>(jsonData);
723+
if (typeof testData === 'object') {
724+
// Emit with proper type structure
725+
this.onTestListRetrieved.emit({
726+
testMode: testMode as 'EditMode' | 'PlayMode',
727+
testContainer: testData
728+
});
729+
}
730+
}
731+
}
732+
break;
733+
case MessageType.TestStarted:
734+
if (this.onTestStarted.hasListeners) {
735+
const testContainer = this.tryParseJson<TestAdaptorContainer>(message.value);
736+
if (typeof testContainer === 'object') {
737+
this.onTestStarted.emit(testContainer);
738+
}
739+
}
740+
break;
741+
case MessageType.TestFinished:
742+
if (this.onTestFinished.hasListeners) {
743+
const testResult = this.tryParseJson<TestResultAdaptorContainer>(message.value);
744+
if (typeof testResult === 'object') {
745+
this.onTestFinished.emit(testResult);
746+
}
747+
}
748+
break;
749+
case MessageType.RunStarted:
750+
if (this.onRunStarted.hasListeners) {
751+
this.onRunStarted.emit();
752+
}
753+
break;
754+
case MessageType.RunFinished:
755+
if (this.onRunFinished.hasListeners) {
756+
this.onRunFinished.emit();
757+
}
758+
break;
759+
case MessageType.ExecuteTests:
760+
if (this.onExecuteTests.hasListeners) {
761+
this.onExecuteTests.emit(message.value);
762+
}
763+
break;
764+
case MessageType.CompilationFinished:
765+
if (this.onCompilationFinished.hasListeners) {
766+
this.onCompilationFinished.emit();
767+
}
768+
break;
769+
default:
770+
console.log(`UnityMessagingClient: No handler for message type ${message.type} (${MessageType[message.type] || 'Unknown'})`);
771+
break;
676772
}
677773
}
678774

src/unityPackageHelper.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as path from 'path';
33
import { promisify } from 'util';
44
import { isInsideDirectory, normalizePath } from './utils';
55
import { VoidEventEmitter } from './eventEmitter';
6-
import { MessageType, UnityMessagingClient } from './unityMessagingClient';
6+
import { UnityMessagingClient } from './unityMessagingClient';
77

88
const readFile = promisify(fs.readFile);
99
const readdir = promisify(fs.readdir);
@@ -413,7 +413,7 @@ export class UnityPackageHelper {
413413
return;
414414
}
415415

416-
messagingClient.onMessage(MessageType.CompilationFinished, async () => {
416+
messagingClient.onCompilationFinished.subscribe(async () => {
417417
console.log('UnityCode: Compilation finished, updating packages...');
418418
await this.updatePackages();
419419
});

0 commit comments

Comments
 (0)