1use holo_hash::ActionHash;
4use holo_hash::AgentPubKey;
5use holo_hash::AnyLinkableHash;
6use holochain_serialized_bytes::prelude::*;
7use holochain_zome_types::prelude::*;
8use regex::Regex;
9
10use crate::dht_op::ChainOpType;
11use crate::dht_op::DhtOpError;
12use crate::dht_op::DhtOpResult;
13use crate::dht_op::RenderedOp;
14use crate::dht_op::RenderedOps;
15
16#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, SerializedBytes)]
17pub struct WireLinkKey {
19 pub base: AnyLinkableHash,
21 pub type_query: LinkTypeFilter,
23 pub tag: Option<LinkTag>,
25 pub after: Option<Timestamp>,
27 pub before: Option<Timestamp>,
29 pub author: Option<AgentPubKey>,
31}
32
33#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, SerializedBytes, Default)]
34pub struct WireLinkOps {
36 pub creates: Vec<WireCreateLink>,
38 pub deletes: Vec<WireDeleteLink>,
40}
41
42impl WireLinkOps {
43 pub fn new() -> Self {
45 Default::default()
46 }
47 pub fn render(self, key: &WireLinkKey) -> DhtOpResult<RenderedOps> {
49 let Self { creates, deletes } = self;
50 let mut ops = Vec::with_capacity(creates.len() + deletes.len());
51 ops.extend(creates.into_iter().filter_map(|op| op.render(key).ok()));
53 ops.extend(deletes.into_iter().filter_map(|op| op.render(key).ok()));
54 Ok(RenderedOps {
55 ops,
56 ..Default::default()
57 })
58 }
59}
60
61#[allow(missing_docs)]
62#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, SerializedBytes)]
63pub struct WireCreateLink {
65 pub author: AgentPubKey,
66 pub timestamp: Timestamp,
67 pub action_seq: u32,
68 pub prev_action: ActionHash,
69
70 pub target_address: AnyLinkableHash,
71 pub zome_index: ZomeIndex,
72 pub link_type: LinkType,
73 pub tag: Option<LinkTag>,
74 pub signature: Signature,
75 pub validation_status: ValidationStatus,
76 pub weight: RateWeight,
77}
78
79#[allow(missing_docs)]
80#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, SerializedBytes)]
81pub struct WireDeleteLink {
83 pub author: AgentPubKey,
84 pub timestamp: Timestamp,
85 pub action_seq: u32,
86 pub prev_action: ActionHash,
87
88 pub link_add_address: ActionHash,
89 pub signature: Signature,
90 pub validation_status: ValidationStatus,
91}
92
93impl WireCreateLink {
94 fn new(
95 h: CreateLink,
96 signature: Signature,
97 validation_status: ValidationStatus,
98 tag: bool,
99 ) -> Self {
100 Self {
101 author: h.author,
102 timestamp: h.timestamp,
103 action_seq: h.action_seq,
104 prev_action: h.prev_action,
105 target_address: h.target_address,
106 zome_index: h.zome_index,
107 link_type: h.link_type,
108 tag: if tag { Some(h.tag) } else { None },
109 signature,
110 validation_status,
111 weight: h.weight,
112 }
113 }
114 pub fn condense_base_only(
116 h: CreateLink,
117 signature: Signature,
118 validation_status: ValidationStatus,
119 ) -> Self {
120 Self::new(h, signature, validation_status, false)
121 }
122 pub fn condense(
124 h: CreateLink,
125 signature: Signature,
126 validation_status: ValidationStatus,
127 ) -> Self {
128 Self::new(h, signature, validation_status, true)
129 }
130 pub fn render(self, key: &WireLinkKey) -> DhtOpResult<RenderedOp> {
132 let tag = self
133 .tag
134 .or_else(|| key.tag.clone())
135 .ok_or(DhtOpError::LinkKeyTagMissing)?;
136 let action = Action::CreateLink(CreateLink {
137 author: self.author,
138 timestamp: self.timestamp,
139 action_seq: self.action_seq,
140 prev_action: self.prev_action,
141 base_address: key.base.clone(),
142 target_address: self.target_address,
143 zome_index: self.zome_index,
144 link_type: self.link_type,
145 weight: self.weight,
146 tag,
147 });
148 let signature = self.signature;
149 let validation_status = Some(self.validation_status);
150 RenderedOp::new(
151 action,
152 signature,
153 validation_status,
154 ChainOpType::RegisterAddLink,
155 )
156 }
157}
158
159impl WireDeleteLink {
160 pub fn condense(
162 h: DeleteLink,
163 signature: Signature,
164 validation_status: ValidationStatus,
165 ) -> Self {
166 Self {
167 author: h.author,
168 timestamp: h.timestamp,
169 action_seq: h.action_seq,
170 prev_action: h.prev_action,
171 signature,
172 validation_status,
173 link_add_address: h.link_add_address,
174 }
175 }
176 pub fn render(self, key: &WireLinkKey) -> DhtOpResult<RenderedOp> {
178 let action = Action::DeleteLink(DeleteLink {
179 author: self.author,
180 timestamp: self.timestamp,
181 action_seq: self.action_seq,
182 prev_action: self.prev_action,
183 base_address: key.base.clone(),
184 link_add_address: self.link_add_address,
185 });
186 let signature = self.signature;
187 let validation_status = Some(self.validation_status);
188 RenderedOp::new(
189 action,
190 signature,
191 validation_status,
192 ChainOpType::RegisterRemoveLink,
193 )
194 }
195}
196#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, SerializedBytes)]
201pub struct GetLinksResponse {
202 pub link_adds: Vec<(CreateLink, Signature)>,
204 pub link_removes: Vec<(DeleteLink, Signature)>,
206}
207
208pub enum LinkMatch<S: Into<String>> {
210 Any,
212
213 Exactly(S),
215
216 Regex(S),
218}
219
220impl<S: Into<String>> LinkMatch<S> {
221 #[allow(clippy::wrong_self_convention)]
223 pub fn to_regex_string(self) -> Result<String, String> {
224 let re_string: String = match self {
225 LinkMatch::Any => ".*".into(),
226 LinkMatch::Exactly(s) => "^".to_owned() + ®ex::escape(&s.into()) + "$",
227 LinkMatch::Regex(s) => s.into(),
228 };
229 match Regex::new(&re_string) {
231 Ok(_) => Ok(re_string),
232 Err(_) => Err("Invalid regex passed to get_links".into()),
233 }
234 }
235}
236
237#[derive(serde::Serialize, serde::Deserialize, SerializedBytes, PartialEq, Clone, Debug)]
239pub struct WireLinkQuery {
240 pub base: AnyLinkableHash,
242
243 pub link_type: LinkTypeFilter,
245
246 pub tag_prefix: Option<LinkTag>,
248
249 pub before: Option<Timestamp>,
251
252 pub after: Option<Timestamp>,
254
255 pub author: Option<AgentPubKey>,
257}
258
259#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, SerializedBytes)]
261pub struct CountLinksResponse(Vec<ActionHash>);
262
263impl CountLinksResponse {
264 pub fn new(create_link_actions: Vec<ActionHash>) -> Self {
266 CountLinksResponse(create_link_actions)
267 }
268
269 pub fn create_link_actions(&self) -> Vec<ActionHash> {
271 self.0.clone()
272 }
273}