mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-07-22 15:59:36 +00:00
Update Cli-Client to use builder
This commit is contained in:
parent
e1f13d94be
commit
180c9012b1
@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use arboard::Clipboard;
|
use arboard::Clipboard;
|
||||||
use crossbeam_channel::Receiver;
|
use crossbeam_channel::Receiver;
|
||||||
use logos_chat::{ChatClient, EphemeralRegistry, Event, RegistrationService, Transport};
|
use logos_chat::{ChatClient, ChatStore, Event, IdentityProvider, RegistrationService, Transport};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::utils::now;
|
use crate::utils::now;
|
||||||
@ -41,8 +41,14 @@ pub struct AppState {
|
|||||||
pub active_chat: Option<String>,
|
pub active_chat: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ChatApp<T: Transport, R: RegistrationService = EphemeralRegistry> {
|
pub struct ChatApp<I, T, R, S>
|
||||||
pub client: ChatClient<T, R>,
|
where
|
||||||
|
I: IdentityProvider + Send + 'static,
|
||||||
|
T: Transport,
|
||||||
|
R: RegistrationService + Send + 'static,
|
||||||
|
S: ChatStore + Send + 'static,
|
||||||
|
{
|
||||||
|
pub client: ChatClient<I, T, R, S>,
|
||||||
events: Receiver<Event>,
|
events: Receiver<Event>,
|
||||||
pub state: AppState,
|
pub state: AppState,
|
||||||
/// Ephemeral command output — not persisted, cleared on chat switch.
|
/// Ephemeral command output — not persisted, cleared on chat switch.
|
||||||
@ -53,13 +59,15 @@ pub struct ChatApp<T: Transport, R: RegistrationService = EphemeralRegistry> {
|
|||||||
state_path: PathBuf,
|
state_path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, R> ChatApp<T, R>
|
impl<I, T, R, S> ChatApp<I, T, R, S>
|
||||||
where
|
where
|
||||||
|
I: IdentityProvider + Send,
|
||||||
T: Transport,
|
T: Transport,
|
||||||
R: RegistrationService + Send + 'static,
|
R: RegistrationService + Send + 'static,
|
||||||
|
S: ChatStore + Send,
|
||||||
{
|
{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
client: ChatClient<T, R>,
|
client: ChatClient<I, T, R, S>,
|
||||||
events: Receiver<Event>,
|
events: Receiver<Event>,
|
||||||
user_name: &str,
|
user_name: &str,
|
||||||
data_dir: &Path,
|
data_dir: &Path,
|
||||||
|
|||||||
@ -8,7 +8,10 @@ use std::path::{Path, PathBuf};
|
|||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use clap::{Parser, ValueEnum};
|
use clap::{Parser, ValueEnum};
|
||||||
use crossbeam_channel::Receiver;
|
use crossbeam_channel::Receiver;
|
||||||
use logos_chat::{ChatClient, Event, HttpRegistry, RegistrationService, StorageConfig, Transport};
|
use logos_chat::{
|
||||||
|
ChatClient, ChatClientBuilder, ChatStore, Event, HttpRegistry, IdentityProvider,
|
||||||
|
RegistrationService, StorageConfig, Transport,
|
||||||
|
};
|
||||||
|
|
||||||
use app::ChatApp;
|
use app::ChatApp;
|
||||||
|
|
||||||
@ -113,14 +116,20 @@ fn run<T: Transport>(transport: T, cli: &Cli) -> Result<()> {
|
|||||||
match cli.registry_url.as_deref() {
|
match cli.registry_url.as_deref() {
|
||||||
Some(url) => {
|
Some(url) => {
|
||||||
let registry = HttpRegistry::new(url);
|
let registry = HttpRegistry::new(url);
|
||||||
let (client, events) =
|
let (client, events) = ChatClientBuilder::new()
|
||||||
ChatClient::open_with_registry(cli.name.clone(), storage, transport, registry)
|
.transport(transport)
|
||||||
.map_err(|e| anyhow::anyhow!("{e:?}"))
|
// .storage(storage) // Groups Do not support persistence at this time.
|
||||||
.context("failed to open chat client with HTTP registry")?;
|
.registration(registry)
|
||||||
|
.build()
|
||||||
|
.map_err(|e| anyhow::anyhow!("{e:?}"))
|
||||||
|
.context("failed to open chat client with HTTP registry")?;
|
||||||
launch_tui(client, events, cli)
|
launch_tui(client, events, cli)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let (client, events) = ChatClient::open(cli.name.clone(), storage, transport)
|
let (client, events) = ChatClientBuilder::new()
|
||||||
|
.transport(transport)
|
||||||
|
// .storage(storage) // Groups Do not support persistence at this time.
|
||||||
|
.build()
|
||||||
.map_err(|e| anyhow::anyhow!("{e:?}"))
|
.map_err(|e| anyhow::anyhow!("{e:?}"))
|
||||||
.context("failed to open chat client")?;
|
.context("failed to open chat client")?;
|
||||||
launch_tui(client, events, cli)
|
launch_tui(client, events, cli)
|
||||||
@ -128,10 +137,16 @@ fn run<T: Transport>(transport: T, cli: &Cli) -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn launch_tui<T, R>(client: ChatClient<T, R>, events: Receiver<Event>, cli: &Cli) -> Result<()>
|
fn launch_tui<I, T, R, S>(
|
||||||
|
client: ChatClient<I, T, R, S>,
|
||||||
|
events: Receiver<Event>,
|
||||||
|
cli: &Cli,
|
||||||
|
) -> Result<()>
|
||||||
where
|
where
|
||||||
|
I: IdentityProvider + Send,
|
||||||
T: Transport,
|
T: Transport,
|
||||||
R: RegistrationService + Send + 'static,
|
R: RegistrationService + Send + 'static,
|
||||||
|
S: ChatStore + Send,
|
||||||
{
|
{
|
||||||
let mut app = ChatApp::new(client, events, &cli.name, &cli.data)?;
|
let mut app = ChatApp::new(client, events, &cli.name, &cli.data)?;
|
||||||
|
|
||||||
@ -209,10 +224,12 @@ fn run_logos_delivery(cli: Cli) -> Result<()> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_app<T, R>(terminal: &mut ui::Tui, app: &mut ChatApp<T, R>) -> Result<()>
|
fn run_app<I, T, R, S>(terminal: &mut ui::Tui, app: &mut ChatApp<I, T, R, S>) -> Result<()>
|
||||||
where
|
where
|
||||||
|
I: IdentityProvider + Send,
|
||||||
T: Transport,
|
T: Transport,
|
||||||
R: RegistrationService + Send + 'static,
|
R: RegistrationService + Send + 'static,
|
||||||
|
S: ChatStore + Send,
|
||||||
{
|
{
|
||||||
loop {
|
loop {
|
||||||
app.process_incoming()?;
|
app.process_incoming()?;
|
||||||
|
|||||||
@ -16,7 +16,7 @@ use ratatui::{
|
|||||||
widgets::{Block, Borders, List, ListItem, Paragraph, Wrap},
|
widgets::{Block, Borders, List, ListItem, Paragraph, Wrap},
|
||||||
};
|
};
|
||||||
|
|
||||||
use logos_chat::{RegistrationService, Transport};
|
use logos_chat::{ChatStore, IdentityProvider, RegistrationService, Transport};
|
||||||
|
|
||||||
use crate::app::ChatApp;
|
use crate::app::ChatApp;
|
||||||
|
|
||||||
@ -38,10 +38,13 @@ pub fn restore() -> io::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the UI.
|
/// Draw the UI.
|
||||||
pub fn draw<D: Transport, R: RegistrationService + Send + 'static>(
|
pub fn draw<I, D, R, S>(frame: &mut Frame, app: &ChatApp<I, D, R, S>)
|
||||||
frame: &mut Frame,
|
where
|
||||||
app: &ChatApp<D, R>,
|
I: IdentityProvider + Send + 'static,
|
||||||
) {
|
D: Transport + Send + 'static,
|
||||||
|
R: RegistrationService + Send + 'static,
|
||||||
|
S: ChatStore + Send + 'static,
|
||||||
|
{
|
||||||
let chunks = Layout::default()
|
let chunks = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints([
|
.constraints([
|
||||||
@ -58,11 +61,13 @@ pub fn draw<D: Transport, R: RegistrationService + Send + 'static>(
|
|||||||
draw_status(frame, app, chunks[3]);
|
draw_status(frame, app, chunks[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_header<D: Transport, R: RegistrationService + Send + 'static>(
|
fn draw_header<I, D, R, S>(frame: &mut Frame, app: &ChatApp<I, D, R, S>, area: Rect)
|
||||||
frame: &mut Frame,
|
where
|
||||||
app: &ChatApp<D, R>,
|
I: IdentityProvider + Send + 'static,
|
||||||
area: Rect,
|
D: Transport + Send + 'static,
|
||||||
) {
|
R: RegistrationService + Send + 'static,
|
||||||
|
S: ChatStore + Send + 'static,
|
||||||
|
{
|
||||||
let title = match app.current_session() {
|
let title = match app.current_session() {
|
||||||
Some(session) => {
|
Some(session) => {
|
||||||
let id = &session.chat_id[..8.min(session.chat_id.len())];
|
let id = &session.chat_id[..8.min(session.chat_id.len())];
|
||||||
@ -85,11 +90,13 @@ fn draw_header<D: Transport, R: RegistrationService + Send + 'static>(
|
|||||||
frame.render_widget(header, area);
|
frame.render_widget(header, area);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_messages<D: Transport, R: RegistrationService + Send + 'static>(
|
fn draw_messages<I, D, R, S>(frame: &mut Frame, app: &ChatApp<I, D, R, S>, area: Rect)
|
||||||
frame: &mut Frame,
|
where
|
||||||
app: &ChatApp<D, R>,
|
I: IdentityProvider + Send + 'static,
|
||||||
area: Rect,
|
D: Transport + Send + 'static,
|
||||||
) {
|
R: RegistrationService + Send + 'static,
|
||||||
|
S: ChatStore + Send + 'static,
|
||||||
|
{
|
||||||
let remote_name = app
|
let remote_name = app
|
||||||
.current_session()
|
.current_session()
|
||||||
.map(|s| s.display_name())
|
.map(|s| s.display_name())
|
||||||
@ -175,11 +182,13 @@ fn draw_messages<D: Transport, R: RegistrationService + Send + 'static>(
|
|||||||
frame.render_stateful_widget(messages_widget, area, &mut list_state);
|
frame.render_stateful_widget(messages_widget, area, &mut list_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_input<D: Transport, R: RegistrationService + Send + 'static>(
|
fn draw_input<I, D, R, S>(frame: &mut Frame, app: &ChatApp<I, D, R, S>, area: Rect)
|
||||||
frame: &mut Frame,
|
where
|
||||||
app: &ChatApp<D, R>,
|
I: IdentityProvider + Send + 'static,
|
||||||
area: Rect,
|
D: Transport + Send + 'static,
|
||||||
) {
|
R: RegistrationService + Send + 'static,
|
||||||
|
S: ChatStore + Send + 'static,
|
||||||
|
{
|
||||||
// Inner width: area minus borders (2).
|
// Inner width: area minus borders (2).
|
||||||
let inner_width = area.width.saturating_sub(2) as usize;
|
let inner_width = area.width.saturating_sub(2) as usize;
|
||||||
let input_len = app.input.len();
|
let input_len = app.input.len();
|
||||||
@ -206,11 +215,13 @@ fn draw_input<D: Transport, R: RegistrationService + Send + 'static>(
|
|||||||
frame.set_cursor_position((cursor_x, area.y + 1));
|
frame.set_cursor_position((cursor_x, area.y + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_status<D: Transport, R: RegistrationService + Send + 'static>(
|
fn draw_status<I, D, R, S>(frame: &mut Frame, app: &ChatApp<I, D, R, S>, area: Rect)
|
||||||
frame: &mut Frame,
|
where
|
||||||
app: &ChatApp<D, R>,
|
I: IdentityProvider + Send + 'static,
|
||||||
area: Rect,
|
D: Transport + Send + 'static,
|
||||||
) {
|
R: RegistrationService + Send + 'static,
|
||||||
|
S: ChatStore + Send + 'static,
|
||||||
|
{
|
||||||
let status = Paragraph::new(app.status.as_str())
|
let status = Paragraph::new(app.status.as_str())
|
||||||
.style(Style::default().fg(Color::Gray))
|
.style(Style::default().fg(Color::Gray))
|
||||||
.block(Block::default().title(" Status ").borders(Borders::ALL))
|
.block(Block::default().title(" Status ").borders(Borders::ALL))
|
||||||
@ -220,9 +231,13 @@ fn draw_status<D: Transport, R: RegistrationService + Send + 'static>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Handle keyboard events.
|
/// Handle keyboard events.
|
||||||
pub fn handle_events<D: Transport, R: RegistrationService + Send + 'static>(
|
pub fn handle_events<I, D, R, S>(app: &mut ChatApp<I, D, R, S>) -> io::Result<bool>
|
||||||
app: &mut ChatApp<D, R>,
|
where
|
||||||
) -> io::Result<bool> {
|
I: IdentityProvider + Send + 'static,
|
||||||
|
D: Transport + Send + 'static,
|
||||||
|
R: RegistrationService + Send + 'static,
|
||||||
|
S: ChatStore + Send + 'static,
|
||||||
|
{
|
||||||
// Poll for events with a short timeout to allow checking incoming messages
|
// Poll for events with a short timeout to allow checking incoming messages
|
||||||
if event::poll(std::time::Duration::from_millis(100))?
|
if event::poll(std::time::Duration::from_millis(100))?
|
||||||
&& let Event::Key(key) = event::read()?
|
&& let Event::Key(key) = event::read()?
|
||||||
|
|||||||
@ -29,6 +29,6 @@ pub use outcomes::{
|
|||||||
pub use service_context::ExternalServices;
|
pub use service_context::ExternalServices;
|
||||||
pub use service_traits::{DeliveryService, RegistrationService, WakeupService};
|
pub use service_traits::{DeliveryService, RegistrationService, WakeupService};
|
||||||
pub use shared_traits::{IdentId, IdentIdRef, IdentityProvider};
|
pub use shared_traits::{IdentId, IdentIdRef, IdentityProvider};
|
||||||
pub use storage::ConversationKind;
|
pub use storage::{ChatStore, ConversationKind};
|
||||||
pub use types::AddressedEnvelope;
|
pub use types::AddressedEnvelope;
|
||||||
pub use utils::{hex_trunc, trunc};
|
pub use utils::{hex_trunc, trunc};
|
||||||
|
|||||||
@ -14,8 +14,8 @@ pub use event::Event;
|
|||||||
|
|
||||||
// Re-export types callers need to interact with ChatClient.
|
// Re-export types callers need to interact with ChatClient.
|
||||||
pub use libchat::{
|
pub use libchat::{
|
||||||
AddressedEnvelope, ConversationClass, ConversationId, DeliveryService, RegistrationService,
|
AddressedEnvelope, ChatStore, ConversationClass, ConversationId, DeliveryService,
|
||||||
StorageConfig,
|
IdentityProvider, RegistrationService, StorageConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Re-export bundled registry implementations so callers can pick one without
|
// Re-export bundled registry implementations so callers can pick one without
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user