Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client side of the registration service. #58

Merged
merged 1 commit into from
Feb 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ docopt = "0.6.78"
docopt_macros = "0.6.80"
env_logger = "0.3.2"
foxbox_users = { git = "https://github.com/fxbox/users.git", rev = "78d3e2f" }
get_if_addrs = "0.3.1"
hyper = "0.7.2"
iron = "0.2.6"
iron-test = "0.2.0"
log = "0.3"
Expand Down
12 changes: 9 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ extern crate staticfile;
extern crate uuid;

mod context;
mod controller;
mod dummy_adapter;
mod events;
mod http_server;
mod service;
mod controller;
mod registration;
mod service_router;

mod stubs {
Expand All @@ -56,24 +57,29 @@ use context::{ ContextTrait, Context };
use controller::Controller;

docopt!(Args derive Debug, "
Usage: foxbox [-v] [-h] [-n <hostname>] [-p <port>] [-w <wsport>]
Usage: foxbox [-v] [-h] [-n <hostname>] [-p <port>] [-w <wsport>] [-r <url>]

Options:
-v, --verbose Toggle verbose output.
-n, --name <hostname> Set local hostname.
-p, --port <port> Set port to listen on for http connections.
-w, --wsport <wsport> Set port to listen on for websocket.
-r, --register <url> Change the url of the registration endpoint.
-h, --help Print this help menu.
",
flag_name: Option<String>,
flag_port: Option<u16>,
flag_wsport: Option<u16>);
flag_wsport: Option<u16>,
flag_register: Option<String>);

fn main() {
env_logger::init().unwrap();

let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

let registrar = registration::Registrar::new();
registrar.start(args.flag_register);

if let Ok(mut event_loop) = mio::EventLoop::new() {
let sender = event_loop.channel();

Expand Down
111 changes: 111 additions & 0 deletions src/registration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/// This manages registration of the foxbox with the discovery endpoint.
/// For now it simply register itselfs every N minutes with the endpoint,
/// after trying more aggressively at first run.

extern crate get_if_addrs;
extern crate hyper;

use self::hyper::Client;
use self::hyper::header::Connection;
use self::hyper::status::StatusCode;
use self::get_if_addrs::IfAddr;
use std::io::Read;
use std::time::Duration;
use std::thread;

const DEFAULT_ENDPOINT: &'static str = "http://localhost:4242/register";
const REGISTRATION_INTERVAL: u32 = 1; // in minutes.

pub struct Registrar;

impl Registrar {
pub fn new() -> Registrar {
Registrar
}

pub fn start(&self, endpoint: Option<String>) {
let url = match endpoint {
Some(u) => u,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we validate the url passed?
Not needed in this PR we could do a follow up.

_ => DEFAULT_ENDPOINT.to_owned()
};

info!("Starting registration with {}", url);
let ip_addr = self.get_ip_addr();
if ip_addr == None {
// TODO: retry later, in case we're racing with the network
// configuration.
return;
}

info!("Got ip address: {}", ip_addr.clone().unwrap());
let full_address = format!("{}?ip={}", url, ip_addr.unwrap());

// Spawn a thread to register every REGISTRATION_INTERVAL minutes.
thread::Builder::new().name("Registrar".to_owned())
.spawn(move || {
loop {
let client = Client::new();
let res = client.get(&full_address)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: not to be done in this pr but in the service, perhaps this should be a post.

.header(Connection::close())
.send();

// Sanity checks, mostly to debug errors since we don't try
// to recover from failures.
if let Ok(mut response) = res {
if response.status == StatusCode::Ok {
let mut body = String::new();
if let Ok(_) = response.read_to_string(&mut body) {
info!("Server responded with: {}", body);
} else {
info!("Unable to read answer from {}", full_address);
}
}
} else {
info!("Unable to send request to {}", full_address);
}

// Go to sleep.
thread::sleep(Duration::from_secs(REGISTRATION_INTERVAL as u64 * 60))
}
}).unwrap();
}

pub fn get_ip_addr(&self) -> Option<String> {
// Look for an ipv4 interface on eth* or wlan*.
if let Ok(ifaces) = get_if_addrs::get_if_addrs() {
if ifaces.is_empty() {
error!("No IP interfaces found!");
return None;
}

let mut ip_addr: Option<String> = None;

for iface in ifaces {
if ! (iface.name.starts_with("eth") ||
iface.name.starts_with("wlan") ||
iface.name.starts_with("en")) {
continue;
}
if let IfAddr::V4(ref v4) = iface.addr {
ip_addr = Some(format!("{}", v4.ip));
}
}

ip_addr
} else {
error!("No IP interfaces found!");
None
}
}
}

#[test]
fn check_ip_addr() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can add this as a test module to avoid compilation when non testing: #[cfg(test)] ...

let registrar = Registrar::new();
let ip_addr = registrar.get_ip_addr();
assert!(ip_addr != None);
}
4 changes: 3 additions & 1 deletion src/service_router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use context::{ ContextTrait, Shared };
use iron::{Request, Response, IronResult};
use iron::headers::ContentType;
use iron::headers::{ ContentType, AccessControlAllowOrigin };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the changes in service_router.rs intended for the origin of the PR? Or maybe I'm missing something.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added them to get my demo client working. I guess we'll change/revert once we have proper user authentication working.

use iron::status::Status;
use router::Router;
use core::marker::Reflect;
Expand All @@ -21,6 +21,7 @@ pub fn create<Ctx: Send + Reflect + ContextTrait + 'static> (context: Shared<Ctx

let mut response = Response::with(serialized);
response.status = Some(Status::Ok);
response.headers.set(AccessControlAllowOrigin::Any);
response.headers.set(ContentType::json());

Ok(response)
Expand All @@ -36,6 +37,7 @@ pub fn create<Ctx: Send + Reflect + ContextTrait + 'static> (context: Shared<Ctx
None => {
let mut response = Response::with(format!("No Such Service: {}", id));
response.status = Some(Status::BadRequest);
response.headers.set(AccessControlAllowOrigin::Any);
response.headers.set(ContentType::plaintext());
Ok(response)
}
Expand Down