-
Notifications
You must be signed in to change notification settings - Fork 4
/
lib.rs
90 lines (81 loc) · 2.99 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#![forbid(unsafe_code)]
#![doc = include_str!("../README.md")]
use std::{
env,
io::Read,
process::{Command, Stdio},
};
use anyhow::{bail, Context};
pub use apis::{
applications_control, applications_upload, basic_device_info, parameter_management,
systemready, ws_data_stream,
};
pub use http::{Client as HttpClient, HttpError, HttpErrorKind};
use log::debug;
use url::Url;
mod ajr;
mod ajr2;
mod ajr_http;
mod ajr_http2;
mod apis;
mod http;
fn from_dbus() -> anyhow::Result<HttpClient> {
// TODO: Consider verifying the manifest or providing hints when it looks misconfigured and this
// call fails.
// TODO: Consider using a DBUs library like `zbus`
debug!("Getting credentials...");
let mut child = Command::new("/usr/bin/gdbus")
.arg("call")
.arg("--system")
.args(["--dest", "com.axis.HTTPConf1"])
.args(["--object-path", "/com/axis/HTTPConf1/VAPIXServiceAccounts1"])
.args([
"--method",
"com.axis.HTTPConf1.VAPIXServiceAccounts1.GetCredentials",
])
.arg("default")
.stdout(Stdio::piped())
.spawn()?;
// Unwrap is OK because `stdout` has not been taken since the child was spawned above.
let mut stdout = child.stdout.take().unwrap();
let status = child.wait()?;
if !status.success() {
// TODO: Consider capturing stderr and attaching to error or logging as warning.
bail!("Command exited with status {status}")
}
let mut credentials = String::new();
stdout.read_to_string(&mut credentials)?;
let (username, password) = credentials
.trim()
.strip_prefix("('")
.context("Expected dbus response to start with ('")?
.strip_suffix("',)")
.context("Expected dbus response to end with ')")?
.split_once(':')
.context("Expected dbus response to contain at least one :")?;
debug!("Creating client using username {username} from dbus");
Ok(
HttpClient::new(Url::parse("http://127.0.0.12").expect("Hardcoded url is valid"))
.basic_auth(username, password),
)
}
fn from_env() -> anyhow::Result<HttpClient> {
let username = env::var("AXIS_DEVICE_USER").unwrap_or("root".into());
let password = env::var("AXIS_DEVICE_PASS").unwrap_or("pass".into());
let host = env::var("AXIS_DEVICE_IP")?;
let url = Url::parse(&format!("http://{host}"))?;
debug!("Creating client using username {username} from env");
// TODO: Select appropriate authentication scheme
// When connecting locally basic is always used but when connecting remotely the default is
// currently digest, so it would be convenient if that was applied to the client.
Ok(HttpClient::new(url).basic_auth(username, password))
}
/// Construct a new [`HttpClient`] for ACAP apps connecting to VAPIX.
pub fn local_client() -> anyhow::Result<HttpClient> {
// TODO: Find a more robust configuration
if cfg!(target_arch = "x86_64") {
from_env()
} else {
from_dbus()
}
}