Skip to content

Commit c438ac6

Browse files
authored
Merge pull request #6 from unytco/register-dna
Register dna
2 parents f2bacb5 + 7f92656 commit c438ac6

3 files changed

Lines changed: 161 additions & 0 deletions

File tree

src/bin/log-sender.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,31 @@ enum Cmd {
4949
conductor_config_path: Vec<std::path::PathBuf>,
5050
},
5151

52+
/// Register DNA hashes with agreements and optional price sheets for a
53+
/// drone.
54+
RegisterDna {
55+
/// Specify a full path to a config file,
56+
/// e.g. `/var/run/log-sender-runtime.json`.
57+
#[arg(long, env = "LOG_SENDER_CONFIG_FILE")]
58+
config_file: std::path::PathBuf,
59+
60+
/// The dna hash to register.
61+
#[arg(long, env = "LOG_SENDER_DNA_HASH")]
62+
dna_hash: String,
63+
64+
/// The agreement id to register.
65+
#[arg(long, env = "LOG_SENDER_AGREEMENT_ID")]
66+
agreement_id: String,
67+
68+
/// Optionally attach a price-sheet hash.
69+
#[arg(long, env = "LOG_SENDER_PRICE_SHEET_HASH")]
70+
price_sheet_hash: Option<String>,
71+
72+
/// Optionally include additional json metadata.
73+
#[arg(long, env = "LOG_SENDER_METADATA")]
74+
metadata: Option<String>,
75+
},
76+
5277
/// Run the service, polling a log-file directory for metrics to
5378
/// publish to the log-collector.
5479
Service {
@@ -98,6 +123,24 @@ async fn main() {
98123
)
99124
.await
100125
.unwrap(),
126+
Cmd::RegisterDna {
127+
config_file,
128+
dna_hash,
129+
agreement_id,
130+
price_sheet_hash,
131+
metadata,
132+
} => {
133+
let out = log_sender::register_dna(
134+
config_file,
135+
dna_hash,
136+
agreement_id,
137+
price_sheet_hash,
138+
metadata.map(|s| serde_json::from_str(&s).unwrap()),
139+
)
140+
.await
141+
.unwrap();
142+
println!("{}", serde_json::to_string_pretty(&out).unwrap());
143+
}
101144
Cmd::Service { config_file } => {
102145
log_sender::run_service(config_file).await.unwrap()
103146
}

src/client.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,96 @@ impl Client {
134134
Err(std::io::Error::other(format!("invalid response: {res:?}")))
135135
}
136136

137+
/// Make a "register-dna" call.
138+
pub async fn register_dna(
139+
&self,
140+
config: &RuntimeConfigFile,
141+
dna_hash: String,
142+
agreement_id: String,
143+
price_sheet_hash: Option<String>,
144+
metadata: Option<serde_json::Value>,
145+
) -> Result<serde_json::Value> {
146+
let mut url = self.url.clone();
147+
url.set_path("/register-dna");
148+
149+
#[derive(serde::Serialize)]
150+
#[serde(rename_all = "camelCase")]
151+
struct Req {
152+
drone_pub_key: String,
153+
dna_hash: String,
154+
agreement_id: String,
155+
price_sheet_hash: Option<String>,
156+
drone_signature: String,
157+
signature_timestamp: u64,
158+
metadata: Option<serde_json::Value>,
159+
}
160+
161+
let drone_pub_key = config.drone_pub_key.clone();
162+
let signature_timestamp = std::time::SystemTime::UNIX_EPOCH
163+
.elapsed()
164+
.expect("can get time")
165+
.as_millis() as u64;
166+
167+
#[derive(serde::Serialize)]
168+
#[serde(rename_all = "camelCase")]
169+
struct Sig {
170+
drone_pub_key: String,
171+
dna_hash: String,
172+
agreement_id: String,
173+
timestamp: u64,
174+
#[serde(skip_serializing_if = "Option::is_none")]
175+
price_sheet_hash: Option<String>,
176+
#[serde(skip_serializing_if = "Option::is_none")]
177+
metadata: Option<serde_json::Value>,
178+
}
179+
180+
let sig = serde_json::to_string(&Sig {
181+
drone_pub_key: drone_pub_key.clone(),
182+
dna_hash: dna_hash.clone(),
183+
agreement_id: agreement_id.clone(),
184+
timestamp: signature_timestamp,
185+
price_sheet_hash: price_sheet_hash.clone(),
186+
metadata: metadata.clone(),
187+
})?;
188+
189+
let drone_signature = config.rt_drone_sec_key.sign(sig.as_bytes())?;
190+
191+
let res = self
192+
.client
193+
.post(url)
194+
.json(&Req {
195+
drone_pub_key,
196+
dna_hash,
197+
agreement_id,
198+
price_sheet_hash,
199+
drone_signature,
200+
signature_timestamp,
201+
metadata,
202+
})
203+
.send()
204+
.await
205+
.map_err(std::io::Error::other)?;
206+
207+
if res.error_for_status_ref().is_err() {
208+
return Err(std::io::Error::other(
209+
res.text().await.map_err(std::io::Error::other)?,
210+
));
211+
}
212+
213+
let res: serde_json::Value =
214+
res.json().await.map_err(std::io::Error::other)?;
215+
216+
if let Some(obj) = res.as_object()
217+
&& let Some(p) = obj.get("success")
218+
&& let Some(b) = p.as_bool()
219+
&& b
220+
{
221+
return Ok(res);
222+
}
223+
224+
Err(std::io::Error::other(format!("invalid response: {res:?}")))
225+
}
226+
137227
/// Submit metrics to the endpoint.
138228
pub async fn metrics(
139229
&self,

src/lib.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,34 @@ pub async fn initialize(
5252
Ok(())
5353
}
5454

55+
/// Register DNA hashes with agreements and optional price sheets for a drone.
56+
pub async fn register_dna(
57+
config_file: std::path::PathBuf,
58+
dna_hash: String,
59+
agreement_id: String,
60+
price_sheet_hash: Option<String>,
61+
metadata: Option<serde_json::Value>,
62+
) -> Result<serde_json::Value> {
63+
let config = RuntimeConfigFile::with_load(config_file).await?;
64+
65+
let url =
66+
reqwest::Url::parse(&config.endpoint).map_err(std::io::Error::other)?;
67+
68+
let client = Client::new(url).await?;
69+
70+
client.health().await?;
71+
72+
client
73+
.register_dna(
74+
&config,
75+
dna_hash,
76+
agreement_id,
77+
price_sheet_hash,
78+
metadata,
79+
)
80+
.await
81+
}
82+
5583
/// Run the service checking for report logs and reporting them.
5684
pub async fn run_service(config_file: std::path::PathBuf) -> Result<()> {
5785
let mut config = RuntimeConfigFile::with_load(config_file).await?;

0 commit comments

Comments
 (0)