nio_client/
lib.rs

1#![allow(unused_variables)]
2#![allow(unused_imports)]
3use std::fmt::{Display, Formatter};
4use std::str::FromStr;
5
6use crate::auth::{CallError, CheckResult};
7use crate::error::ReadError;
8use crate::pb::tuple_set::ObjectSpec;
9use crate::pb::TupleSet;
10use chrono::{DateTime, Utc};
11pub use error::ConnectError;
12use error::{AddError, ParseError};
13use http::Uri;
14use tonic::transport::Channel;
15
16pub mod auth;
17#[cfg(feature = "axum")]
18pub mod axum;
19mod error;
20
21#[derive(Clone, Debug)]
22pub struct Namespace(pub String);
23
24#[derive(Clone, Debug)]
25pub struct Permission(pub &'static str);
26
27#[derive(Clone, Debug)]
28pub struct Rel(pub String);
29
30impl From<Permission> for Rel {
31    fn from(value: Permission) -> Self {
32        Rel(value.0.to_string())
33    }
34}
35
36#[derive(Clone, Debug)]
37pub struct UserId(pub String);
38
39#[derive(Clone, Debug)]
40pub struct Timestamp(pub String);
41
42impl Timestamp {
43    pub fn empty() -> Self {
44        Timestamp("1:0000000000000".into())
45    }
46}
47
48impl FromStr for UserId {
49    type Err = ParseError;
50
51    fn from_str(s: &str) -> Result<Self, Self::Err> {
52        Ok(UserId(s.into()))
53    }
54}
55
56impl TryFrom<String> for UserId {
57    type Error = ParseError;
58    fn try_from(value: String) -> Result<Self, Self::Error> {
59        UserId::from_str(&value)
60    }
61}
62
63#[derive(Clone, Debug)]
64pub struct Obj(pub String);
65
66impl FromStr for Obj {
67    type Err = ParseError;
68
69    fn from_str(s: &str) -> Result<Self, Self::Err> {
70        Ok(Obj(s.into()))
71    }
72}
73
74impl TryFrom<String> for Obj {
75    type Error = ParseError;
76    fn try_from(value: String) -> Result<Self, Self::Error> {
77        Obj::from_str(&value)
78    }
79}
80
81#[derive(Clone, Debug)]
82pub struct Tuple {
83    pub ns: Namespace,
84    pub obj: Obj,
85    pub rel: Rel,
86    pub sbj: User,
87}
88
89impl Display for Tuple {
90    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
91        match self {
92            Tuple {
93                ref ns,
94                ref obj,
95                ref rel,
96                sbj: User::UserId(ref s),
97            } => write!(f, "Tuple({}:{}#{}@{})", ns.0, obj.0, rel.0, s),
98            Tuple {
99                ref ns,
100                ref obj,
101                ref rel,
102                sbj:
103                    User::UserSet {
104                        ns: ref ns2,
105                        obj: ref obj2,
106                        rel: ref rel2,
107                    },
108            } => write!(
109                f,
110                "Tuple({}:{}#{}@{}:{}#{})",
111                ns.0, obj.0, rel.0, ns2.0, obj2.0, rel2.0
112            ),
113        }
114    }
115}
116
117#[derive(Clone, Debug)]
118pub enum Condition {
119    Expires(DateTime<Utc>),
120}
121
122#[derive(Clone, Debug)]
123pub enum User {
124    UserId(String),
125    UserSet { ns: Namespace, obj: Obj, rel: Rel },
126}
127
128mod pb {
129    tonic::include_proto!("am");
130}
131
132#[derive(Clone, Debug)]
133pub struct CheckClient {
134    pub(crate) client: pb::check_service_client::CheckServiceClient<Channel>,
135}
136
137impl CheckClient {
138    // <<<<<<< HEAD
139    //     // pub async fn get_all(&mut self, ns: &Namespace, obj: &Obj) -> Result<String, AddError> {
140    //     //     let response = self
141    //     //         .client
142    //     //         .read(pb::ReadRequest {
143    //     //             tuple_sets: vec![TupleSet {
144    //     //                 ns: "".to_string(),
145    //     //                 spec: Some(ObjectSpec(ObjectSpec {})),
146    //     //             }],
147    //     //             ts: None,
148    //     //         })
149    //     //         .await
150    //     //         .map(|r| r.into_inner().ts)
151    //     //         .map_err(Into::into)?;
152    //     // }
153    // =======
154    pub async fn get_all(&mut self, ns: &Namespace, obj: &Obj) -> Result<Vec<Tuple>, ReadError> {
155        let response = self
156            .client
157            .read(pb::ReadRequest {
158                tuple_sets: vec![TupleSet {
159                    ns: ns.0.clone(),
160                    spec: Some(pb::tuple_set::Spec::ObjectSpec(ObjectSpec {
161                        obj: obj.0.clone(),
162                        rel: None,
163                    })),
164                }],
165                ts: None,
166            })
167            .await?;
168        let response = response.into_inner();
169        Ok(response
170            .tuples
171            .into_iter()
172            .map(|tup| Tuple {
173                ns: Namespace(tup.ns),
174                obj: Obj(tup.obj),
175                rel: Rel(tup.rel),
176                sbj: match tup.user {
177                    None => todo!(),
178                    Some(user) => match user {
179                        pb::tuple::User::UserId(userid) => User::UserId(userid),
180                        pb::tuple::User::UserSet(pb::UserSet { ns, obj, rel }) => User::UserSet {
181                            ns: Namespace(ns),
182                            obj: Obj(obj),
183                            rel: Rel(rel),
184                        },
185                    },
186                },
187            })
188            .collect())
189    }
190    // >>>>>>> b14ae43 (Add read api and client API)
191}
192impl CheckClient {
193    pub async fn create(uri: Uri) -> Result<Self, ConnectError> {
194        match Channel::builder(uri).connect().await {
195            Ok(channel) => Ok(CheckClient {
196                client: pb::check_service_client::CheckServiceClient::new(channel),
197            }),
198            Err(err) => Err(ConnectError(err)),
199        }
200    }
201    // pub async fn create(uri: Uri) -> Result<Self, ConnectError> {
202    //     let retry_strategy = FixedInterval::from_millis(100).take(20);
203    //     let channel = Retry::spawn(retry_strategy, connect(uri)).await?;
204    //     let client = pb::check_service_client::CheckServiceClient::new(channel.clone());
205    //     Ok(CheckClient { client })
206    // }
207    pub async fn add_one(&mut self, tuple: Tuple) -> Result<String, AddError> {
208        let add_tuples = vec![pb::Tuple {
209            ns: tuple.ns.0.to_string(),
210            obj: tuple.obj.0,
211            rel: tuple.rel.0.to_string(),
212            user: match tuple.sbj {
213                User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
214                User::UserSet {
215                    ns: Namespace(ns),
216                    obj: Obj(obj),
217                    rel: Rel(rel),
218                } => Some(pb::tuple::User::UserSet(pb::UserSet {
219                    ns: ns.to_string(),
220                    obj,
221                    rel: rel.to_string(),
222                })),
223            },
224            condition: None,
225        }];
226        dbg!(&add_tuples);
227        self.client
228            .write(pb::WriteRequest {
229                add_tuples,
230                ..Default::default()
231            })
232            .await
233            .map(|r| r.into_inner().ts)
234            .map_err(Into::into)
235    }
236
237    pub async fn add_one_with_condition(
238        &mut self,
239        tuple: Tuple,
240        condition: Condition,
241    ) -> Result<String, AddError> {
242        let add_tuples = vec![pb::Tuple {
243            ns: tuple.ns.0.to_string(),
244            obj: tuple.obj.0,
245            rel: tuple.rel.0.to_string(),
246            user: match tuple.sbj {
247                User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
248                User::UserSet {
249                    ns: Namespace(ns),
250                    obj: Obj(obj),
251                    rel: Rel(rel),
252                } => Some(pb::tuple::User::UserSet(pb::UserSet {
253                    ns: ns.to_string(),
254                    obj,
255                    rel: rel.to_string(),
256                })),
257            },
258            condition: match condition {
259                Condition::Expires(exp) => Some(pb::tuple::Condition::Expires(exp.timestamp())),
260            },
261        }];
262        self.client
263            .write(pb::WriteRequest {
264                add_tuples,
265                ..Default::default()
266            })
267            .await
268            .map(|r| r.into_inner().ts)
269            .map_err(Into::into)
270    }
271
272    pub async fn add_many(&mut self, tuples: Vec<Tuple>) -> Result<String, AddError> {
273        let add_tuples = tuples
274            .into_iter()
275            .map(|tuple| pb::Tuple {
276                ns: tuple.ns.0,
277                obj: tuple.obj.0,
278                rel: tuple.rel.0,
279                user: match tuple.sbj {
280                    User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
281                    User::UserSet {
282                        ns: Namespace(ns),
283                        obj: Obj(obj),
284                        rel: Rel(rel),
285                    } => Some(pb::tuple::User::UserSet(pb::UserSet { ns, obj, rel })),
286                },
287                condition: None,
288            })
289            .collect();
290        self.client
291            .write(pb::WriteRequest {
292                add_tuples,
293                ..Default::default()
294            })
295            .await
296            .map(|r| r.into_inner().ts)
297            .map_err(Into::into)
298    }
299
300    pub async fn delete_one(&mut self, tuple: Tuple) -> Result<String, AddError> {
301        let del_tuples = vec![pb::Tuple {
302            ns: tuple.ns.0,
303            obj: tuple.obj.0,
304            rel: tuple.rel.0.to_string(),
305            user: match tuple.sbj {
306                User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
307                User::UserSet {
308                    ns: Namespace(ns),
309                    obj: Obj(obj),
310                    rel: Rel(rel),
311                } => Some(pb::tuple::User::UserSet(pb::UserSet {
312                    ns: ns.to_string(),
313                    obj,
314                    rel: rel.to_string(),
315                })),
316            },
317            condition: None,
318        }];
319        self.client
320            .write(pb::WriteRequest {
321                del_tuples,
322                ..Default::default()
323            })
324            .await
325            .map(|r| r.into_inner().ts)
326            .map_err(Into::into)
327    }
328}
329
330// fn connect<'a>(
331//     uri: Uri,
332// ) -> impl FnMut() -> Pin<Box<dyn Future<Output = Result<Channel, ConnectError>> + 'a>> {
333//     move || {
334//         let uri = uri.clone();
335//         Box::pin(async {
336//             match Channel::builder(uri).connect().await {
337//                 Ok(channel) => Ok(channel),
338//                 Err(err) => Err(ConnectError(err)),
339//             }
340//         })
341//     }
342// }
343impl CheckClient {
344    pub async fn check(
345        &mut self,
346        Namespace(ns): Namespace,
347        Obj(obj): Obj,
348        Permission(permission): Permission,
349        UserId(user_id): UserId,
350        timestamp: Option<Timestamp>,
351    ) -> Result<CheckResult, CallError> {
352        let r = pb::CheckRequest {
353            ns: ns.to_string(),
354            obj,
355            rel: permission.to_string(),
356            user_id,
357            ts: timestamp.unwrap_or(Timestamp::empty()).0,
358        };
359        match self.client.check(r).await.map(|r| r.into_inner()) {
360            Ok(pb::CheckResponse {
361                principal: Some(pb::Principal { id }),
362                ok,
363            }) if ok => Ok(CheckResult::Ok(id.into())),
364            Ok(pb::CheckResponse {
365                principal: Some(pb::Principal { id }),
366                ok,
367            }) if !ok => Ok(CheckResult::Forbidden(id.into())),
368            Ok(pb::CheckResponse {
369                principal: None, ..
370            }) => Ok(CheckResult::UnknownPutativeUser),
371            Ok(pb::CheckResponse { .. }) => Err(CallError::UnexpectedResponseFormat),
372            Err(status) => Err(status.into()),
373        }
374    }
375
376    pub async fn list(
377        &mut self,
378        Namespace(ns): Namespace,
379        Rel(rel): Rel,
380        UserId(user_id): UserId,
381        timestamp: Option<Timestamp>,
382    ) -> Result<Vec<String>, CallError> {
383        let r = pb::ListRequest {
384            ns,
385            rel: rel.to_string(),
386            user_id,
387            ts: timestamp.unwrap_or(Timestamp::empty()).0,
388        };
389        match self.client.list(r).await.map(|r| r.into_inner()) {
390            Ok(response) => Ok(response.objs),
391            Err(e) => Err(e.into()),
392        }
393    }
394}