feat: wire chain_client_sdk gRPC client + HubRepository scaffold
Adds a real Ch∆In hub backend to the Flutter client as a sibling-path dependency on chain_client_sdk_dart, alongside the existing MockRepository (which stays the default until the flow.completed-to-Evaluation pipeline lands in Phase 0 week 1). Wiring HubSettings (lib/data/hub_endpoint.dart) — persists host / port / secure / token / useHub flags via SharedPreferences under the Studio-compatible hub.* keys. Distinct from the SDK's chain.HubEndpoint, which is a transport-level value type — HubSettings adapts in that direction. HubRepository (lib/data/hub_repository.dart) — implements EvaluationRepository on top of HubClient. connect() runs a 4-second healthy() probe; on failure returns a repository with isHealthy=false rather than throwing, so the UI can surface "hub-down" without an exception-handling round-trip. list() / byEli() return empty data in Phase 0 because no hub-side flow yet produces Evaluation objects in the lawheatmap-specific shape. main.dart — loads HubSettings on startup; if useHub=false starts with MockRepository (fast offline default), otherwise probes the hub and falls back to MockRepository on probe failure. No mid-session swap to keep the Phase 0 wiring simple; a settings save instructs the user to restart. HubStatusPage — read-only summary card at the top, editable endpoint form, "Verbindung testen" probe button, "Speichern" persist button. Live-flow runbook below describes the chain serve / install / run / approve sequence so a user can wire the real flow themselves once Phase 1 lands. flutter analyze: clean. flutter test: 2/2 passing. Smoke-launch on macOS: app boots, Dart VM service comes up, no runtime errors in mock mode. Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
parent
fa8acd41b8
commit
39733628b6
6 changed files with 509 additions and 31 deletions
83
app/lib/data/hub_endpoint.dart
Normal file
83
app/lib/data/hub_endpoint.dart
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
/// Persisted user settings for the Ch∆In hub connection.
|
||||
///
|
||||
/// Stored under four SharedPreferences keys matching the Studio
|
||||
/// convention (`hub.host`, `hub.port`, `hub.secure`, `hub.token`)
|
||||
/// so a hub once configured stays configured across app launches.
|
||||
/// Distinct from the SDK's `chain.HubEndpoint`, which is a
|
||||
/// transport-level value type — [HubSettings.toEndpoint] adapts
|
||||
/// in that direction.
|
||||
class HubSettings {
|
||||
const HubSettings({
|
||||
required this.host,
|
||||
required this.port,
|
||||
required this.secure,
|
||||
this.authToken,
|
||||
this.useHub = false,
|
||||
});
|
||||
|
||||
final String host;
|
||||
final int port;
|
||||
final bool secure;
|
||||
|
||||
/// Bearer token; read from `~/.chain/hub-auth-token` by the
|
||||
/// hub-status page in Phase 1. Optional in Phase 0 because the
|
||||
/// default `chain serve` runs without auth.
|
||||
final String? authToken;
|
||||
|
||||
/// User intent: try to connect to the hub on startup. False
|
||||
/// keeps the app in MockRepository mode regardless of host/port.
|
||||
final bool useHub;
|
||||
|
||||
static const defaultHost = '127.0.0.1';
|
||||
static const defaultPort = 50051;
|
||||
|
||||
String get scheme => secure ? 'https' : 'http';
|
||||
String get url => '$scheme://$host:$port';
|
||||
|
||||
static const _kHost = 'hub.host';
|
||||
static const _kPort = 'hub.port';
|
||||
static const _kSecure = 'hub.secure';
|
||||
static const _kToken = 'hub.token';
|
||||
static const _kUseHub = 'hub.use';
|
||||
|
||||
static Future<HubSettings> load() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return HubSettings(
|
||||
host: prefs.getString(_kHost) ?? defaultHost,
|
||||
port: prefs.getInt(_kPort) ?? defaultPort,
|
||||
secure: prefs.getBool(_kSecure) ?? false,
|
||||
authToken: prefs.getString(_kToken),
|
||||
useHub: prefs.getBool(_kUseHub) ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> save() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_kHost, host);
|
||||
await prefs.setInt(_kPort, port);
|
||||
await prefs.setBool(_kSecure, secure);
|
||||
await prefs.setBool(_kUseHub, useHub);
|
||||
if (authToken != null) {
|
||||
await prefs.setString(_kToken, authToken!);
|
||||
} else {
|
||||
await prefs.remove(_kToken);
|
||||
}
|
||||
}
|
||||
|
||||
HubSettings copyWith({
|
||||
String? host,
|
||||
int? port,
|
||||
bool? secure,
|
||||
String? authToken,
|
||||
bool? useHub,
|
||||
}) =>
|
||||
HubSettings(
|
||||
host: host ?? this.host,
|
||||
port: port ?? this.port,
|
||||
secure: secure ?? this.secure,
|
||||
authToken: authToken ?? this.authToken,
|
||||
useHub: useHub ?? this.useHub,
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue