ndn_config/
nfd_command.rs1use bytes::Bytes;
12use ndn_packet::{Name, NameComponent};
13
14use crate::control_parameters::ControlParameters;
15
16pub const NFD_PREFIX: &[&[u8]] = &[b"localhost", b"nfd"];
18
19pub mod module {
23 pub const FACES: &[u8] = b"faces";
24 pub const FIB: &[u8] = b"fib";
25 pub const RIB: &[u8] = b"rib";
26 pub const ROUTING: &[u8] = b"routing";
27 pub const DISCOVERY: &[u8] = b"discovery";
28 pub const CS: &[u8] = b"cs";
29 pub const STRATEGY: &[u8] = b"strategy-choice";
30 pub const STATUS: &[u8] = b"status";
31 pub const NEIGHBORS: &[u8] = b"neighbors";
32 pub const SERVICE: &[u8] = b"service";
33 pub const MEASUREMENTS: &[u8] = b"measurements";
34 pub const CONFIG: &[u8] = b"config";
35 pub const SECURITY: &[u8] = b"security";
36 pub const LOG: &[u8] = b"log";
37}
38
39pub mod verb {
41 pub const GET: &[u8] = b"get";
43
44 pub const CREATE: &[u8] = b"create";
46 pub const UPDATE: &[u8] = b"update";
47 pub const DESTROY: &[u8] = b"destroy";
48 pub const LIST: &[u8] = b"list";
49
50 pub const ADD_NEXTHOP: &[u8] = b"add-nexthop";
52 pub const REMOVE_NEXTHOP: &[u8] = b"remove-nexthop";
53
54 pub const REGISTER: &[u8] = b"register";
56 pub const UNREGISTER: &[u8] = b"unregister";
57
58 pub const SET: &[u8] = b"set";
60 pub const UNSET: &[u8] = b"unset";
61
62 pub const CONFIG: &[u8] = b"config";
64 pub const INFO: &[u8] = b"info";
65 pub const ERASE: &[u8] = b"erase";
66
67 pub const ANNOUNCE: &[u8] = b"announce";
69 pub const WITHDRAW: &[u8] = b"withdraw";
70 pub const BROWSE: &[u8] = b"browse";
71
72 pub const COUNTERS: &[u8] = b"counters";
74
75 pub const IDENTITY_LIST: &[u8] = b"identity-list";
77 pub const IDENTITY_GENERATE: &[u8] = b"identity-generate";
78 pub const IDENTITY_DID: &[u8] = b"identity-did";
79 pub const IDENTITY_STATUS: &[u8] = b"identity-status";
81 pub const ANCHOR_LIST: &[u8] = b"anchor-list";
82 pub const KEY_DELETE: &[u8] = b"key-delete";
83
84 pub const CA_INFO: &[u8] = b"ca-info";
86 pub const CA_ENROLL: &[u8] = b"ca-enroll";
87 pub const CA_TOKEN_ADD: &[u8] = b"ca-token-add";
88 pub const CA_REQUESTS: &[u8] = b"ca-requests";
89
90 pub const YUBIKEY_DETECT: &[u8] = b"yubikey-detect";
92 pub const YUBIKEY_GENERATE: &[u8] = b"yubikey-generate";
93
94 pub const SCHEMA_RULE_ADD: &[u8] = b"schema-rule-add";
98 pub const SCHEMA_RULE_REMOVE: &[u8] = b"schema-rule-remove";
101 pub const SCHEMA_LIST: &[u8] = b"schema-list";
103 pub const SCHEMA_SET: &[u8] = b"schema-set";
106
107 pub const GET_FILTER: &[u8] = b"get-filter";
109 pub const SET_FILTER: &[u8] = b"set-filter";
110 pub const GET_RECENT: &[u8] = b"get-recent";
111
112 pub const DVR_STATUS: &[u8] = b"dvr-status";
114 pub const DVR_CONFIG: &[u8] = b"dvr-config";
115}
116
117pub fn command_name(module: &[u8], verb: &[u8], params: &ControlParameters) -> Name {
127 let params_tlv = params.encode();
128 Name::from_components([
129 NameComponent::generic(Bytes::from_static(b"localhost")),
130 NameComponent::generic(Bytes::from_static(b"nfd")),
131 NameComponent::generic(Bytes::copy_from_slice(module)),
132 NameComponent::generic(Bytes::copy_from_slice(verb)),
133 NameComponent::generic(params_tlv),
134 ])
135}
136
137pub fn dataset_name(module: &[u8], verb: &[u8]) -> Name {
141 Name::from_components([
142 NameComponent::generic(Bytes::from_static(b"localhost")),
143 NameComponent::generic(Bytes::from_static(b"nfd")),
144 NameComponent::generic(Bytes::copy_from_slice(module)),
145 NameComponent::generic(Bytes::copy_from_slice(verb)),
146 ])
147}
148
149#[derive(Debug)]
153pub struct ParsedCommand {
154 pub module: Bytes,
155 pub verb: Bytes,
156 pub params: Option<ControlParameters>,
157}
158
159pub fn parse_command_name(name: &Name) -> Option<ParsedCommand> {
166 let comps = name.components();
167 if comps.len() < 4 {
168 return None;
169 }
170
171 if comps[0].value.as_ref() != b"localhost" || comps[1].value.as_ref() != b"nfd" {
173 return None;
174 }
175
176 let module = comps[2].value.clone();
177 let verb = comps[3].value.clone();
178
179 let params = if comps.len() >= 5 {
184 ControlParameters::decode(comps[4].value.clone()).ok()
185 } else {
186 None
187 };
188
189 Some(ParsedCommand {
190 module,
191 verb,
192 params,
193 })
194}
195
196#[cfg(test)]
199mod tests {
200 use super::*;
201
202 #[test]
203 fn command_name_structure() {
204 let params = ControlParameters {
205 name: Some(Name::from_components([NameComponent::generic(
206 Bytes::from_static(b"test"),
207 )])),
208 cost: Some(10),
209 ..Default::default()
210 };
211 let name = command_name(module::RIB, verb::REGISTER, ¶ms);
212 let comps = name.components();
213 assert_eq!(comps.len(), 5);
214 assert_eq!(comps[0].value.as_ref(), b"localhost");
215 assert_eq!(comps[1].value.as_ref(), b"nfd");
216 assert_eq!(comps[2].value.as_ref(), b"rib");
217 assert_eq!(comps[3].value.as_ref(), b"register");
218 let decoded = ControlParameters::decode(comps[4].value.clone()).unwrap();
220 assert_eq!(decoded.cost, Some(10));
221 }
222
223 #[test]
224 fn dataset_name_structure() {
225 let name = dataset_name(module::FACES, verb::LIST);
226 let comps = name.components();
227 assert_eq!(comps.len(), 4);
228 assert_eq!(comps[2].value.as_ref(), b"faces");
229 assert_eq!(comps[3].value.as_ref(), b"list");
230 }
231
232 #[test]
233 fn parse_command_roundtrip() {
234 let params = ControlParameters {
235 uri: Some("shm://myapp".to_owned()),
236 ..Default::default()
237 };
238 let name = command_name(module::FACES, verb::CREATE, ¶ms);
239 let parsed = parse_command_name(&name).unwrap();
240 assert_eq!(parsed.module.as_ref(), b"faces");
241 assert_eq!(parsed.verb.as_ref(), b"create");
242 let p = parsed.params.unwrap();
243 assert_eq!(p.uri.as_deref(), Some("shm://myapp"));
244 }
245
246 #[test]
247 fn parse_command_too_short() {
248 let name = Name::from_components([
249 NameComponent::generic(Bytes::from_static(b"localhost")),
250 NameComponent::generic(Bytes::from_static(b"nfd")),
251 ]);
252 assert!(parse_command_name(&name).is_none());
253 }
254
255 #[test]
256 fn parse_command_wrong_prefix() {
257 let name = Name::from_components([
258 NameComponent::generic(Bytes::from_static(b"localhop")),
259 NameComponent::generic(Bytes::from_static(b"nfd")),
260 NameComponent::generic(Bytes::from_static(b"rib")),
261 NameComponent::generic(Bytes::from_static(b"register")),
262 ]);
263 assert!(parse_command_name(&name).is_none());
264 }
265
266 #[test]
267 fn parse_command_no_params() {
268 let name = dataset_name(module::FACES, verb::LIST);
269 let parsed = parse_command_name(&name).unwrap();
270 assert_eq!(parsed.module.as_ref(), b"faces");
271 assert_eq!(parsed.verb.as_ref(), b"list");
272 assert!(parsed.params.is_none());
273 }
274}