T-127: replace InProcessClient with socket loopback
test / unit + widget + golden + a11y (push) Failing after 2m16s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 29s
test / unit + widget + golden + a11y (push) Failing after 2m16s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 29s
Fourth slice of T-99. The UI's DaemonClient now talks to its own IpcServer through the same per-workspace Unix socket the C `clide` client uses — one transport, one wire contract, no second path through the dispatch tree. Changes: * lib/kernel/src/ipc/in_process.dart deleted. Nothing imports it. * DaemonClient.socketPath becomes mutable + new `reconnectAt(path)` method swaps an active client onto a different socket without restart. Project switch in main.dart uses it — the dispatcher + IpcServer are rebuilt for the new workspace, and the client reconnects to the new path. * main.dart's daemonClientFactory now builds a real DaemonClient pointed at workspaceSocketPath(workRoot); swapIpcServer kicks off server.start() then client.start() in sequence. * lib/test_app.dart's pane.spawn smoke test uses dispatcher.dispatch directly instead of InProcessClient — same coverage, no dead-end import. * DaemonClient client_test gets a reconnectAt round-trip test. T-128 (delete IsolateClient + Backend + backend_entry.dart) unblocked. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -11,13 +11,15 @@ import 'package:flutter/foundation.dart';
|
||||
|
||||
class DaemonClient extends ChangeNotifier {
|
||||
DaemonClient({
|
||||
required this.socketPath,
|
||||
required String socketPath,
|
||||
required Logger log,
|
||||
required DaemonBus events,
|
||||
}) : _log = log,
|
||||
}) : _socketPath = socketPath,
|
||||
_log = log,
|
||||
_events = events;
|
||||
|
||||
final String socketPath;
|
||||
String _socketPath;
|
||||
String get socketPath => _socketPath;
|
||||
final Logger _log;
|
||||
final DaemonBus _events;
|
||||
|
||||
@@ -47,6 +49,28 @@ class DaemonClient extends ChangeNotifier {
|
||||
_setConnected(false);
|
||||
}
|
||||
|
||||
/// Point the client at a different socket path and reconnect.
|
||||
/// Used on project switch — the workspace-derived socket path
|
||||
/// (D-70) changes when the user opens a different project, so the
|
||||
/// client follows. Cancels the reconnect timer, closes the live
|
||||
/// socket (failing in-flight requests with `disconnect`), updates
|
||||
/// the path, and re-arms the connect loop. Idempotent if the new
|
||||
/// path equals the current one.
|
||||
Future<void> reconnectAt(String newPath) async {
|
||||
if (newPath == _socketPath && _connected) return;
|
||||
_socketPath = newPath;
|
||||
_reconnectTimer?.cancel();
|
||||
_reconnectTimer = null;
|
||||
final s = _socket;
|
||||
_socket = null;
|
||||
await s?.close();
|
||||
_failPending('socket path changed');
|
||||
_setConnected(false);
|
||||
_disposed = false;
|
||||
_backoff = const Duration(milliseconds: 200);
|
||||
await _connect();
|
||||
}
|
||||
|
||||
Future<IpcResponse> request(
|
||||
String cmd, {
|
||||
Map<String, Object?> args = const {},
|
||||
@@ -72,12 +96,12 @@ class DaemonClient extends ChangeNotifier {
|
||||
Future<void> _connect() async {
|
||||
if (_disposed) return;
|
||||
try {
|
||||
final addr = InternetAddress(socketPath, type: InternetAddressType.unix);
|
||||
final addr = InternetAddress(_socketPath, type: InternetAddressType.unix);
|
||||
final socket = await Socket.connect(addr, 0);
|
||||
_socket = socket;
|
||||
_backoff = const Duration(milliseconds: 200);
|
||||
_setConnected(true);
|
||||
_log.info('ipc', 'connected to $socketPath');
|
||||
_log.info('ipc', 'connected to $_socketPath');
|
||||
socket.cast<List<int>>().transform(utf8.decoder).transform(const LineSplitter()).listen(
|
||||
_handleLine,
|
||||
onDone: _handleDisconnect,
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import 'package:clide/clide.dart';
|
||||
import 'package:clide/kernel/src/ipc/client.dart';
|
||||
|
||||
class InProcessClient extends DaemonClient {
|
||||
InProcessClient({
|
||||
required super.log,
|
||||
required super.events,
|
||||
required this.dispatcher,
|
||||
}) : super(socketPath: '');
|
||||
|
||||
DaemonDispatcher dispatcher;
|
||||
int _nextReqId = 0;
|
||||
|
||||
@override
|
||||
bool get isConnected => true;
|
||||
|
||||
@override
|
||||
Future<void> start() async {}
|
||||
|
||||
@override
|
||||
Future<void> stop() async {}
|
||||
|
||||
@override
|
||||
Future<IpcResponse> request(String cmd, {Map<String, Object?> args = const {}}) {
|
||||
final id = '${_nextReqId++}';
|
||||
final req = IpcRequest(id: id, cmd: cmd, args: args);
|
||||
return dispatcher.dispatch(req);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user