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
74
app/lib/data/hub_repository.dart
Normal file
74
app/lib/data/hub_repository.dart
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import 'package:chain_client_sdk/chain_client_sdk.dart' as chain;
|
||||
|
||||
import 'hub_endpoint.dart';
|
||||
import 'models.dart';
|
||||
import 'repository.dart';
|
||||
|
||||
/// Live `EvaluationRepository` backed by a Ch∆In hub over gRPC.
|
||||
///
|
||||
/// Phase 0 scope: open a HubClient, run a healthy() probe, and
|
||||
/// surface the connection state to the UI. The list() / byEli()
|
||||
/// methods return empty data because no flow on the hub yet
|
||||
/// produces Evaluation objects in the lawheatmap-specific shape —
|
||||
/// that pipeline lands in Phase 0 week 1 once a chain run wraps
|
||||
/// flows/durchstich-gewo-14.yaml output into the Evaluation
|
||||
/// schema.
|
||||
///
|
||||
/// Until then [MockRepository] stays the default. Pick this
|
||||
/// repository explicitly via the Hub-settings page; on first
|
||||
/// healthy() failure the app falls back to MockRepository so the
|
||||
/// UI keeps working.
|
||||
class HubRepository implements EvaluationRepository {
|
||||
HubRepository._(this._client, this.settings, this._healthy);
|
||||
|
||||
final chain.HubClient _client;
|
||||
final HubSettings settings;
|
||||
final bool _healthy;
|
||||
|
||||
/// Try to connect. Returns a repository with `isHealthy=false`
|
||||
/// if the probe times out or the hub is unreachable; the
|
||||
/// caller decides whether to use it or fall back to
|
||||
/// MockRepository.
|
||||
static Future<HubRepository> connect(HubSettings settings) async {
|
||||
final endpoint = chain.HubEndpoint(
|
||||
host: settings.host,
|
||||
port: settings.port,
|
||||
secure: settings.secure,
|
||||
);
|
||||
final client = chain.HubClient(
|
||||
endpoint: endpoint,
|
||||
authToken: settings.authToken,
|
||||
);
|
||||
final ok = await client.healthy().timeout(
|
||||
const Duration(seconds: 4),
|
||||
onTimeout: () => false,
|
||||
);
|
||||
return HubRepository._(client, settings, ok);
|
||||
}
|
||||
|
||||
bool get isHealthy => _healthy;
|
||||
|
||||
/// Underlying SDK client — exposed so the hub-status page can
|
||||
/// list capabilities, query the audit log, and verify the
|
||||
/// event-chain without leaking gRPC types to other pages.
|
||||
chain.HubClient get client => _client;
|
||||
|
||||
@override
|
||||
Future<List<Evaluation>> list() async {
|
||||
// Phase 0 placeholder. The pipeline that turns
|
||||
// flow.completed events into Evaluation objects lives in the
|
||||
// surrounding flow (flows/durchstich-gewo-14.yaml) and lands
|
||||
// in Phase 0 week 1.
|
||||
return const [];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Evaluation?> byEli(String eli) async => null;
|
||||
|
||||
@override
|
||||
String get mode => _healthy ? 'hub-live' : 'hub-down';
|
||||
|
||||
@override
|
||||
String get hubLabel => '${settings.url}'
|
||||
'${_healthy ? '' : ' — Verbindung gestört'}';
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue