feat: import Chinese-localized Buzz source snapshot
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Signed-off-by: cls_宁波本机 <908705107@qq.com>
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:nostr/nostr.dart' as nostr;
|
||||
|
||||
import '../community/community_provider.dart';
|
||||
import 'relay_client.dart';
|
||||
|
||||
/// Relay connection configuration.
|
||||
///
|
||||
/// In the pure-nostr world the only secrets the app cares about are:
|
||||
/// - `baseUrl` — where the relay lives (used for WS + media upload)
|
||||
/// - `nsec` — the user's signing key (drives NIP-42 AUTH and event sigs)
|
||||
class RelayConfig {
|
||||
const RelayConfig({required String baseUrl, this.nsec}) : _baseUrl = baseUrl;
|
||||
|
||||
/// Relay origin exactly as the active community stored it.
|
||||
final String _baseUrl;
|
||||
|
||||
/// Nostr secret key (bech32 nsec) for signing events and NIP-42 AUTH.
|
||||
final String? nsec;
|
||||
|
||||
/// The origin as persisted, before scheme canonicalization.
|
||||
///
|
||||
/// Exists solely so identity-scoped storage keys written before [baseUrl]
|
||||
/// was canonicalized stay reachable — see [readMigratedPref]. Never use it
|
||||
/// for network I/O; [baseUrl] and [wsUrl] are the addresses to connect to.
|
||||
String get storedOrigin => _baseUrl;
|
||||
|
||||
/// Relay origin as an HTTP(S) URL.
|
||||
///
|
||||
/// Communities are persisted with whichever scheme their onboarding flow
|
||||
/// used: device pairing stores `https://` (it rejects anything else), while
|
||||
/// an invite join stores the `wss://` relay URL carried by the invite link.
|
||||
/// Every consumer treats this as an HTTP origin — [wsUrl], the `/query`
|
||||
/// endpoint, media upload and Blossom auth — so a `wss://` base silently
|
||||
/// degrades all of them. Folding the websocket schemes back here keeps both
|
||||
/// onboarding paths equivalent, including for already-persisted communities.
|
||||
///
|
||||
/// Derived rather than normalized in the constructor so that the constructor
|
||||
/// stays `const`: the compile-time fallback below relies on canonicalization
|
||||
/// to keep its identity stable across rebuilds, and Riverpod's default
|
||||
/// `updateShouldNotify` is `previous != next`, which falls back to identity
|
||||
/// here. A fresh instance per rebuild would resubscribe every listener.
|
||||
String get baseUrl {
|
||||
final uri = Uri.tryParse(_baseUrl);
|
||||
if (uri == null) return _baseUrl;
|
||||
final scheme = switch (uri.scheme) {
|
||||
'wss' => 'https',
|
||||
'ws' => 'http',
|
||||
_ => null,
|
||||
};
|
||||
return scheme == null ? _baseUrl : uri.replace(scheme: scheme).toString();
|
||||
}
|
||||
|
||||
/// Derive the websocket URL from the HTTP base URL.
|
||||
String get wsUrl {
|
||||
final uri = Uri.parse(baseUrl);
|
||||
final scheme = uri.scheme == 'https' ? 'wss' : 'ws';
|
||||
return uri.replace(scheme: scheme).toString();
|
||||
}
|
||||
}
|
||||
|
||||
/// Compile-time environment config via --dart-define.
|
||||
///
|
||||
/// Run with:
|
||||
/// flutter run --dart-define=BUZZ_RELAY_URL=http://localhost:3000
|
||||
///
|
||||
/// Or create a `.env.json` and use --dart-define-from-file=.env.json
|
||||
class Env {
|
||||
static const relayUrl = String.fromEnvironment(
|
||||
'BUZZ_RELAY_URL',
|
||||
defaultValue: 'http://localhost:3000',
|
||||
);
|
||||
}
|
||||
|
||||
class RelayConfigNotifier extends Notifier<RelayConfig> {
|
||||
@override
|
||||
RelayConfig build() {
|
||||
// Watch the active community so that when it changes (community switch),
|
||||
// the config rebuilds, triggering the full provider cascade.
|
||||
final activeAsync = ref.watch(activeCommunityProvider);
|
||||
final active = activeAsync.value;
|
||||
if (active != null) {
|
||||
return RelayConfig(baseUrl: active.relayUrl, nsec: active.nsec);
|
||||
}
|
||||
|
||||
// Fallback to compile-time env config (dev mode).
|
||||
return const RelayConfig(baseUrl: Env.relayUrl);
|
||||
}
|
||||
|
||||
void update({required String baseUrl, String? nsec}) {
|
||||
state = RelayConfig(baseUrl: baseUrl, nsec: nsec);
|
||||
}
|
||||
}
|
||||
|
||||
final relayConfigProvider = NotifierProvider<RelayConfigNotifier, RelayConfig>(
|
||||
RelayConfigNotifier.new,
|
||||
);
|
||||
|
||||
/// Derive the hex pubkey from a bech32 nsec, or null on any failure.
|
||||
String? pubkeyFromNsec(String? nsec) {
|
||||
if (nsec == null || nsec.isEmpty) return null;
|
||||
try {
|
||||
final privkeyHex = nostr.Nip19.decode(payload: nsec).data;
|
||||
if (privkeyHex.isEmpty) return null;
|
||||
return nostr.Keys(privkeyHex).public;
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// The current user's hex pubkey, derived from the active community nsec.
|
||||
final myPubkeyProvider = Provider<String?>((ref) {
|
||||
final config = ref.watch(relayConfigProvider);
|
||||
return pubkeyFromNsec(config.nsec);
|
||||
});
|
||||
|
||||
/// Provides a [RelayClient] that reacts to config changes.
|
||||
///
|
||||
/// Only used for the media upload HTTP endpoint now — all data flow goes
|
||||
/// through the relay WebSocket session.
|
||||
final relayClientProvider = Provider<RelayClient>((ref) {
|
||||
final config = ref.watch(relayConfigProvider);
|
||||
final client = RelayClient(baseUrl: config.baseUrl);
|
||||
ref.onDispose(client.dispose);
|
||||
return client;
|
||||
});
|
||||
Reference in New Issue
Block a user