mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-07-31 12:13:14 +00:00
feat: add config for logos chat client (#163)
* feat: add config for logos chat client * chore: fix mock registry log message * chore: set custom fields in logos config
This commit is contained in:
parent
c09459c0a0
commit
b6fe452ea7
2
.github/scripts/mock-registry.py
vendored
2
.github/scripts/mock-registry.py
vendored
@ -38,7 +38,7 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
self._drain()
|
self._drain()
|
||||||
self._reply(404)
|
self._reply(404)
|
||||||
|
|
||||||
def log_message(self, *args):
|
def log_message(self, format, *args):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -11,8 +11,8 @@ use crossbeam_channel::Receiver;
|
|||||||
use logos_account::TestLogosAccount;
|
use logos_account::TestLogosAccount;
|
||||||
use logos_chat::{
|
use logos_chat::{
|
||||||
AccountDirectory, ChatClient, ChatClientBuilder, ChatStore, DelegateSigner, Event,
|
AccountDirectory, ChatClient, ChatClientBuilder, ChatStore, DelegateSigner, Event,
|
||||||
HttpRegistry, LogosChatClient, NETWORK_PRESET, REGISTRY_ENDPOINT, RegistrationService,
|
HttpRegistry, LogosChatClient, LogosConfig, NETWORK_PRESET, REGISTRY_ENDPOINT,
|
||||||
StorageConfig, Transport,
|
RegistrationService, StorageConfig, Transport,
|
||||||
};
|
};
|
||||||
|
|
||||||
use app::ChatApp;
|
use app::ChatApp;
|
||||||
@ -49,9 +49,10 @@ struct Cli {
|
|||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
preset: Option<String>,
|
preset: Option<String>,
|
||||||
|
|
||||||
/// TCP port for the embedded logos-delivery node.
|
/// TCP port for the embedded logos-delivery node. When omitted, the
|
||||||
#[arg(long, default_value_t = 60000)]
|
/// preconfigured port is used.
|
||||||
port: u16,
|
#[arg(long)]
|
||||||
|
port: Option<u16>,
|
||||||
|
|
||||||
/// Write logs to a file instead of stderr (keeps TUI output clean).
|
/// Write logs to a file instead of stderr (keeps TUI output clean).
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
@ -84,15 +85,19 @@ fn main() -> Result<()> {
|
|||||||
println!("Starting logos-delivery node (preset={preset})...");
|
println!("Starting logos-delivery node (preset={preset})...");
|
||||||
println!("This may take a few seconds while connecting to the network.");
|
println!("This may take a few seconds while connecting to the network.");
|
||||||
|
|
||||||
let (client, events) = LogosChatClient::open(
|
let mut config = LogosConfig::new(db_str, "chat-cli");
|
||||||
db_str,
|
if let Some(port) = cli.port {
|
||||||
"chat-cli",
|
config.set_tcp_port(port);
|
||||||
cli.port,
|
}
|
||||||
cli.preset.as_deref(),
|
if let Some(preset) = cli.preset.as_deref() {
|
||||||
cli.registry_url.as_deref(),
|
config.set_preset(preset);
|
||||||
)
|
}
|
||||||
.map_err(|e| anyhow::anyhow!("{e:?}"))
|
if let Some(registry_url) = cli.registry_url.as_deref() {
|
||||||
.context("failed to open chat client")?;
|
config.set_registry_url(registry_url);
|
||||||
|
}
|
||||||
|
let (client, events) = LogosChatClient::open(config)
|
||||||
|
.map_err(|e| anyhow::anyhow!("{e:?}"))
|
||||||
|
.context("failed to open chat client")?;
|
||||||
|
|
||||||
println!("Node connected.");
|
println!("Node connected.");
|
||||||
launch_tui(client, events, &cli)
|
launch_tui(client, events, &cli)
|
||||||
|
|||||||
@ -5,3 +5,6 @@ pub const REGISTRY_ENDPOINT: &str = "https://devnet.chat-kc.logos.co";
|
|||||||
|
|
||||||
/// The logos-delivery network preset the Logos client joins by default.
|
/// The logos-delivery network preset the Logos client joins by default.
|
||||||
pub const NETWORK_PRESET: &str = "logos.dev";
|
pub const NETWORK_PRESET: &str = "logos.dev";
|
||||||
|
|
||||||
|
/// Default TCP port for the embedded logos-delivery node.
|
||||||
|
pub const DEFAULT_TCP_PORT: u16 = 60000;
|
||||||
|
|||||||
@ -10,13 +10,13 @@ mod logos;
|
|||||||
|
|
||||||
pub use builder::{ChatClientBuilder, Unset};
|
pub use builder::{ChatClientBuilder, Unset};
|
||||||
pub use client::{ChatClient, Transport};
|
pub use client::{ChatClient, Transport};
|
||||||
pub use config::{NETWORK_PRESET, REGISTRY_ENDPOINT};
|
pub use config::{DEFAULT_TCP_PORT, NETWORK_PRESET, REGISTRY_ENDPOINT};
|
||||||
pub use delegate::DelegateSigner;
|
pub use delegate::DelegateSigner;
|
||||||
pub use delivery_in_process::{InProcessDelivery, MessageBus};
|
pub use delivery_in_process::{InProcessDelivery, MessageBus};
|
||||||
pub use errors::ClientError;
|
pub use errors::ClientError;
|
||||||
pub use event::{Event, MessageSender};
|
pub use event::{Event, MessageSender};
|
||||||
#[cfg(feature = "embedded-p2p-delivery")]
|
#[cfg(feature = "embedded-p2p-delivery")]
|
||||||
pub use logos::LogosChatClient;
|
pub use logos::{LogosChatClient, LogosConfig};
|
||||||
|
|
||||||
// Re-export types callers need to interact with ChatClient.
|
// Re-export types callers need to interact with ChatClient.
|
||||||
pub use libchat::{
|
pub use libchat::{
|
||||||
|
|||||||
@ -20,7 +20,7 @@ use logos_account::TestLogosAccount;
|
|||||||
|
|
||||||
use crate::ChatClientBuilder;
|
use crate::ChatClientBuilder;
|
||||||
use crate::client::{ChatClient, Transport};
|
use crate::client::{ChatClient, Transport};
|
||||||
use crate::config::{NETWORK_PRESET, REGISTRY_ENDPOINT};
|
use crate::config::{DEFAULT_TCP_PORT, NETWORK_PRESET, REGISTRY_ENDPOINT};
|
||||||
use crate::delegate::DelegateSigner;
|
use crate::delegate::DelegateSigner;
|
||||||
use crate::errors::ClientError;
|
use crate::errors::ClientError;
|
||||||
use crate::event::Event;
|
use crate::event::Event;
|
||||||
@ -34,6 +34,54 @@ impl Transport for EmbeddedP2pDeliveryService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configuration for opening a [`LogosChatClient`].
|
||||||
|
///
|
||||||
|
/// `db_path` (a per-client location) and `db_key` (a secret) are required and
|
||||||
|
/// never baked into the library. The TCP port and the network config default to
|
||||||
|
/// the baked-in Logos values; override them with the setters (e.g. to point at a
|
||||||
|
/// local deployment).
|
||||||
|
pub struct LogosConfig {
|
||||||
|
db_path: String,
|
||||||
|
db_key: String,
|
||||||
|
tcp_port: u16,
|
||||||
|
preset: String,
|
||||||
|
registry_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LogosConfig {
|
||||||
|
/// Config for the required per-client `db_path` and `db_key`. The TCP port,
|
||||||
|
/// network preset, and registry endpoint default to the baked-in Logos
|
||||||
|
/// values; override them with [`set_tcp_port`](Self::set_tcp_port),
|
||||||
|
/// [`set_preset`](Self::set_preset), and
|
||||||
|
/// [`set_registry_url`](Self::set_registry_url).
|
||||||
|
pub fn new(db_path: impl Into<String>, db_key: impl Into<String>) -> Self {
|
||||||
|
Self {
|
||||||
|
db_path: db_path.into(),
|
||||||
|
db_key: db_key.into(),
|
||||||
|
tcp_port: DEFAULT_TCP_PORT,
|
||||||
|
preset: NETWORK_PRESET.to_string(),
|
||||||
|
registry_url: REGISTRY_ENDPOINT.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Override the TCP port for the embedded logos-delivery node.
|
||||||
|
pub fn set_tcp_port(&mut self, tcp_port: u16) {
|
||||||
|
self.tcp_port = tcp_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Override the logos-delivery network preset (defaults to the baked-in
|
||||||
|
/// [`NETWORK_PRESET`]).
|
||||||
|
pub fn set_preset(&mut self, preset: impl Into<String>) {
|
||||||
|
self.preset = preset.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Override the registry endpoint (account + keypackage store; defaults to
|
||||||
|
/// the baked-in [`REGISTRY_ENDPOINT`]).
|
||||||
|
pub fn set_registry_url(&mut self, registry_url: impl Into<String>) {
|
||||||
|
self.registry_url = registry_url.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A [`ChatClient`] wired to the Logos service stack: a [`DelegateSigner`]
|
/// A [`ChatClient`] wired to the Logos service stack: a [`DelegateSigner`]
|
||||||
/// identity acting for a fresh dev account, the HTTP keypackage + account
|
/// identity acting for a fresh dev account, the HTTP keypackage + account
|
||||||
/// registry ([`HttpRegistry`], which is both the keypackage store and the
|
/// registry ([`HttpRegistry`], which is both the keypackage store and the
|
||||||
@ -42,37 +90,23 @@ impl Transport for EmbeddedP2pDeliveryService {
|
|||||||
pub type LogosChatClient = ChatClient<EmbeddedP2pDeliveryService, HttpRegistry, ChatStorage>;
|
pub type LogosChatClient = ChatClient<EmbeddedP2pDeliveryService, HttpRegistry, ChatStorage>;
|
||||||
|
|
||||||
impl LogosChatClient {
|
impl LogosChatClient {
|
||||||
/// Open a client on the Logos stack, starting a logos-delivery node on
|
/// Open a client on the Logos stack per `config`, starting a logos-delivery
|
||||||
/// `tcp_port` as its transport and persisting to the encrypted database at
|
/// node as its transport and persisting to the encrypted database.
|
||||||
/// `db_path` unlocked with `db_key`. When `preset`/`registry_url` are `Some`,
|
pub fn open(config: LogosConfig) -> Result<(Self, Receiver<Event>), ClientError> {
|
||||||
/// they override the baked-in network preset/registry endpoint (e.g. a local
|
|
||||||
/// deployment); otherwise the preconfigured values are used.
|
|
||||||
///
|
|
||||||
/// `db_path` is a per-client location, `db_key` is a secret, and `tcp_port`
|
|
||||||
/// is a per-client local resource, so all three are caller-supplied — never
|
|
||||||
/// baked into the library.
|
|
||||||
pub fn open(
|
|
||||||
db_path: impl Into<String>,
|
|
||||||
db_key: impl Into<String>,
|
|
||||||
tcp_port: u16,
|
|
||||||
preset: Option<&str>,
|
|
||||||
registry_url: Option<&str>,
|
|
||||||
) -> Result<(Self, Receiver<Event>), ClientError> {
|
|
||||||
let transport = EmbeddedP2pDeliveryService::start(P2pConfig {
|
let transport = EmbeddedP2pDeliveryService::start(P2pConfig {
|
||||||
preset: preset.unwrap_or(NETWORK_PRESET).to_string(),
|
preset: config.preset,
|
||||||
tcp_port,
|
tcp_port: config.tcp_port,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.map_err(|e| ClientError::Transport(e.to_string()))?;
|
.map_err(|e| ClientError::Transport(e.to_string()))?;
|
||||||
|
|
||||||
let endpoint = registry_url.unwrap_or(REGISTRY_ENDPOINT);
|
|
||||||
// A fresh account endorsing a fresh delegate each open: the account
|
// A fresh account endorsing a fresh delegate each open: the account
|
||||||
// key is dropped after publishing the bundle, so devices cannot be
|
// key is dropped after publishing the bundle, so devices cannot be
|
||||||
// added later. A caller-supplied, custody-holding account replaces
|
// added later. A caller-supplied, custody-holding account replaces
|
||||||
// this once the platform provides one.
|
// this once the platform provides one.
|
||||||
let account = TestLogosAccount::new();
|
let account = TestLogosAccount::new();
|
||||||
let delegate = DelegateSigner::random();
|
let delegate = DelegateSigner::random();
|
||||||
let mut registry = HttpRegistry::new(endpoint);
|
let mut registry = HttpRegistry::new(config.registry_url);
|
||||||
account
|
account
|
||||||
.add_delegate_signer(&mut registry, delegate.public_key())
|
.add_delegate_signer(&mut registry, delegate.public_key())
|
||||||
.map_err(|e| ClientError::BundlePublish(e.to_string()))?;
|
.map_err(|e| ClientError::BundlePublish(e.to_string()))?;
|
||||||
@ -81,8 +115,8 @@ impl LogosChatClient {
|
|||||||
.transport(transport)
|
.transport(transport)
|
||||||
.registration(registry)
|
.registration(registry)
|
||||||
.storage_config(StorageConfig::Encrypted {
|
.storage_config(StorageConfig::Encrypted {
|
||||||
path: db_path.into(),
|
path: config.db_path,
|
||||||
key: db_key.into(),
|
key: config.db_key,
|
||||||
})
|
})
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user