mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-08-25 15:11:15 +00:00
feat: http server based key package registry (#124)
* feat: http server based key package registry * chore: instructions on running the registration service * chore: remove duplicate post param * chore: revert out sourced account id for multi devices support * feat: signature on account id and key packages * chore: include http registry in contact registry module * refactor: use device id for retrieve key package * chore: use string for device id * feat: server verification on the register * chore: doc the smoke test * chore: fix data folder non exist * chore: use payload for register and retrieve * chore: fix clippy
This commit is contained in:
@@ -5,7 +5,7 @@ use std::sync::mpsc;
|
||||
|
||||
use anyhow::Result;
|
||||
use arboard::Clipboard;
|
||||
use logos_chat::{ChatClient, DeliveryService, Event};
|
||||
use logos_chat::{ChatClient, DeliveryService, EphemeralRegistry, Event, RegistrationService};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::utils::now;
|
||||
@@ -41,8 +41,8 @@ pub struct AppState {
|
||||
pub active_chat: Option<String>,
|
||||
}
|
||||
|
||||
pub struct ChatApp<D: DeliveryService> {
|
||||
pub client: ChatClient<D>,
|
||||
pub struct ChatApp<D: DeliveryService, R: RegistrationService = EphemeralRegistry> {
|
||||
pub client: ChatClient<D, R>,
|
||||
inbound: mpsc::Receiver<Vec<u8>>,
|
||||
pub state: AppState,
|
||||
/// Ephemeral command output — not persisted, cleared on chat switch.
|
||||
@@ -53,9 +53,13 @@ pub struct ChatApp<D: DeliveryService> {
|
||||
state_path: PathBuf,
|
||||
}
|
||||
|
||||
impl<D: DeliveryService + 'static> ChatApp<D> {
|
||||
impl<D, R> ChatApp<D, R>
|
||||
where
|
||||
D: DeliveryService + 'static,
|
||||
R: RegistrationService + 'static,
|
||||
{
|
||||
pub fn new(
|
||||
client: ChatClient<D>,
|
||||
client: ChatClient<D, R>,
|
||||
inbound: mpsc::Receiver<Vec<u8>>,
|
||||
user_name: &str,
|
||||
data_dir: &Path,
|
||||
|
||||
+42
-15
@@ -8,7 +8,7 @@ use std::sync::mpsc;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use clap::{Parser, ValueEnum};
|
||||
use logos_chat::DeliveryService;
|
||||
use logos_chat::{ChatClient, DeliveryService, HttpRegistry, RegistrationService, StorageConfig};
|
||||
|
||||
use app::ChatApp;
|
||||
|
||||
@@ -55,6 +55,12 @@ struct Cli {
|
||||
/// Initialize and immediately exit without launching the TUI (for CI).
|
||||
#[arg(long)]
|
||||
smoketest: bool,
|
||||
|
||||
/// Optional KeyPackage registry base URL. When set, uses the HTTP-backed
|
||||
/// registry instead of the in-memory `EphemeralRegistry`.
|
||||
/// Example: `--registry-url http://localhost:8080`.
|
||||
#[arg(long)]
|
||||
registry_url: Option<String>,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
@@ -104,18 +110,38 @@ fn run<D: DeliveryService + 'static>(
|
||||
.to_str()
|
||||
.context("db path contains non-UTF-8 characters")?
|
||||
.to_string();
|
||||
let storage = StorageConfig::Encrypted {
|
||||
path: db_str,
|
||||
key: "chat-cli".to_string(),
|
||||
};
|
||||
|
||||
let client = logos_chat::ChatClient::open(
|
||||
cli.name.clone(),
|
||||
logos_chat::StorageConfig::Encrypted {
|
||||
path: db_str,
|
||||
key: "chat-cli".to_string(),
|
||||
},
|
||||
transport,
|
||||
)
|
||||
.map_err(|e| anyhow::anyhow!("{e:?}"))
|
||||
.context("failed to open chat client")?;
|
||||
match cli.registry_url.as_deref() {
|
||||
Some(url) => {
|
||||
let registry = HttpRegistry::new(url);
|
||||
let client =
|
||||
ChatClient::open_with_registry(cli.name.clone(), storage, transport, registry)
|
||||
.map_err(|e| anyhow::anyhow!("{e:?}"))
|
||||
.context("failed to open chat client with HTTP registry")?;
|
||||
launch_tui(client, inbound, cli)
|
||||
}
|
||||
None => {
|
||||
let client = ChatClient::open(cli.name.clone(), storage, transport)
|
||||
.map_err(|e| anyhow::anyhow!("{e:?}"))
|
||||
.context("failed to open chat client")?;
|
||||
launch_tui(client, inbound, cli)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn launch_tui<D, R>(
|
||||
client: ChatClient<D, R>,
|
||||
inbound: mpsc::Receiver<Vec<u8>>,
|
||||
cli: &Cli,
|
||||
) -> Result<()>
|
||||
where
|
||||
D: DeliveryService + 'static,
|
||||
R: RegistrationService + 'static,
|
||||
{
|
||||
let mut app = ChatApp::new(client, inbound, &cli.name, &cli.data)?;
|
||||
|
||||
if cli.smoketest {
|
||||
@@ -193,10 +219,11 @@ fn run_logos_delivery(cli: Cli) -> Result<()> {
|
||||
)
|
||||
}
|
||||
|
||||
fn run_app<D: DeliveryService + 'static>(
|
||||
terminal: &mut ui::Tui,
|
||||
app: &mut ChatApp<D>,
|
||||
) -> Result<()> {
|
||||
fn run_app<D, R>(terminal: &mut ui::Tui, app: &mut ChatApp<D, R>) -> Result<()>
|
||||
where
|
||||
D: DeliveryService + 'static,
|
||||
R: RegistrationService + 'static,
|
||||
{
|
||||
loop {
|
||||
app.process_incoming()?;
|
||||
terminal.draw(|frame| ui::draw(frame, app))?;
|
||||
|
||||
+28
-7
@@ -16,7 +16,7 @@ use ratatui::{
|
||||
widgets::{Block, Borders, List, ListItem, Paragraph, Wrap},
|
||||
};
|
||||
|
||||
use logos_chat::DeliveryService;
|
||||
use logos_chat::{DeliveryService, RegistrationService};
|
||||
|
||||
use crate::app::ChatApp;
|
||||
|
||||
@@ -38,7 +38,10 @@ pub fn restore() -> io::Result<()> {
|
||||
}
|
||||
|
||||
/// Draw the UI.
|
||||
pub fn draw<D: DeliveryService + 'static>(frame: &mut Frame, app: &ChatApp<D>) {
|
||||
pub fn draw<D: DeliveryService + 'static, R: RegistrationService + 'static>(
|
||||
frame: &mut Frame,
|
||||
app: &ChatApp<D, R>,
|
||||
) {
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
@@ -55,7 +58,11 @@ pub fn draw<D: DeliveryService + 'static>(frame: &mut Frame, app: &ChatApp<D>) {
|
||||
draw_status(frame, app, chunks[3]);
|
||||
}
|
||||
|
||||
fn draw_header<D: DeliveryService + 'static>(frame: &mut Frame, app: &ChatApp<D>, area: Rect) {
|
||||
fn draw_header<D: DeliveryService + 'static, R: RegistrationService + 'static>(
|
||||
frame: &mut Frame,
|
||||
app: &ChatApp<D, R>,
|
||||
area: Rect,
|
||||
) {
|
||||
let title = match app.current_session() {
|
||||
Some(session) => {
|
||||
let id = &session.chat_id[..8.min(session.chat_id.len())];
|
||||
@@ -78,7 +85,11 @@ fn draw_header<D: DeliveryService + 'static>(frame: &mut Frame, app: &ChatApp<D>
|
||||
frame.render_widget(header, area);
|
||||
}
|
||||
|
||||
fn draw_messages<D: DeliveryService + 'static>(frame: &mut Frame, app: &ChatApp<D>, area: Rect) {
|
||||
fn draw_messages<D: DeliveryService + 'static, R: RegistrationService + 'static>(
|
||||
frame: &mut Frame,
|
||||
app: &ChatApp<D, R>,
|
||||
area: Rect,
|
||||
) {
|
||||
let remote_name = app
|
||||
.current_session()
|
||||
.map(|s| s.display_name())
|
||||
@@ -164,7 +175,11 @@ fn draw_messages<D: DeliveryService + 'static>(frame: &mut Frame, app: &ChatApp<
|
||||
frame.render_stateful_widget(messages_widget, area, &mut list_state);
|
||||
}
|
||||
|
||||
fn draw_input<D: DeliveryService + 'static>(frame: &mut Frame, app: &ChatApp<D>, area: Rect) {
|
||||
fn draw_input<D: DeliveryService + 'static, R: RegistrationService + 'static>(
|
||||
frame: &mut Frame,
|
||||
app: &ChatApp<D, R>,
|
||||
area: Rect,
|
||||
) {
|
||||
// Inner width: area minus borders (2).
|
||||
let inner_width = area.width.saturating_sub(2) as usize;
|
||||
let input_len = app.input.len();
|
||||
@@ -191,7 +206,11 @@ fn draw_input<D: DeliveryService + 'static>(frame: &mut Frame, app: &ChatApp<D>,
|
||||
frame.set_cursor_position((cursor_x, area.y + 1));
|
||||
}
|
||||
|
||||
fn draw_status<D: DeliveryService + 'static>(frame: &mut Frame, app: &ChatApp<D>, area: Rect) {
|
||||
fn draw_status<D: DeliveryService + 'static, R: RegistrationService + 'static>(
|
||||
frame: &mut Frame,
|
||||
app: &ChatApp<D, R>,
|
||||
area: Rect,
|
||||
) {
|
||||
let status = Paragraph::new(app.status.as_str())
|
||||
.style(Style::default().fg(Color::Gray))
|
||||
.block(Block::default().title(" Status ").borders(Borders::ALL))
|
||||
@@ -201,7 +220,9 @@ fn draw_status<D: DeliveryService + 'static>(frame: &mut Frame, app: &ChatApp<D>
|
||||
}
|
||||
|
||||
/// Handle keyboard events.
|
||||
pub fn handle_events<D: DeliveryService + 'static>(app: &mut ChatApp<D>) -> io::Result<bool> {
|
||||
pub fn handle_events<D: DeliveryService + 'static, R: RegistrationService + 'static>(
|
||||
app: &mut ChatApp<D, R>,
|
||||
) -> io::Result<bool> {
|
||||
// Poll for events with a short timeout to allow checking incoming messages
|
||||
if event::poll(std::time::Duration::from_millis(100))?
|
||||
&& let Event::Key(key) = event::read()?
|
||||
|
||||
Reference in New Issue
Block a user