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);
23const PERSONAL: &str = "personal";
24const ROOT: &str = "root";
25const TOKEN: &str = "token";
26const SERVICEACCOUNT_NS: &str = "serviceaccount";
27impl Namespace {
28    pub fn personal() -> Namespace {
29        Namespace(PERSONAL.into())
30    }
31    pub fn token() -> Namespace {
32        Namespace(TOKEN.into())
33    }
34    pub fn root() -> Namespace {
35        Namespace(ROOT.into())
36    }
37    pub fn serviceaccount() -> Namespace {
38        Namespace(SERVICEACCOUNT_NS.into())
39    }
40}
41
42#[derive(Clone, Debug)]
43pub struct Permission(pub &'static str);
44
45#[derive(Clone, Debug)]
46pub struct Rel(pub String);
47impl Rel {
48    pub const TRIPLE_DOT: &'static str = "...";
49    pub const IS: &'static str = "is";
50    pub const PARENT: &'static str = "parent";
51    pub const IAM_GET: &'static str = "iam.get";
52    pub const IAM_UPDATE: &'static str = "iam.update";
53    pub const IAM_DELETE: &'static str = "iam.delete";
54    pub const SERVICEACCOUNT_GET: &'static str = "serviceaccount.get";
55    pub const SERVICEACCOUNT_CREATE: &'static str = "serviceaccount.create";
56    pub const SERVICEACCOUNT_KEY_GET: &'static str = "serviceaccount.key.get";
57    pub const SERVICEACCOUNT_KEY_CREATE: &'static str = "serviceaccount.key.create";
58    pub const SERVICEACCOUNT_CREATE_TOKEN: &'static str = "serviceaccount.createToken";
59    pub const USER_CREATE: &'static str = "user.create";
60
61    pub fn triple_dot() -> Rel {
62        Rel(Self::TRIPLE_DOT.into())
63    }
64    pub fn is() -> Rel {
65        Rel(Self::IS.into())
66    }
67    pub fn parent() -> Rel {
68        Rel(Self::PARENT.into())
69    }
70    pub fn iam_get() -> Rel {
71        Rel(Self::IAM_GET.into())
72    }
73    pub fn iam_update() -> Rel {
74        Rel(Self::IAM_UPDATE.into())
75    }
76    pub fn iam_delete() -> Rel {
77        Rel(Self::IAM_DELETE.into())
78    }
79    pub fn serviceaccount_get() -> Rel {
80        Rel(Self::SERVICEACCOUNT_GET.into())
81    }
82    pub fn serviceaccount_create() -> Rel {
83        Rel(Self::SERVICEACCOUNT_CREATE.into())
84    }
85    pub fn serviceaccount_key_get() -> Rel {
86        Rel(Self::SERVICEACCOUNT_KEY_GET.into())
87    }
88    pub fn serviceaccount_key_create() -> Rel {
89        Rel(Self::SERVICEACCOUNT_KEY_CREATE.into())
90    }
91    pub fn serviceaccount_create_token() -> Rel {
92        Rel(Self::SERVICEACCOUNT_CREATE_TOKEN.into())
93    }
94    pub fn user_upsert() -> Rel {
95        Rel(Self::USER_CREATE.into())
96    }
97}
98
99impl From<Permission> for Rel {
100    fn from(value: Permission) -> Self {
101        Rel(value.0.to_string())
102    }
103}
104
105#[derive(Clone, Debug)]
106pub struct UserId(pub String);
107
108#[derive(Clone, Debug)]
109pub struct Timestamp(pub String);
110
111impl Timestamp {
112    pub fn empty() -> Self {
113        Timestamp("1:0000000000000".into())
114    }
115}
116
117impl FromStr for UserId {
118    type Err = ParseError;
119
120    fn from_str(s: &str) -> Result<Self, Self::Err> {
121        Ok(UserId(s.into()))
122    }
123}
124
125impl TryFrom<String> for UserId {
126    type Error = ParseError;
127    fn try_from(value: String) -> Result<Self, Self::Error> {
128        UserId::from_str(&value)
129    }
130}
131
132#[derive(Clone, Debug)]
133pub struct Obj(pub String);
134const ROOT_OBJ: &str = "root";
135const UNSPECIFIED_OBJ: &str = "...";
136impl Obj {
137    pub fn unspecified() -> Obj {
138        Obj(UNSPECIFIED_OBJ.into())
139    }
140    pub fn root() -> Obj {
141        Obj(ROOT_OBJ.into())
142    }
143}
144
145impl FromStr for Obj {
146    type Err = ParseError;
147
148    fn from_str(s: &str) -> Result<Self, Self::Err> {
149        Ok(Obj(s.into()))
150    }
151}
152
153impl TryFrom<String> for Obj {
154    type Error = ParseError;
155    fn try_from(value: String) -> Result<Self, Self::Error> {
156        Obj::from_str(&value)
157    }
158}
159
160#[derive(Clone, Debug)]
161pub struct Tuple {
162    pub ns: Namespace,
163    pub obj: Obj,
164    pub rel: Rel,
165    pub sbj: User,
166}
167
168impl Display for Tuple {
169    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
170        match self {
171            Tuple {
172                ref ns,
173                ref obj,
174                ref rel,
175                sbj: User::UserId(ref s),
176            } => write!(f, "Tuple({}:{}#{}@{})", ns.0, obj.0, rel.0, s),
177            Tuple {
178                ref ns,
179                ref obj,
180                ref rel,
181                sbj:
182                    User::UserSet {
183                        ns: ref ns2,
184                        obj: ref obj2,
185                        rel: ref rel2,
186                    },
187            } => write!(
188                f,
189                "Tuple({}:{}#{}@{}:{}#{})",
190                ns.0, obj.0, rel.0, ns2.0, obj2.0, rel2.0
191            ),
192        }
193    }
194}
195
196#[derive(Clone, Debug)]
197pub enum Condition {
198    Expires(DateTime<Utc>),
199}
200
201#[derive(Clone, Debug)]
202pub enum User {
203    UserId(String),
204    UserSet { ns: Namespace, obj: Obj, rel: Rel },
205}
206
207mod pb {
208    tonic::include_proto!("am");
209}
210
211#[derive(Clone, Debug)]
212pub struct CheckClient {
213    pub(crate) client: pb::check_service_client::CheckServiceClient<Channel>,
214}
215
216impl CheckClient {
217    // <<<<<<< HEAD
218    //     // pub async fn get_all(&mut self, ns: &Namespace, obj: &Obj) -> Result<String, AddError> {
219    //     //     let response = self
220    //     //         .client
221    //     //         .read(pb::ReadRequest {
222    //     //             tuple_sets: vec![TupleSet {
223    //     //                 ns: "".to_string(),
224    //     //                 spec: Some(ObjectSpec(ObjectSpec {})),
225    //     //             }],
226    //     //             ts: None,
227    //     //         })
228    //     //         .await
229    //     //         .map(|r| r.into_inner().ts)
230    //     //         .map_err(Into::into)?;
231    //     // }
232    // =======
233    pub async fn get_all(&mut self, ns: &Namespace, obj: &Obj) -> Result<Vec<Tuple>, ReadError> {
234        let response = self
235            .client
236            .read(pb::ReadRequest {
237                tuple_sets: vec![TupleSet {
238                    ns: ns.0.clone(),
239                    spec: Some(pb::tuple_set::Spec::ObjectSpec(ObjectSpec {
240                        obj: obj.0.clone(),
241                        rel: None,
242                    })),
243                }],
244                ts: None,
245            })
246            .await?;
247        let response = response.into_inner();
248        Ok(response
249            .tuples
250            .into_iter()
251            .map(|tup| Tuple {
252                ns: Namespace(tup.ns),
253                obj: Obj(tup.obj),
254                rel: Rel(tup.rel),
255                sbj: match tup.user {
256                    None => todo!(),
257                    Some(user) => match user {
258                        pb::tuple::User::UserId(userid) => User::UserId(userid),
259                        pb::tuple::User::UserSet(pb::UserSet { ns, obj, rel }) => User::UserSet {
260                            ns: Namespace(ns),
261                            obj: Obj(obj),
262                            rel: Rel(rel),
263                        },
264                    },
265                },
266            })
267            .collect())
268    }
269    // >>>>>>> b14ae43 (Add read api and client API)
270}
271impl CheckClient {
272    pub async fn create(uri: Uri) -> Result<Self, ConnectError> {
273        match Channel::builder(uri).connect().await {
274            Ok(channel) => Ok(CheckClient {
275                client: pb::check_service_client::CheckServiceClient::new(channel),
276            }),
277            Err(err) => Err(ConnectError(err)),
278        }
279    }
280    // pub async fn create(uri: Uri) -> Result<Self, ConnectError> {
281    //     let retry_strategy = FixedInterval::from_millis(100).take(20);
282    //     let channel = Retry::spawn(retry_strategy, connect(uri)).await?;
283    //     let client = pb::check_service_client::CheckServiceClient::new(channel.clone());
284    //     Ok(CheckClient { client })
285    // }
286    pub async fn add_one(&mut self, tuple: Tuple) -> Result<String, AddError> {
287        let add_tuples = vec![pb::Tuple {
288            ns: tuple.ns.0.to_string(),
289            obj: tuple.obj.0,
290            rel: tuple.rel.0.to_string(),
291            user: match tuple.sbj {
292                User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
293                User::UserSet {
294                    ns: Namespace(ns),
295                    obj: Obj(obj),
296                    rel: Rel(rel),
297                } => Some(pb::tuple::User::UserSet(pb::UserSet {
298                    ns: ns.to_string(),
299                    obj,
300                    rel: rel.to_string(),
301                })),
302            },
303            condition: None,
304        }];
305        dbg!(&add_tuples);
306        self.client
307            .write(pb::WriteRequest {
308                add_tuples,
309                ..Default::default()
310            })
311            .await
312            .map(|r| r.into_inner().ts)
313            .map_err(Into::into)
314    }
315
316    pub async fn add_one_with_condition(
317        &mut self,
318        tuple: Tuple,
319        condition: Condition,
320    ) -> Result<String, AddError> {
321        let add_tuples = vec![pb::Tuple {
322            ns: tuple.ns.0.to_string(),
323            obj: tuple.obj.0,
324            rel: tuple.rel.0.to_string(),
325            user: match tuple.sbj {
326                User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
327                User::UserSet {
328                    ns: Namespace(ns),
329                    obj: Obj(obj),
330                    rel: Rel(rel),
331                } => Some(pb::tuple::User::UserSet(pb::UserSet {
332                    ns: ns.to_string(),
333                    obj,
334                    rel: rel.to_string(),
335                })),
336            },
337            condition: match condition {
338                Condition::Expires(exp) => Some(pb::tuple::Condition::Expires(exp.timestamp())),
339            },
340        }];
341        self.client
342            .write(pb::WriteRequest {
343                add_tuples,
344                ..Default::default()
345            })
346            .await
347            .map(|r| r.into_inner().ts)
348            .map_err(Into::into)
349    }
350
351    pub async fn add_many(&mut self, tuples: Vec<Tuple>) -> Result<String, AddError> {
352        let add_tuples = tuples
353            .into_iter()
354            .map(|tuple| pb::Tuple {
355                ns: tuple.ns.0,
356                obj: tuple.obj.0,
357                rel: tuple.rel.0,
358                user: match tuple.sbj {
359                    User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
360                    User::UserSet {
361                        ns: Namespace(ns),
362                        obj: Obj(obj),
363                        rel: Rel(rel),
364                    } => Some(pb::tuple::User::UserSet(pb::UserSet { ns, obj, rel })),
365                },
366                condition: None,
367            })
368            .collect();
369        self.client
370            .write(pb::WriteRequest {
371                add_tuples,
372                ..Default::default()
373            })
374            .await
375            .map(|r| r.into_inner().ts)
376            .map_err(Into::into)
377    }
378
379    pub async fn delete_one(&mut self, tuple: Tuple) -> Result<String, AddError> {
380        let del_tuples = vec![pb::Tuple {
381            ns: tuple.ns.0,
382            obj: tuple.obj.0,
383            rel: tuple.rel.0.to_string(),
384            user: match tuple.sbj {
385                User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
386                User::UserSet {
387                    ns: Namespace(ns),
388                    obj: Obj(obj),
389                    rel: Rel(rel),
390                } => Some(pb::tuple::User::UserSet(pb::UserSet {
391                    ns: ns.to_string(),
392                    obj,
393                    rel: rel.to_string(),
394                })),
395            },
396            condition: None,
397        }];
398        self.client
399            .write(pb::WriteRequest {
400                del_tuples,
401                ..Default::default()
402            })
403            .await
404            .map(|r| r.into_inner().ts)
405            .map_err(Into::into)
406    }
407}
408
409// fn connect<'a>(
410//     uri: Uri,
411// ) -> impl FnMut() -> Pin<Box<dyn Future<Output = Result<Channel, ConnectError>> + 'a>> {
412//     move || {
413//         let uri = uri.clone();
414//         Box::pin(async {
415//             match Channel::builder(uri).connect().await {
416//                 Ok(channel) => Ok(channel),
417//                 Err(err) => Err(ConnectError(err)),
418//             }
419//         })
420//     }
421// }
422impl CheckClient {
423    pub async fn check(
424        &mut self,
425        Namespace(ns): Namespace,
426        Obj(obj): Obj,
427        Permission(permission): Permission,
428        UserId(user_id): UserId,
429        timestamp: Option<Timestamp>,
430    ) -> Result<CheckResult, CallError> {
431        let r = pb::CheckRequest {
432            ns: ns.to_string(),
433            obj,
434            rel: permission.to_string(),
435            user_id,
436            ts: timestamp.unwrap_or(Timestamp::empty()).0,
437        };
438        match self.client.check(r).await.map(|r| r.into_inner()) {
439            Ok(pb::CheckResponse {
440                principal: Some(pb::Principal { id }),
441                ok,
442            }) if ok => Ok(CheckResult::Ok(id.into())),
443            Ok(pb::CheckResponse {
444                principal: Some(pb::Principal { id }),
445                ok,
446            }) if !ok => Ok(CheckResult::Forbidden(id.into())),
447            Ok(pb::CheckResponse {
448                principal: None, ..
449            }) => Ok(CheckResult::UnknownPutativeUser),
450            Ok(pb::CheckResponse { .. }) => Err(CallError::UnexpectedResponseFormat),
451            Err(status) => Err(status.into()),
452        }
453    }
454
455    pub async fn list(
456        &mut self,
457        Namespace(ns): Namespace,
458        Rel(rel): Rel,
459        UserId(user_id): UserId,
460        timestamp: Option<Timestamp>,
461    ) -> Result<Vec<String>, CallError> {
462        let r = pb::ListRequest {
463            ns,
464            rel: rel.to_string(),
465            user_id,
466            ts: timestamp.unwrap_or(Timestamp::empty()).0,
467        };
468        match self.client.list(r).await.map(|r| r.into_inner()) {
469            Ok(response) => Ok(response.objs),
470            Err(e) => Err(e.into()),
471        }
472    }
473}