about summary refs log tree commit diff
path: root/tools/sendsms/src/main.rs
diff options
context:
space:
mode:
authorFranck Cuny <franck@fcuny.net>2022-09-05 16:59:20 -0700
committerFranck Cuny <franck@fcuny.net>2022-09-07 19:12:12 -0700
commitc853a5078b0a8dee22bb69b971b8315f66033f49 (patch)
tree3c05da1eb7c9d39e936de21108f42a59765ab4ef /tools/sendsms/src/main.rs
parentmeta: ignore build for rust projects (diff)
downloadworld-c853a5078b0a8dee22bb69b971b8315f66033f49.tar.gz
feat(tool/sendsms): a CLI to send SMS
This is a new tool to send SMS via Twilio's API. For now it supports a
single subcommand: reboot. Using that subcommand, a SMS will be send
with the name of the host and the IP address for the defined network
interface. This is useful to be notified when one of my machine reboot,
and what's the IP for the main interface (this is useful since my ISP
does not provide a static IP).

Change-Id: I5886a2c77ebd344ab3befa51a6bdd3d65bcc85d4
Diffstat (limited to 'tools/sendsms/src/main.rs')
-rwxr-xr-xtools/sendsms/src/main.rs85
1 files changed, 85 insertions, 0 deletions
diff --git a/tools/sendsms/src/main.rs b/tools/sendsms/src/main.rs
new file mode 100755
index 0000000..30e92ff
--- /dev/null
+++ b/tools/sendsms/src/main.rs
@@ -0,0 +1,85 @@
+#![warn(rust_2018_idioms)]
+
+mod config;
+mod message;
+
+use clap::{crate_version, Parser};
+use gethostname::gethostname;
+use log::{error, info};
+use std::net::IpAddr;
+use std::path::PathBuf;
+use std::process::exit;
+
+#[derive(Parser, Debug)]
+#[clap(name = "sendsms")]
+#[clap(author = "Franck Cuny <franck@fcuny.net>")]
+#[clap(version = crate_version!())]
+#[clap(propagate_version = true)]
+struct Args {
+    #[clap(short, long, value_parser)]
+    config: PathBuf,
+
+    #[clap(subcommand)]
+    subcmd: SubCommand,
+}
+
+#[derive(Parser, Debug)]
+enum SubCommand {
+    Reboot,
+}
+
+fn main() {
+    env_logger::init();
+    let args = Args::parse();
+
+    let config: config::Config = match config::Config::load_from_file(&args.config) {
+        Ok(r) => r,
+        Err(e) => {
+            error!(
+                "unable to load data from {}: {}",
+                args.config.display(),
+                e.to_string()
+            );
+            exit(1);
+        }
+    };
+
+    let body = match args.subcmd {
+        SubCommand::Reboot => reboot(&config.reboot),
+    };
+
+    let msg = message::Message {
+        from: config.from.to_owned(),
+        to: config.to.to_owned(),
+        body,
+    };
+
+    match msg.send(&config) {
+        Ok(_) => info!("message sent successfully"),
+        Err(error) => {
+            error!("failed to send the message: {}", error);
+            exit(1);
+        }
+    }
+}
+
+fn reboot(config: &config::RebootConfig) -> String {
+    let ipaddr_v4 = if_addrs::get_if_addrs()
+        .unwrap_or_default()
+        .into_iter()
+        .find(|iface| iface.name == config.ifname)
+        .and_then(|iface| match iface.ip() {
+            IpAddr::V4(addr) => Some(addr),
+            IpAddr::V6(_) => None,
+        })
+        .expect("there should be an ipv4 address");
+
+    let hostname = gethostname()
+        .into_string()
+        .expect("failed to get the hostname");
+
+    format!(
+        "{} has rebooted. The IP address for the interface {} is {}.",
+        hostname, config.ifname, ipaddr_v4
+    )
+}