Skip to main content

minecraft_rpc/
lib.rs

1use std::str::FromStr;
2
3use jsonrpsee::core::client::ClientT;
4use jsonrpsee::rpc_params;
5use jsonrpsee::ws_client::{HeaderMap, HeaderValue, WsClient, WsClientBuilder};
6use serde::{Deserialize, Serialize};
7
8#[derive(Serialize, Deserialize, Debug)]
9pub struct UntypedGameRule {
10    value: String,
11    key: String,
12}
13
14#[derive(Serialize, Deserialize, Debug)]
15pub struct IncomingIPBan {
16    reason: String,
17    expires: String,
18    ip: String,
19    source: String,
20    player: Player,
21}
22
23#[derive(Serialize, Deserialize, Debug)]
24pub struct SystemMessage {
25    receiveing_players: Vec<Player>,
26    overlay: bool,
27    message: Message,
28}
29
30#[derive(Serialize, Deserialize, Debug)]
31pub struct KickPlayer {
32    player: Player,
33    message: Message,
34}
35
36#[derive(Serialize, Deserialize, Debug)]
37pub struct IPBan {
38    reason: String,
39    expires: String,
40    ip: String,
41    source: String,
42}
43
44#[derive(Serialize, Deserialize, Debug)]
45pub struct TypedGameRule {
46    r#type: String,
47    value: String,
48    key: String,
49}
50
51#[derive(Serialize, Deserialize, Debug)]
52pub struct UserBan {
53    reason: String,
54    expires: Option<String>,
55    source: Option<String>,
56    player: Player,
57}
58
59impl UserBan {
60    // was not able to understand expires and source (no doc)
61    pub fn new(player_name: &str, reason: &str) -> Self {
62        UserBan {
63            reason: reason.to_string(),
64            expires: None,
65            source: None,
66            player: player_name.parse().unwrap(),
67        }
68    }
69}
70
71#[derive(Serialize, Deserialize, Debug)]
72pub struct Message {
73    translatable: String,
74    translatable_params: Vec<String>,
75    literal: String,
76}
77
78#[derive(Serialize, Deserialize, Debug)]
79pub struct Version {
80    protocol: i64,
81    name: String,
82}
83
84#[derive(Serialize, Deserialize, Debug)]
85pub struct ServerState {
86    players: Vec<Player>,
87    started: bool,
88    version: Version,
89}
90
91#[derive(Serialize, Deserialize, Debug)]
92pub struct Operator {
93    permission_level: i64,
94    bypasses_player_limit: bool,
95    player: Player,
96}
97
98#[derive(Serialize, Deserialize, Debug)]
99pub struct Player {
100    pub name: String,
101    pub id: Option<String>,
102}
103
104impl FromStr for Player {
105    type Err = Error;
106    // Enable "player".parse(). Should never fail, unwrap is safe
107    fn from_str(s: &str) -> Result<Self, Self::Err> {
108        Ok(Player {
109            name: s.to_string(),
110            id: None,
111        })
112    }
113}
114
115#[derive(Debug)]
116pub struct Error;
117
118impl std::fmt::Display for Error {
119    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120        write!(f, "MinecraftRpcError")
121    }
122}
123
124impl std::error::Error for Error {}
125
126pub trait ClientTrait {
127    /*************
128     * ALLOWLIST *
129     *************/
130    fn allowlist_get(
131        &self,
132    ) -> impl std::future::Future<Output = anyhow::Result<Vec<Player>>> + Send;
133    fn allowlist_set(
134        &self,
135        players: &[Player],
136    ) -> impl std::future::Future<Output = anyhow::Result<Vec<Player>>> + Send;
137    fn allowlist_add(
138        &self,
139        players: &[Player],
140    ) -> impl std::future::Future<Output = anyhow::Result<Vec<Player>>> + Send;
141    fn allowlist_remove(
142        &self,
143        players: &[Player],
144    ) -> impl std::future::Future<Output = anyhow::Result<Vec<Player>>> + Send;
145    fn allowlist_clear(
146        &self,
147    ) -> impl std::future::Future<Output = anyhow::Result<Vec<Player>>> + Send;
148
149    /********
150     * BANS *
151     ********/
152    fn bans_get(&self) -> impl std::future::Future<Output = anyhow::Result<Vec<UserBan>>> + Send;
153    fn bans_set(
154        &self,
155        bans: &[UserBan],
156    ) -> impl std::future::Future<Output = anyhow::Result<Vec<UserBan>>> + Send;
157    fn bans_add(
158        &self,
159        bans: &[UserBan],
160    ) -> impl std::future::Future<Output = anyhow::Result<Vec<UserBan>>> + Send;
161    fn bans_remove(
162        &self,
163        players: &[Player],
164    ) -> impl std::future::Future<Output = anyhow::Result<Vec<UserBan>>> + Send;
165    fn bans_clear(&self) -> impl std::future::Future<Output = anyhow::Result<Vec<UserBan>>> + Send;
166}
167
168struct Client {
169    ws_client: WsClient,
170}
171
172pub async fn new_client(url: &str, secret: &str) -> anyhow::Result<impl ClientTrait> {
173    let mut headers = HeaderMap::new();
174    headers.insert(
175        "Authorization",
176        HeaderValue::from_str(&format!("Bearer {secret}"))?,
177    );
178    let client = WsClientBuilder::new()
179        .set_headers(headers)
180        .build(url)
181        .await?;
182    Ok(Client { ws_client: client })
183}
184
185impl ClientTrait for Client {
186    /*************
187     * ALLOWLIST *
188     *************/
189    async fn allowlist_get(&self) -> anyhow::Result<Vec<Player>> {
190        let players: Vec<Player> = self
191            .ws_client
192            .request("minecraft:allowlist", rpc_params![])
193            .await?;
194        Ok(players)
195    }
196    async fn allowlist_set(&self, players: &[Player]) -> anyhow::Result<Vec<Player>> {
197        let players: Vec<Player> = self
198            .ws_client
199            .request("minecraft:allowlist/set", rpc_params![players])
200            .await?;
201        Ok(players)
202    }
203    async fn allowlist_add(&self, players: &[Player]) -> anyhow::Result<Vec<Player>> {
204        let players: Vec<Player> = self
205            .ws_client
206            .request("minecraft:allowlist/add", rpc_params![players])
207            .await?;
208        Ok(players)
209    }
210    async fn allowlist_remove(&self, players: &[Player]) -> anyhow::Result<Vec<Player>> {
211        let players: Vec<Player> = self
212            .ws_client
213            .request("minecraft:allowlist/remove", rpc_params![players])
214            .await?;
215        Ok(players)
216    }
217    async fn allowlist_clear(&self) -> anyhow::Result<Vec<Player>> {
218        let players: Vec<Player> = self
219            .ws_client
220            .request("minecraft:allowlist/clear", rpc_params![])
221            .await?;
222        Ok(players)
223    }
224
225    /********
226     * BANS *
227     ********/
228    async fn bans_get(&self) -> anyhow::Result<Vec<UserBan>> {
229        let bans: Vec<UserBan> = self
230            .ws_client
231            .request("minecraft:bans", rpc_params![])
232            .await?;
233        Ok(bans)
234    }
235    async fn bans_set(&self, bans: &[UserBan]) -> anyhow::Result<Vec<UserBan>> {
236        let bans: Vec<UserBan> = self
237            .ws_client
238            .request("minecraft:bans/set", rpc_params![bans])
239            .await?;
240        Ok(bans)
241    }
242    async fn bans_add(&self, bans: &[UserBan]) -> anyhow::Result<Vec<UserBan>> {
243        let bans: Vec<UserBan> = self
244            .ws_client
245            .request("minecraft:bans/add", rpc_params![bans])
246            .await?;
247        Ok(bans)
248    }
249    async fn bans_remove(&self, players: &[Player]) -> anyhow::Result<Vec<UserBan>> {
250        let bans: Vec<UserBan> = self
251            .ws_client
252            .request("minecraft:bans/remove", rpc_params![players])
253            .await?;
254        Ok(bans)
255    }
256    async fn bans_clear(&self) -> anyhow::Result<Vec<UserBan>> {
257        let bans: Vec<UserBan> = self
258            .ws_client
259            .request("minecraft:bans/clear", rpc_params![])
260            .await?;
261        Ok(bans)
262    }
263}