added more boilerplate for using login, but the misskey login thing doesnt work so bleh

This commit is contained in:
emilis 2023-01-27 17:37:19 +00:00
parent e2776996ef
commit eef6c40dc1
6 changed files with 106 additions and 31 deletions

13
Cargo.lock generated
View File

@ -57,6 +57,17 @@ dependencies = [
"event-listener", "event-listener",
] ]
[[package]]
name = "async-trait"
version = "0.1.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eff18d764974428cf3a9328e23fc5c986f5fbed46e6cd4cdf42544df5d297ec1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "async-tungstenite" name = "async-tungstenite"
version = "0.18.0" version = "0.18.0"
@ -609,6 +620,7 @@ name = "kkdisp"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait",
"serde", "serde",
"termion", "termion",
] ]
@ -618,6 +630,7 @@ name = "kkx"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait",
"futures", "futures",
"kkdisp", "kkdisp",
"misskey", "misskey",

View File

@ -7,6 +7,7 @@ edition = "2021"
[dependencies] [dependencies]
anyhow = "1.0.68" anyhow = "1.0.68"
async-trait = "0.1.63"
# termion = "2.0.1" # termion = "2.0.1"
[dependencies.serde] [dependencies.serde]
@ -14,4 +15,4 @@ version = "1"
features = ["std", "derive"] features = ["std", "derive"]
[dependencies.termion] [dependencies.termion]
git = "https://sectorinf.com/emilis/termion" git = "https://sectorinf.com/emilis/termion"

View File

@ -227,7 +227,7 @@ where
); );
let mut events_iter = termion::async_stdin().events(); let mut events_iter = termion::async_stdin().events();
let mut plans = let mut plans =
PlanState::from_plans(view.init()?, base_colorset)?; PlanState::from_plans(view.init().await?, base_colorset)?;
plans.render(&mut screen)?; plans.render(&mut screen)?;
// FIXME: current loop means that pasting a string with len >1 // FIXME: current loop means that pasting a string with len >1
// results in only the first character being rendered, until // results in only the first character being rendered, until
@ -235,7 +235,7 @@ where
loop { loop {
if let Some(msg) = view.query() { if let Some(msg) = view.query() {
plans = plans.act_on( plans = plans.act_on(
view.update(Event::Message(msg))?, view.update(Event::Message(msg)).await?,
&mut screen, &mut screen,
)?; )?;
continue; continue;
@ -304,7 +304,8 @@ where
// } // }
if let Some(event) = event { if let Some(event) = event {
plans = plans.act_on(view.update(event)?, &mut screen)?; plans = plans
.act_on(view.update(event).await?, &mut screen)?;
} }
} }
Ok(()) Ok(())
@ -368,10 +369,11 @@ pub enum Action {
Nothing, Nothing,
} }
#[async_trait::async_trait]
pub trait View { pub trait View {
type Message; type Message;
fn init( async fn init(
&mut self, &mut self,
) -> std::result::Result<PlanLayers, anyhow::Error>; ) -> std::result::Result<PlanLayers, anyhow::Error>;
@ -380,7 +382,7 @@ pub trait View {
// from some sort of queue, or None if there's an empty queue. // from some sort of queue, or None if there's an empty queue.
fn query(&mut self) -> Option<Self::Message>; fn query(&mut self) -> Option<Self::Message>;
fn update( async fn update(
&mut self, &mut self,
event: Event<Self::Message>, event: Event<Self::Message>,
) -> std::result::Result<Action, anyhow::Error>; ) -> std::result::Result<Action, anyhow::Error>;

View File

@ -9,6 +9,7 @@ edition = "2021"
anyhow = "1.0.68" anyhow = "1.0.68"
kkdisp = { version = "0.1.0", path = "../kkdisp" } kkdisp = { version = "0.1.0", path = "../kkdisp" }
futures = "0.3.25" futures = "0.3.25"
async-trait = "0.1.63"
[dependencies.tokio] [dependencies.tokio]
version = "1.24.2" version = "1.24.2"

View File

@ -6,10 +6,12 @@ use kkdisp::{
view::{Event, Key}, view::{Event, Key},
Action, Action,
}; };
use misskey::{StreamingClientExt, WebSocketClient}; use misskey::{
use tokio::sync::mpsc::{self, Receiver, Sender}; websocket::WebSocketClientBuilder, ClientExt, StreamingClientExt,
WebSocketClient,
};
use crate::Message; use crate::{AuthDetail, Message};
pub enum LoginFocus { pub enum LoginFocus {
Hostname, Hostname,
Token, Token,
@ -30,7 +32,7 @@ pub struct LoginPrompt {
token: String, token: String,
error: Option<String>, error: Option<String>,
focus: LoginFocus, focus: LoginFocus,
client: Option<WebSocketClient>, client: Option<AuthDetail>,
} }
impl LoginPrompt { impl LoginPrompt {
@ -62,12 +64,13 @@ impl LoginPrompt {
LoginFocus::OK => {} LoginFocus::OK => {}
} }
} }
pub fn query(&mut self) -> Option<()> { pub fn query(&mut self) -> Option<AuthDetail> {
todo!() self.client.take()
} }
pub fn attempt(&mut self) { pub async fn attempt(&mut self) {
let hostname = self.hostname.clone(); let hostname =
self.hostname.trim_end_matches('/').to_string();
if hostname.len() == 0 { if hostname.len() == 0 {
self.error = Some("empty hostname".into()); self.error = Some("empty hostname".into());
self.focus = LoginFocus::Hostname; self.focus = LoginFocus::Hostname;
@ -79,17 +82,42 @@ impl LoginPrompt {
self.focus = LoginFocus::Token; self.focus = LoginFocus::Token;
return; return;
} }
todo!(); let auth = AuthDetail { hostname, token };
match auth.normal().await {
Ok(client) => {
match client.recommended_users().try_next().await {
Ok(next) => {
eprintln!("next: {:#?}", next);
self.client = Some(auth);
}
Err(err) => {
self.error = Some(err.to_string());
}
};
}
Err(err) => {
self.error = Some(err.to_string());
}
};
} }
pub fn update( fn down(&mut self) {
self.focus = match self.focus {
LoginFocus::Hostname => LoginFocus::Token,
LoginFocus::Token => LoginFocus::OK,
LoginFocus::OK => LoginFocus::Hostname,
};
}
pub async fn update(
&mut self, &mut self,
event: Event<Message>, event: Event<Message>,
) -> Result<Action, anyhow::Error> { ) -> Result<Action, anyhow::Error> {
match event { match event {
Event::Link(lnk) => { Event::Link(lnk) => {
if lnk == "ok" { if lnk == "ok" {
self.attempt(); self.attempt().await;
Ok(Action::ReplaceAll(vec![self.plan()])) Ok(Action::ReplaceAll(vec![self.plan()]))
} else if lnk == "token" { } else if lnk == "token" {
self.focus = LoginFocus::Token; self.focus = LoginFocus::Token;
@ -110,9 +138,10 @@ impl LoginPrompt {
LoginFocus::Token => { LoginFocus::Token => {
self.focus = LoginFocus::OK; self.focus = LoginFocus::OK;
} }
LoginFocus::OK => self.attempt(), LoginFocus::OK => self.attempt().await,
}, },
Key::Backspace => self.backspace(), Key::Backspace => self.backspace(),
Key::Tab => self.down(),
Key::Up => { Key::Up => {
self.focus = match self.focus { self.focus = match self.focus {
LoginFocus::Hostname => LoginFocus::OK, LoginFocus::Hostname => LoginFocus::OK,
@ -120,13 +149,7 @@ impl LoginPrompt {
LoginFocus::OK => LoginFocus::Token, LoginFocus::OK => LoginFocus::Token,
}; };
} }
Key::Down => { Key::Down => self.down(),
self.focus = match self.focus {
LoginFocus::Hostname => LoginFocus::Token,
LoginFocus::Token => LoginFocus::OK,
LoginFocus::OK => LoginFocus::Hostname,
};
}
Key::Char(c) => match self.focus { Key::Char(c) => match self.focus {
LoginFocus::Hostname => self.hostname.push(c), LoginFocus::Hostname => self.hostname.push(c),
LoginFocus::Token => self.token.push(c), LoginFocus::Token => self.token.push(c),

View File

@ -8,6 +8,9 @@ use kkdisp::{
Action, PlanLayers, View, Action, PlanLayers, View,
}; };
use login::LoginPrompt; use login::LoginPrompt;
use misskey::{
websocket::WebSocketClientBuilder, HttpClient, WebSocketClient,
};
use tokio::sync::mpsc::{self, Receiver, Sender}; use tokio::sync::mpsc::{self, Receiver, Sender};
mod login; mod login;
@ -17,6 +20,30 @@ async fn main() {
std::process::exit(0); std::process::exit(0);
} }
#[derive(Clone, Debug)]
pub struct AuthDetail {
pub hostname: String,
pub token: String,
}
impl AuthDetail {
pub async fn streaming(
&self,
) -> Result<WebSocketClient, anyhow::Error> {
Ok(WebSocketClientBuilder::with_host(&self.hostname)
.token(&self.token)
.connect()
.await?)
}
pub async fn normal(&self) -> Result<HttpClient, anyhow::Error> {
Ok(HttpClient::builder(
format!("https://{}", &self.hostname).as_str(),
)
.token(&self.token)
.build()?)
}
}
pub enum Page { pub enum Page {
Login(LoginPrompt), Login(LoginPrompt),
} }
@ -31,6 +58,7 @@ impl Page {
pub struct AppView { pub struct AppView {
recv: Receiver<Message>, recv: Receiver<Message>,
auth: Option<AuthDetail>,
page: Page, page: Page,
} }
@ -46,35 +74,42 @@ impl Default for AppView {
Self { Self {
recv, recv,
page: Page::Login(LoginPrompt::new()), page: Page::Login(LoginPrompt::new()),
auth: None,
} }
} }
} }
pub enum Message {} pub enum Message {}
#[async_trait::async_trait]
impl View for AppView { impl View for AppView {
type Message = Message; type Message = Message;
fn init( async fn init(
&mut self, &mut self,
) -> std::result::Result<kkdisp::PlanLayers, anyhow::Error> { ) -> std::result::Result<kkdisp::PlanLayers, anyhow::Error> {
self.page.init() self.page.init()
} }
fn update( async fn update(
&mut self, &mut self,
event: Event<Self::Message>, event: Event<Self::Message>,
) -> std::result::Result<Action, anyhow::Error> { ) -> std::result::Result<Action, anyhow::Error> {
let page = &mut self.page; let page = &mut self.page;
match page { match page {
Page::Login(login) => login.update(event), Page::Login(login) => login.update(event).await,
} }
} }
fn query(&mut self) -> Option<Self::Message> { fn query(&mut self) -> Option<Self::Message> {
match self.recv.try_recv() { match &mut self.page {
Ok(msg) => Some(msg), Page::Login(log) => match log.query() {
Err(_) => None, Some(auth) => {
self.auth = Some(auth);
None
}
None => None,
},
} }
} }
} }