use futures_util::stream::BoxStream;
use reqwest::Method;
use crate::api::gameplay::board::{
ChatForm, LichessBoardEvent, LichessChatRoom, LichessIncomingEvent, yes_no,
};
use crate::api::gameplay::games::LichessGameChatMessage;
use crate::client::LichessClient;
use crate::config::Host;
use crate::error::Result;
use crate::http;
use crate::model::LichessUser;
#[derive(Debug)]
pub struct BotApi<'a> {
client: &'a LichessClient,
}
impl<'a> BotApi<'a> {
pub(crate) fn new(client: &'a LichessClient) -> Self {
Self { client }
}
pub async fn upgrade_to_bot(&self) -> Result<()> {
let request = self
.client
.request(Method::POST, Host::Default, "/api/bot/account/upgrade");
http::ok(request).await
}
pub async fn online(&self, nb: Option<u32>) -> Result<BoxStream<'static, Result<LichessUser>>> {
let request = self
.client
.request(Method::GET, Host::Default, "/api/bot/online")
.query(&[("nb", nb)]);
http::stream(request, self.client.max_line_bytes()).await
}
pub async fn stream_game(
&self,
game_id: &str,
) -> Result<BoxStream<'static, Result<LichessBoardEvent>>> {
let path = format!("/api/bot/game/stream/{}", http::segment(game_id));
let request = self.client.request(Method::GET, Host::Default, &path);
http::stream(request, self.client.max_line_bytes()).await
}
pub async fn make_move(
&self,
game_id: &str,
chess_move: &str,
offering_draw: bool,
) -> Result<()> {
let path = format!(
"/api/bot/game/{}/move/{}",
http::segment(game_id),
http::segment(chess_move)
);
let request = self
.client
.request(Method::POST, Host::Default, &path)
.query(&[("offeringDraw", offering_draw)]);
http::ok(request).await
}
pub async fn abort(&self, game_id: &str) -> Result<()> {
self.post_action(game_id, "abort").await
}
pub async fn resign(&self, game_id: &str) -> Result<()> {
self.post_action(game_id, "resign").await
}
pub async fn claim_victory(&self, game_id: &str) -> Result<()> {
self.post_action(game_id, "claim-victory").await
}
pub async fn claim_draw(&self, game_id: &str) -> Result<()> {
self.post_action(game_id, "claim-draw").await
}
pub async fn handle_draw(&self, game_id: &str, accept: bool) -> Result<()> {
let path = format!(
"/api/bot/game/{}/draw/{}",
http::segment(game_id),
yes_no(accept)
);
http::ok(self.client.request(Method::POST, Host::Default, &path)).await
}
pub async fn handle_takeback(&self, game_id: &str, accept: bool) -> Result<()> {
let path = format!(
"/api/bot/game/{}/takeback/{}",
http::segment(game_id),
yes_no(accept)
);
http::ok(self.client.request(Method::POST, Host::Default, &path)).await
}
pub async fn write_chat(&self, game_id: &str, room: LichessChatRoom, text: &str) -> Result<()> {
let path = format!("/api/bot/game/{}/chat", http::segment(game_id));
let request = self
.client
.request(Method::POST, Host::Default, &path)
.form(&ChatForm { room, text });
http::ok(request).await
}
pub async fn stream_events(&self) -> Result<BoxStream<'static, Result<LichessIncomingEvent>>> {
let request = self
.client
.request(Method::GET, Host::Default, "/api/stream/event");
http::stream(request, self.client.max_line_bytes()).await
}
pub async fn read_chat(&self, game_id: &str) -> Result<Vec<LichessGameChatMessage>> {
let path = format!("/api/bot/game/{}/chat", http::segment(game_id));
let request = self.client.request(Method::GET, Host::Default, &path);
http::json(request, "Vec<LichessGameChatMessage>").await
}
async fn post_action(&self, game_id: &str, action: &str) -> Result<()> {
let path = format!(
"/api/bot/game/{}/{}",
http::segment(game_id),
http::segment(action)
);
http::ok(self.client.request(Method::POST, Host::Default, &path)).await
}
}
impl LichessClient {
#[must_use]
pub fn bot(&self) -> BotApi<'_> {
BotApi::new(self)
}
}