connect method
Connect to Socket.IO server
Implementation
Future<String?> connect({String? authToken}) async {
try {
print('🔌 [SOCKET] Connecting to Socket.IO server...');
// Disconnect existing connection if any
disconnect();
// Create socket connection.
//
// IMPORTANT: onairos-npm (web SDK) authenticates via `auth: { token }` and then emits
// `start-training` after connect. We send auth both ways (handshake auth + header) for
// maximum backend compatibility.
final opts = <String, dynamic>{
'transports': ['websocket', 'polling'],
'reconnection': false,
'timeout': 60000,
if (authToken != null) 'auth': {'token': authToken},
if (authToken != null) 'extraHeaders': {'Authorization': 'Bearer $authToken'},
};
_socket = IO.io('https://api2.onairos.uk', opts);
// Create completer to wait for connection
_connectionCompleter = Completer<String?>();
// Set up event listeners
_socket!.onConnect((_) {
print('✅ [SOCKET] Connected to training server');
_isConnected = true;
_socketId = _socket!.id;
print('🔑 [SOCKET] Socket ID: $_socketId');
// Complete the connection completer
if (!_connectionCompleter!.isCompleted) {
_connectionCompleter!.complete(_socketId);
}
});
_socket!.onDisconnect((_) {
print('❌ [SOCKET] Disconnected from training server');
_isConnected = false;
_socketId = null;
});
_socket!.onConnectError((error) {
print('❌ [SOCKET] Connection error: $error');
_errorController.add('Connection failed: $error');
// Complete with null on error
if (!_connectionCompleter!.isCompleted) {
_connectionCompleter!.complete(null);
}
});
// Listen for training updates
_socket!.on('trainingUpdate', (data) {
print('📡 [SOCKET] Training update received: $data');
_progressController.add(Map<String, dynamic>.from(data));
if (data['status'] != null) {
_statusController.add(data['status'].toString());
}
if (data['error'] != null) {
_errorController.add(data['error'].toString());
}
});
// Listen for training completion
_socket!.on('trainingCompleted', (data) {
print('✅ [SOCKET] Training completed: $data');
_completionController.add({
...Map<String, dynamic>.from(data),
'completed': true,
'sourceEvent': 'trainingCompleted',
});
});
// onairos-npm uses these event names.
_socket!.on('training-progress', (data) {
print('📡 [SOCKET] training-progress: $data');
_progressController.add(Map<String, dynamic>.from(data));
});
_socket!.on('training-complete', (data) {
print('✅ [SOCKET] training-complete: $data');
_completionController.add({
...Map<String, dynamic>.from(data),
'completed': true,
'sourceEvent': 'training-complete',
});
});
// Back-compat: legacy Enoch mobile backend events (we no longer depend on them for flow).
_socket!.on('inferenceCompleted', (data) {
print('🧠 [SOCKET] Inference completed (legacy): $data');
_completionController.add({
...Map<String, dynamic>.from(data),
'completed': true,
'sourceEvent': 'inferenceCompleted',
});
});
_socket!.on('modelStandby', (data) {
print('✅ [SOCKET] Model standby (legacy): $data');
_completionController.add({
...Map<String, dynamic>.from(data),
'completed': true,
'fullyComplete': true,
'sourceEvent': 'modelStandby',
});
});
// Connect to server
_socket!.connect();
// Wait for connection with timeout
try {
final socketId = await _connectionCompleter!.future.timeout(
const Duration(seconds: 10),
onTimeout: () {
print('⚠️ [SOCKET] Connection timeout after 10 seconds');
if (!_connectionCompleter!.isCompleted) {
_connectionCompleter!.complete(null);
}
return null;
},
);
if (socketId != null) {
print('✅ [SOCKET] Successfully connected with ID: $socketId');
return socketId;
} else {
print('⚠️ [SOCKET] Connection failed or timed out');
return null;
}
} catch (e) {
print('❌ [SOCKET] Error waiting for connection: $e');
return null;
}
} catch (e) {
print('❌ [SOCKET] Error connecting: $e');
_errorController.add('Connection error: $e');
return null;
}
}