1use std::sync::atomic::{self, AtomicBool};
2use std::sync::Arc;
3
4use bstr::BString;
5use radicle::crypto::PublicKey;
6use radicle::git::Oid;
7use radicle::identity::{Doc, DocError};
8use radicle::storage::git::Repository;
9use radicle::storage::ReadRepository;
10
11use crate::policy::{Allowed, BlockList};
12use crate::transport::{ConnectionStream, Transport};
13
14pub struct Handle<R, S> {
16 pub(crate) local: PublicKey,
17 repo: R,
18 pub(crate) allowed: Allowed,
19 pub(crate) transport: Transport<S>,
20 pub(crate) blocked: BlockList,
28 pub(crate) interrupt: Arc<AtomicBool>,
30}
31
32impl<R, S> Handle<R, S> {
33 pub fn is_blocked(&self, key: &PublicKey) -> bool {
34 self.blocked.is_blocked(key)
35 }
36
37 #[inline]
38 pub fn local(&self) -> &PublicKey {
39 &self.local
40 }
41
42 pub fn interrupt_pack_writer(&mut self) {
43 self.interrupt.store(true, atomic::Ordering::Relaxed);
44 }
45
46 pub fn allowed(&self) -> Allowed {
47 self.allowed.clone()
48 }
49
50 pub fn into_inner(self) -> R {
51 self.repo
52 }
53}
54
55impl<R, S> Handle<R, S>
56where
57 R: AsRef<Repository>,
58{
59 pub fn new(
60 local: PublicKey,
61 repo: R,
62 follow: Allowed,
63 blocked: BlockList,
64 connection: S,
65 ) -> Result<Self, error::Init>
66 where
67 S: ConnectionStream,
68 {
69 let git_dir = repo.as_ref().backend.path().to_path_buf();
70 let transport = Transport::new(
71 git_dir,
72 BString::from(repo.as_ref().id.canonical()),
73 connection,
74 );
75
76 Ok(Self {
77 local,
78 repo,
79 allowed: follow,
80 transport,
81 blocked,
82 interrupt: Arc::new(AtomicBool::new(false)),
83 })
84 }
85
86 #[inline]
87 pub fn repository(&self) -> &Repository {
88 self.repo.as_ref()
89 }
90
91 pub fn verified(&self, head: Oid) -> Result<Doc, DocError> {
92 Ok(self.repository().identity_doc_at(head)?.doc)
93 }
94}
95
96pub mod error {
97 use radicle::node::policy;
98 use radicle::prelude::RepoId;
99 use radicle::{git, storage};
100 use thiserror::Error;
101
102 #[derive(Debug, Error)]
103 pub enum Init {
104 #[error(transparent)]
105 Tracking(#[from] policy::config::Error),
106 }
107
108 #[derive(Debug, Error)]
109 pub enum Tracking {
110 #[error("failed to find policy for {rid}")]
111 FailedPolicy {
112 rid: RepoId,
113 #[source]
114 err: policy::store::Error,
115 },
116 #[error("cannot fetch {rid} as it is not seeded")]
117 BlockedPolicy { rid: RepoId },
118 #[error("failed to get tracking nodes for {rid}")]
119 FailedNodes {
120 rid: RepoId,
121 #[source]
122 err: policy::store::Error,
123 },
124
125 #[error(transparent)]
126 Storage(#[from] storage::Error),
127
128 #[error(transparent)]
129 Git(#[from] git::raw::Error),
130
131 #[error(transparent)]
132 Refs(#[from] storage::refs::Error),
133 }
134}