use async_std::net::TcpStream; use kuska_handshake::async_std::BoxStream; use kuska_sodiumoxide::crypto::{auth, sign::ed25519}; use kuska_ssb::{ api::{ dto::{content::Post, CreateHistoryStreamIn}, ApiCaller, }, discovery, keystore, keystore::OwnedIdentity, rpc::{RpcReader, RpcWriter}, }; use crate::error::GolgiError; use crate::utils; pub struct Sbot { id: String, public_key: ed25519::PublicKey, private_key: ed25519::SecretKey, address: String, // aka caps key (scuttleverse identifier) network_id: auth::Key, client: ApiCaller, rpc_reader: RpcReader, } impl Sbot { pub async fn init(ip_port: Option, net_id: Option) -> Result { let address; if ip_port.is_none() { address = "127.0.0.1:8008".to_string(); } else { address = ip_port.unwrap(); } let network_id; if net_id.is_none() { network_id = discovery::ssb_net_id(); } else { network_id = auth::Key::from_slice(&hex::decode(net_id.unwrap()).unwrap()).unwrap(); } let OwnedIdentity { pk, sk, id } = keystore::from_gosbot_local() .await .expect("couldn't read local secret"); let socket = TcpStream::connect(&address) .await .map_err(|source| GolgiError::Io { source, context: "socket error; failed to initiate tcp stream connection".to_string(), })?; let handshake = kuska_handshake::async_std::handshake_client( &mut &socket, network_id.clone(), pk, sk.clone(), pk, ) .await .map_err(GolgiError::Handshake)?; let (box_stream_read, box_stream_write) = BoxStream::from_handshake(socket.clone(), socket, handshake, 0x8000).split_read_write(); let rpc_reader = RpcReader::new(box_stream_read); let client = ApiCaller::new(RpcWriter::new(box_stream_write)); Ok(Self { id, public_key: pk, private_key: sk, address, network_id, client, rpc_reader, }) } pub async fn whoami(&mut self) -> Result { let req_id = self.client.whoami_req_send().await?; utils::get_async(&mut self.rpc_reader, req_id, utils::whoami_res_parse) .await .map(|whoami| whoami.id) } pub async fn publish_post(&mut self, post: Post) -> Result { let req_id = self.client.publish_req_send(post).await?; utils::get_async(&mut self.rpc_reader, req_id, utils::publish_res_parse).await } async fn create_history_stream(&mut self, id: String) -> Result<(), GolgiError> { let args = CreateHistoryStreamIn::new(id); let req_id = self.client.create_history_stream_req_send(&args).await?; utils::print_source_until_eof(&mut self.rpc_reader, req_id, utils::feed_res_parse).await } }