<commit_before>/* 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/. */

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventBinding;
use dom::bindings::codegen::Bindings::EventBinding::{EventConstants, EventMethods};
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{MutNullableJS, JSRef, Temporary};
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::eventtarget::{EventTarget, EventTargetHelpers};
use util::str::DOMString;

use std::borrow::ToOwned;
use std::cell::Cell;
use std::default::Default;

use time;

#[jstraceable]
#[derive(Copy)]
pub enum EventPhase {
    None      = EventConstants::NONE as int,
    Capturing = EventConstants::CAPTURING_PHASE as int,
    AtTarget  = EventConstants::AT_TARGET as int,
    Bubbling  = EventConstants::BUBBLING_PHASE as int,
}

#[derive(PartialEq)]
#[jstraceable]
pub enum EventTypeId {
    CustomEvent,
    HTMLEvent,
    KeyboardEvent,
    MessageEvent,
    MouseEvent,
    ProgressEvent,
    UIEvent,
    ErrorEvent
}

#[derive(PartialEq)]
pub enum EventBubbles {
    Bubbles,
    DoesNotBubble
}

#[derive(PartialEq)]
pub enum EventCancelable {
    Cancelable,
    NotCancelable
}

#[dom_struct]
pub struct Event {
    reflector_: Reflector,
    type_id: EventTypeId,
    current_target: MutNullableJS<EventTarget>,
    target: MutNullableJS<EventTarget>,
    type_: DOMRefCell<DOMString>,
    phase: Cell<EventPhase>,
    canceled: Cell<bool>,
    stop_propagation: Cell<bool>,
    stop_immediate: Cell<bool>,
    cancelable: Cell<bool>,
    bubbles: Cell<bool>,
    trusted: Cell<bool>,
    dispatching: Cell<bool>,
    initialized: Cell<bool>,
    timestamp: u64,
}

impl Event {
    pub fn new_inherited(type_id: EventTypeId) -> Event {
        Event {
            reflector_: Reflector::new(),
            type_id: type_id,
            current_target: Default::default(),
            target: Default::default(),
            phase: Cell::new(EventPhase::None),
            type_: DOMRefCell::new("".to_owned()),
            canceled: Cell::new(false),
            cancelable: Cell::new(false),
            bubbles: Cell::new(false),
            trusted: Cell::new(false),
            dispatching: Cell::new(false),
            stop_propagation: Cell::new(false),
            stop_immediate: Cell::new(false),
            initialized: Cell::new(false),
            timestamp: time::get_time().sec as u64,
        }
    }

    pub fn new_uninitialized(global: GlobalRef) -> Temporary<Event> {
        reflect_dom_object(box Event::new_inherited(EventTypeId::HTMLEvent),
                           global,
                           EventBinding::Wrap)
    }

    pub fn new(global: GlobalRef,
               type_: DOMString,
               bubbles: EventBubbles,
               cancelable: EventCancelable) -> Temporary<Event> {
        let event = Event::new_uninitialized(global).root();
        event.r().InitEvent(type_, bubbles == EventBubbles::Bubbles, cancelable == EventCancelable::Cancelable);
        Temporary::from_rooted(event.r())
    }

    pub fn Constructor(global: GlobalRef,
                       type_: DOMString,
                       init: &EventBinding::EventInit) -> Fallible<Temporary<Event>> {
        let bubbles = if init.bubbles { EventBubbles::Bubbles } else { EventBubbles::DoesNotBubble };
        let cancelable = if init.cancelable { EventCancelable::Cancelable } else { EventCancelable::NotCancelable };
        Ok(Event::new(global, type_, bubbles, cancelable))
    }

    #[inline]
    pub fn type_id<'a>(&'a self) -> &'a EventTypeId {
        &self.type_id
    }

    #[inline]
    pub fn clear_current_target(&self) {
        self.current_target.clear();
    }

    #[inline]
    pub fn set_current_target(&self, val: JSRef<EventTarget>) {
        self.current_target.assign(Some(val));
    }

    #[inline]
    pub fn set_target(&self, val: JSRef<EventTarget>) {
        self.target.assign(Some(val));
    }

    #[inline]
    pub fn set_phase(&self, val: EventPhase) {
        self.phase.set(val)
    }

    #[inline]
    pub fn stop_propagation(&self) -> bool {
        self.stop_propagation.get()
    }

    #[inline]
    pub fn stop_immediate(&self) -> bool {
        self.stop_immediate.get()
    }

    #[inline]
    pub fn bubbles(&self) -> bool {
        self.bubbles.get()
    }

    #[inline]
    pub fn dispatching(&self) -> bool {
        self.dispatching.get()
    }

    #[inline]
    pub fn set_dispatching(&self, val: bool) {
        self.dispatching.set(val)
    }

    #[inline]
    pub fn initialized(&self) -> bool {
        self.initialized.get()
    }
}

impl<'a> EventMethods for JSRef<'a, Event> {
    fn EventPhase(self) -> u16 {
        self.phase.get() as u16
    }

    fn Type(self) -> DOMString {
        self.type_.borrow().clone()
    }

    fn GetTarget(self) -> Option<Temporary<EventTarget>> {
        self.target.get()
    }

    fn GetCurrentTarget(self) -> Option<Temporary<EventTarget>> {
        self.current_target.get()
    }

    fn DefaultPrevented(self) -> bool {
        self.canceled.get()
    }

    fn PreventDefault(self) {
        if self.cancelable.get() {
            self.canceled.set(true)
        }
    }

    fn StopPropagation(self) {
        self.stop_propagation.set(true);
    }

    fn StopImmediatePropagation(self) {
        self.stop_immediate.set(true);
        self.stop_propagation.set(true);
    }

    fn Bubbles(self) -> bool {
        self.bubbles.get()
    }

    fn Cancelable(self) -> bool {
        self.cancelable.get()
    }

    fn TimeStamp(self) -> u64 {
        self.timestamp
    }

    fn InitEvent(self,
                 type_: DOMString,
                 bubbles: bool,
                 cancelable: bool) {
        if self.dispatching.get() {
            return;
        }

        self.initialized.set(true);
        self.stop_propagation.set(false);
        self.stop_immediate.set(false);
        self.canceled.set(false);
        self.trusted.set(false);
        self.target.clear();
        *self.type_.borrow_mut() = type_;
        self.bubbles.set(bubbles);
        self.cancelable.set(cancelable);
    }

    fn IsTrusted(self) -> bool {
        self.trusted.get()
    }
}

pub trait EventHelpers {
    fn set_trusted(self, trusted: bool);
    fn fire(self, target: JSRef<EventTarget>);
}

impl<'a> EventHelpers for JSRef<'a, Event> {
    fn set_trusted(self, trusted: bool) {
        self.trusted.set(trusted);
    }

    // https://html.spec.whatwg.org/multipage/webappapis.html#fire-a-simple-event
    fn fire(self, target: JSRef<EventTarget>) {
        self.set_trusted(true);
        target.dispatch_event(self);
    }
}
<commit_msg>Change the representation of EventPhase to u16.<commit_after>/* 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/. */

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventBinding;
use dom::bindings::codegen::Bindings::EventBinding::{EventConstants, EventMethods};
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{MutNullableJS, JSRef, Temporary};
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::eventtarget::{EventTarget, EventTargetHelpers};
use util::str::DOMString;

use std::borrow::ToOwned;
use std::cell::Cell;
use std::default::Default;

use time;

#[jstraceable]
#[derive(Copy)]
#[repr(u16)]
pub enum EventPhase {
    None      = EventConstants::NONE,
    Capturing = EventConstants::CAPTURING_PHASE,
    AtTarget  = EventConstants::AT_TARGET,
    Bubbling  = EventConstants::BUBBLING_PHASE,
}

#[derive(PartialEq)]
#[jstraceable]
pub enum EventTypeId {
    CustomEvent,
    HTMLEvent,
    KeyboardEvent,
    MessageEvent,
    MouseEvent,
    ProgressEvent,
    UIEvent,
    ErrorEvent
}

#[derive(PartialEq)]
pub enum EventBubbles {
    Bubbles,
    DoesNotBubble
}

#[derive(PartialEq)]
pub enum EventCancelable {
    Cancelable,
    NotCancelable
}

#[dom_struct]
pub struct Event {
    reflector_: Reflector,
    type_id: EventTypeId,
    current_target: MutNullableJS<EventTarget>,
    target: MutNullableJS<EventTarget>,
    type_: DOMRefCell<DOMString>,
    phase: Cell<EventPhase>,
    canceled: Cell<bool>,
    stop_propagation: Cell<bool>,
    stop_immediate: Cell<bool>,
    cancelable: Cell<bool>,
    bubbles: Cell<bool>,
    trusted: Cell<bool>,
    dispatching: Cell<bool>,
    initialized: Cell<bool>,
    timestamp: u64,
}

impl Event {
    pub fn new_inherited(type_id: EventTypeId) -> Event {
        Event {
            reflector_: Reflector::new(),
            type_id: type_id,
            current_target: Default::default(),
            target: Default::default(),
            phase: Cell::new(EventPhase::None),
            type_: DOMRefCell::new("".to_owned()),
            canceled: Cell::new(false),
            cancelable: Cell::new(false),
            bubbles: Cell::new(false),
            trusted: Cell::new(false),
            dispatching: Cell::new(false),
            stop_propagation: Cell::new(false),
            stop_immediate: Cell::new(false),
            initialized: Cell::new(false),
            timestamp: time::get_time().sec as u64,
        }
    }

    pub fn new_uninitialized(global: GlobalRef) -> Temporary<Event> {
        reflect_dom_object(box Event::new_inherited(EventTypeId::HTMLEvent),
                           global,
                           EventBinding::Wrap)
    }

    pub fn new(global: GlobalRef,
               type_: DOMString,
               bubbles: EventBubbles,
               cancelable: EventCancelable) -> Temporary<Event> {
        let event = Event::new_uninitialized(global).root();
        event.r().InitEvent(type_, bubbles == EventBubbles::Bubbles, cancelable == EventCancelable::Cancelable);
        Temporary::from_rooted(event.r())
    }

    pub fn Constructor(global: GlobalRef,
                       type_: DOMString,
                       init: &EventBinding::EventInit) -> Fallible<Temporary<Event>> {
        let bubbles = if init.bubbles { EventBubbles::Bubbles } else { EventBubbles::DoesNotBubble };
        let cancelable = if init.cancelable { EventCancelable::Cancelable } else { EventCancelable::NotCancelable };
        Ok(Event::new(global, type_, bubbles, cancelable))
    }

    #[inline]
    pub fn type_id<'a>(&'a self) -> &'a EventTypeId {
        &self.type_id
    }

    #[inline]
    pub fn clear_current_target(&self) {
        self.current_target.clear();
    }

    #[inline]
    pub fn set_current_target(&self, val: JSRef<EventTarget>) {
        self.current_target.assign(Some(val));
    }

    #[inline]
    pub fn set_target(&self, val: JSRef<EventTarget>) {
        self.target.assign(Some(val));
    }

    #[inline]
    pub fn set_phase(&self, val: EventPhase) {
        self.phase.set(val)
    }

    #[inline]
    pub fn stop_propagation(&self) -> bool {
        self.stop_propagation.get()
    }

    #[inline]
    pub fn stop_immediate(&self) -> bool {
        self.stop_immediate.get()
    }

    #[inline]
    pub fn bubbles(&self) -> bool {
        self.bubbles.get()
    }

    #[inline]
    pub fn dispatching(&self) -> bool {
        self.dispatching.get()
    }

    #[inline]
    pub fn set_dispatching(&self, val: bool) {
        self.dispatching.set(val)
    }

    #[inline]
    pub fn initialized(&self) -> bool {
        self.initialized.get()
    }
}

impl<'a> EventMethods for JSRef<'a, Event> {
    fn EventPhase(self) -> u16 {
        self.phase.get() as u16
    }

    fn Type(self) -> DOMString {
        self.type_.borrow().clone()
    }

    fn GetTarget(self) -> Option<Temporary<EventTarget>> {
        self.target.get()
    }

    fn GetCurrentTarget(self) -> Option<Temporary<EventTarget>> {
        self.current_target.get()
    }

    fn DefaultPrevented(self) -> bool {
        self.canceled.get()
    }

    fn PreventDefault(self) {
        if self.cancelable.get() {
            self.canceled.set(true)
        }
    }

    fn StopPropagation(self) {
        self.stop_propagation.set(true);
    }

    fn StopImmediatePropagation(self) {
        self.stop_immediate.set(true);
        self.stop_propagation.set(true);
    }

    fn Bubbles(self) -> bool {
        self.bubbles.get()
    }

    fn Cancelable(self) -> bool {
        self.cancelable.get()
    }

    fn TimeStamp(self) -> u64 {
        self.timestamp
    }

    fn InitEvent(self,
                 type_: DOMString,
                 bubbles: bool,
                 cancelable: bool) {
        if self.dispatching.get() {
            return;
        }

        self.initialized.set(true);
        self.stop_propagation.set(false);
        self.stop_immediate.set(false);
        self.canceled.set(false);
        self.trusted.set(false);
        self.target.clear();
        *self.type_.borrow_mut() = type_;
        self.bubbles.set(bubbles);
        self.cancelable.set(cancelable);
    }

    fn IsTrusted(self) -> bool {
        self.trusted.get()
    }
}

pub trait EventHelpers {
    fn set_trusted(self, trusted: bool);
    fn fire(self, target: JSRef<EventTarget>);
}

impl<'a> EventHelpers for JSRef<'a, Event> {
    fn set_trusted(self, trusted: bool) {
        self.trusted.set(trusted);
    }

    // https://html.spec.whatwg.org/multipage/webappapis.html#fire-a-simple-event
    fn fire(self, target: JSRef<EventTarget>) {
        self.set_trusted(true);
        target.dispatch_event(self);
    }
}
<|endoftext|>


<commit_before>//!
//! The API for communicating with devices.
//!
//! This API is provided as Traits to be implemented:
//!
//! - by the low-level layers of the FoxBox, including the adapters;
//! - by test suites and tools that need to simulate connected devices.
//!
//! In turn, this API is used to implement:
//!
//! - the public-facing REST and WebSocket API;
//! - the rules API (ThinkerBell).
//!
//!

use devices::*;
use requests::*;
use values::Value;

/// An error produced by one of the APIs in this module.
pub enum Error {
    /// There is no such node connected to the Foxbox, even indirectly.
    NoSuchNode(NodeId),

    /// There is no such service connected to the Foxbox, even indirectly.
    NoSuchService(ServiceId),

    /// Attempting to set a value with the wrong type
    TypeError,
}

/// An event during watching.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum WatchEvent {
    /// A new value is available.
    Value {
        /// The service that sent the value.
        from: ServiceId,

        /// The actual value.
        value: Value
    },

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// removed. Payload is the id of the device that was removed.
    InputRemoved(ServiceId),

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// added. Payload is the id of the device that was added.
    InputAdded(ServiceId),
}

/// The public API.
pub trait API {
    /// Get the metadata on nodes matching some conditions.
    ///
    /// A call to `API::get_nodes(vec![req1, req2, ...])` will return
    /// the metadata on all nodes matching _either_ `req1` or `req2`
    /// or ...
    ///
    /// # REST API
    ///
    /// `GET /api/v1/nodes`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to a `Vec<NodeRequest>`. See
    /// the implementation of `NodeRequest` for details.
    ///
    /// ### Example
    ///
    /// Request all doors in the entrance (tags `door`, `entrance`)
    /// that support output service `OpenClose`
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door"],
    ///   "inputs": [
    ///     {
    ///       "kind": {
    ///         "Exactly": {
    ///           "OpenClose": []
    ///         }
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    ///
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing an array of `Node`. See the implementation
    /// of `Node` for details.
    ///
    /// ### Example
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door", "somevendor"],
    ///   "id: "some-node-id",
    ///   "inputs": [],
    ///   "outputs": [
    ///     "tags": [...],
    ///     "id": "some-service-id",
    ///     "node": "some-node-id",
    ///     "last_seen": "some-date",
    ///     "mechanism": {
    ///       "Output":  {
    ///         "kind": {
    ///           "OnOff": []
    ///         },
    ///         "push": [5000],
    ///         "updated": "some-date",
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    fn get_nodes(&Vec<NodeRequest>) -> Vec<Node>;

    /// Label a set of nodes with a set of tags.
    ///
    /// A call to `API::put_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the nodes matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/nodes/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON string representing a number.
    fn put_node_tag(set: &Vec<NodeRequest>, tags: &Vec<String>) -> usize;

    /// Remove a set of tags from a set of nodes.
    ///
    /// A call to `API::delete_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the nodes matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/nodes/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_node_tag(set: &Vec<NodeRequest>, tags: String) -> usize;

    /// Get a list of inputs matching some conditions
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services`
    fn get_input_services(&Vec<InputRequest>) -> Vec<Service<Input>>;
    fn get_output_services(&Vec<OutputRequest>) -> Vec<Service<Output>>;

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```rust
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn put_input_tag(&Vec<InputRequest>, &Vec<String>) -> usize;
    fn put_output_tag(&Vec<OutputRequest>, &Vec<String>) -> usize;

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/services/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```rust
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_input_tag(&Vec<InputRequest>, &Vec<String>) -> usize;
    fn delete_output_tag(&Vec<InputRequest>, &Vec<String>) -> usize;

    /// Read the latest value from a set of services
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services/value`
    fn get_service_value(&Vec<InputRequest>) -> Vec<(ServiceId, Result<Value, Error>)>;

    /// Send one value to a set of services
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/value`
    fn put_service_value(&Vec<OutputRequest>, Value) -> Vec<(ServiceId, Result<(), Error>)>;

    /// Watch for any change
    ///
    /// # WebSocket API
    ///
    /// `/api/v1/services/watch`
    fn register_service_watch<F>(Vec<WatchOptions>, cb: F) -> Self::WatchGuard
        where F: FnMut(WatchEvent) + Send + Sync;

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard;
}

/// Options for watching changes in one or more services.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct WatchOptions {
    /// The set of inputs to watch. Note that the actual inputs in the
    /// set may change over time.
    source: InputRequest,

    /// If `true`, watch as new values become available.
    should_watch_values: bool,

    /// If `true`, watch as nodes are connected/disconnected.
    should_watch_topology: bool,
}

impl WatchOptions {
    pub fn new() -> Self {
        WatchOptions {
            source: InputRequest::new(),
            should_watch_values: false,
            should_watch_topology: false,
        }
    }

    /// Restrict to input services in a given set.
    ///
    /// Also note that the actual input services that are part of the
    /// set may change with time, for instance if devices are added
    /// ore removed.  The request _is live_, i.e. the service watch
    /// will continue watching any input services that match `req`.
    pub fn with_inputs(self, req: InputRequest) -> Self {
        WatchOptions {
            source: self.source.and(req),
            ..self
        }
    }

    pub fn with_watch_values(self, should: bool) -> Self {
        WatchOptions {
            should_watch_values: should,
            ..self
        }
    }

    pub fn with_watch_topology(self, should: bool) -> Self {
        WatchOptions {
            should_watch_topology: should,
            ..self
        }
    }
}
<commit_msg>[fxbox/taxonomy] API::register_service_watch now requires 'static instead of Sync<commit_after>//!
//! The API for communicating with devices.
//!
//! This API is provided as Traits to be implemented:
//!
//! - by the low-level layers of the FoxBox, including the adapters;
//! - by test suites and tools that need to simulate connected devices.
//!
//! In turn, this API is used to implement:
//!
//! - the public-facing REST and WebSocket API;
//! - the rules API (ThinkerBell).
//!
//!

use devices::*;
use requests::*;
use values::Value;

/// An error produced by one of the APIs in this module.
pub enum Error {
    /// There is no such node connected to the Foxbox, even indirectly.
    NoSuchNode(NodeId),

    /// There is no such service connected to the Foxbox, even indirectly.
    NoSuchService(ServiceId),

    /// Attempting to set a value with the wrong type
    TypeError,
}

/// An event during watching.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum WatchEvent {
    /// A new value is available.
    Value {
        /// The service that sent the value.
        from: ServiceId,

        /// The actual value.
        value: Value
    },

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// removed. Payload is the id of the device that was removed.
    InputRemoved(ServiceId),

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// added. Payload is the id of the device that was added.
    InputAdded(ServiceId),
}

/// The public API.
pub trait API {
    /// Get the metadata on nodes matching some conditions.
    ///
    /// A call to `API::get_nodes(vec![req1, req2, ...])` will return
    /// the metadata on all nodes matching _either_ `req1` or `req2`
    /// or ...
    ///
    /// # REST API
    ///
    /// `GET /api/v1/nodes`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to a `Vec<NodeRequest>`. See
    /// the implementation of `NodeRequest` for details.
    ///
    /// ### Example
    ///
    /// Request all doors in the entrance (tags `door`, `entrance`)
    /// that support output service `OpenClose`
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door"],
    ///   "inputs": [
    ///     {
    ///       "kind": {
    ///         "Exactly": {
    ///           "OpenClose": []
    ///         }
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    ///
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing an array of `Node`. See the implementation
    /// of `Node` for details.
    ///
    /// ### Example
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door", "somevendor"],
    ///   "id: "some-node-id",
    ///   "inputs": [],
    ///   "outputs": [
    ///     "tags": [...],
    ///     "id": "some-service-id",
    ///     "node": "some-node-id",
    ///     "last_seen": "some-date",
    ///     "mechanism": {
    ///       "Output":  {
    ///         "kind": {
    ///           "OnOff": []
    ///         },
    ///         "push": [5000],
    ///         "updated": "some-date",
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    fn get_nodes(&Vec<NodeRequest>) -> Vec<Node>;

    /// Label a set of nodes with a set of tags.
    ///
    /// A call to `API::put_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the nodes matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/nodes/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON string representing a number.
    fn put_node_tag(set: &Vec<NodeRequest>, tags: &Vec<String>) -> usize;

    /// Remove a set of tags from a set of nodes.
    ///
    /// A call to `API::delete_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the nodes matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/nodes/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_node_tag(set: &Vec<NodeRequest>, tags: String) -> usize;

    /// Get a list of inputs matching some conditions
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services`
    fn get_input_services(&Vec<InputRequest>) -> Vec<Service<Input>>;
    fn get_output_services(&Vec<OutputRequest>) -> Vec<Service<Output>>;

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```rust
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn put_input_tag(&Vec<InputRequest>, &Vec<String>) -> usize;
    fn put_output_tag(&Vec<OutputRequest>, &Vec<String>) -> usize;

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/services/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```rust
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_input_tag(&Vec<InputRequest>, &Vec<String>) -> usize;
    fn delete_output_tag(&Vec<InputRequest>, &Vec<String>) -> usize;

    /// Read the latest value from a set of services
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services/value`
    fn get_service_value(&Vec<InputRequest>) -> Vec<(ServiceId, Result<Value, Error>)>;

    /// Send one value to a set of services
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/value`
    fn put_service_value(&Vec<OutputRequest>, Value) -> Vec<(ServiceId, Result<(), Error>)>;

    /// Watch for any change
    ///
    /// # WebSocket API
    ///
    /// `/api/v1/services/watch`
    fn register_service_watch<F>(Vec<WatchOptions>, cb: F) -> Self::WatchGuard
        where F: FnMut(WatchEvent) + Send + 'static;

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard;
}

/// Options for watching changes in one or more services.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct WatchOptions {
    /// The set of inputs to watch. Note that the actual inputs in the
    /// set may change over time.
    source: InputRequest,

    /// If `true`, watch as new values become available.
    should_watch_values: bool,

    /// If `true`, watch as nodes are connected/disconnected.
    should_watch_topology: bool,
}

impl WatchOptions {
    pub fn new() -> Self {
        WatchOptions {
            source: InputRequest::new(),
            should_watch_values: false,
            should_watch_topology: false,
        }
    }

    /// Restrict to input services in a given set.
    ///
    /// Also note that the actual input services that are part of the
    /// set may change with time, for instance if devices are added
    /// ore removed.  The request _is live_, i.e. the service watch
    /// will continue watching any input services that match `req`.
    pub fn with_inputs(self, req: InputRequest) -> Self {
        WatchOptions {
            source: self.source.and(req),
            ..self
        }
    }

    pub fn with_watch_values(self, should: bool) -> Self {
        WatchOptions {
            should_watch_values: should,
            ..self
        }
    }

    pub fn with_watch_topology(self, should: bool) -> Self {
        WatchOptions {
            should_watch_topology: should,
            ..self
        }
    }
}
<|endoftext|>


<commit_before>
pub struct Task {
        id: int,
        todo: ~str,
        priority: char,
        finished: bool,
        raw_todo: ~str,
        create_date ~str,
        finish_date ~str,
        contexts: & 'static [~str],
        projects: & 'static [~str]
}

impl Task {
        pub fn to_str(&self) -> ~str {
                return format!("{:d} {:b} ({:c}) '{:s}' \"{:s}\"",
                                self.id, self.finished, self.priority,
                                self.todo, self.raw_todo)
        }

        pub fn create(text: ~str, id: int) -> Task {
                let mut task = Task{id: id, raw_todo: text.clone(), todo: text.clone(),
                                        finished: false, priority: '^',
                                        contexts: &[], projects: &[]};

                let mut todo = text.clone();

                if (todo.slice(0, 2) == "x ") {
                        task.finished = true;
                        todo = todo.slice(2, todo.len()).to_owned();
                }

                let mut chars = todo.chars().to_owned_vec();
                if (chars[0] == '(' && chars[2] == ')' &&
                    chars[1].is_uppercase() && chars[3] == ' ') {

                        task.priority = chars[1];
                        todo = todo.slice(4, todo.len()).to_owned();
                }

                chars = todo.chars().to_owned_vec();

                if (chars[10] == ' ' && chars[4] == '-' && chars[7] == '-') {
                        task.create_date = todo.slice(0, 10).to_owned();
                        todo = todo.slice(11, todo.len()).to_owned();
                }

                task.todo = todo;

                return task;
        }
}

#[test]
fn simple_todo_create_test() {
        let t = Task::create(~"some important task", 1);

        assert_eq!(t.id , 1);
        assert_eq!(t.priority , '^');
        assert_eq!(t.finished , false);
        assert_eq!(t.todo , ~"some important task");
        assert_eq!(t.raw_todo , ~"some important task");
}

#[test]
fn simple_todo_with_priority_test() {
        let t = Task::create(~"(A) some important task with priority", 1);

        assert_eq!(t.id , 1);
        assert_eq!(t.priority , 'A');
        assert_eq!(t.finished , false);
        assert_eq!(t.todo , ~"some important task with priority");
        assert_eq!(t.raw_todo , ~"(A) some important task with priority");

        let ts = Task::create(~"(a) some important task with priority", 1);

        assert_eq!(ts.id , 1);
        assert_eq!(ts.priority , '^');
        assert_eq!(ts.finished , false);
        assert_eq!(ts.todo , ~"(a) some important task with priority");
        assert_eq!(ts.raw_todo , ~"(a) some important task with priority");

}

#[test]
fn todo_to_str_test() {
        let t = Task::create(~"some important task", 1);

        assert_eq!(t.to_str(), ~"1 false (^) 'some important task' \"some important task\"")

        let x = Task::create(~"x some important task", 1);
        assert_eq!(x.to_str(), ~"1 true (^) 'some important task' \"x some important task\"")
}
<commit_msg>finished with dates<commit_after>
pub struct Task {
        id: int,
        todo: ~str,
        priority: char,
        finished: bool,
        raw_todo: ~str,
        create_date: ~str,
        finish_date: ~str,
        contexts: & 'static [~str],
        projects: & 'static [~str]
}

impl Task {
        pub fn to_str(&self) -> ~str {
                return format!("{:d} {:b} ({:c}) '{:s}' \"{:s}\"",
                                self.id, self.finished, self.priority,
                                self.todo, self.raw_todo)
        }

        pub fn create(text: ~str, id: int) -> Task {
                let mut task = Task{id: id, raw_todo: text.clone(), todo: text.clone(),
                                        finished: false, priority: '^',
                                        create_date: ~"", finish_date: ~"",
                                        contexts: &[], projects: &[]};

                let mut todo = text.clone();

                if (todo.slice(0, 2) == "x ") {
                        task.finished = true;
                        todo = todo.slice(2, todo.len()).to_owned();
                }

                let mut chars = todo.chars().to_owned_vec();
                if (chars[0] == '(' && chars[2] == ')' &&
                    chars[1].is_uppercase() && chars[3] == ' ') {

                        task.priority = chars[1];
                        todo = todo.slice(4, todo.len()).to_owned();
                }

                chars = todo.chars().to_owned_vec();

                if (chars[10] == ' ' && chars[4] == '-' && chars[7] == '-') {
                        task.create_date = todo.slice(0, 10).to_owned();
                        todo = todo.slice(11, todo.len()).to_owned();
                }

                task.todo = todo;

                return task;
        }
}

#[test]
fn simple_todo_create_test() {
        let t = Task::create(~"some important task", 1);

        assert_eq!(t.id , 1);
        assert_eq!(t.priority , '^');
        assert_eq!(t.finished , false);
        assert_eq!(t.todo , ~"some important task");
        assert_eq!(t.raw_todo , ~"some important task");
}

#[test]
fn simple_todo_with_priority_test() {
        let t = Task::create(~"(A) some important task with priority", 1);

        assert_eq!(t.id , 1);
        assert_eq!(t.priority , 'A');
        assert_eq!(t.finished , false);
        assert_eq!(t.todo , ~"some important task with priority");
        assert_eq!(t.raw_todo , ~"(A) some important task with priority");

        let ts = Task::create(~"(a) some important task with priority", 1);

        assert_eq!(ts.id , 1);
        assert_eq!(ts.priority , '^');
        assert_eq!(ts.finished , false);
        assert_eq!(ts.todo , ~"(a) some important task with priority");
        assert_eq!(ts.raw_todo , ~"(a) some important task with priority");

}

#[test]
fn simple_todo_with_date_test() {
        let t = Task::create(~"(A) 2014-03-02 some important task with priority", 1);

        assert_eq!(t.id , 1);
        assert_eq!(t.priority , 'A');
        assert_eq!(t.finished , false);
        assert_eq!(t.todo , ~"some important task with priority");
        assert_eq!(t.raw_todo , ~"(A) 2014-03-02 some important task with priority");
}

#[test]
fn todo_to_str_test() {
        let t = Task::create(~"some important task", 1);

        assert_eq!(t.to_str(), ~"1 false (^) 'some important task' \"some important task\"")

        let x = Task::create(~"x some important task", 1);
        assert_eq!(x.to_str(), ~"1 true (^) 'some important task' \"x some important task\"")
}
<|endoftext|>


<commit_before><commit_msg>Don't parse files in module completion<commit_after><|endoftext|>


<commit_before>use std::io;
use std::mem::swap;
use std::net::SocketAddr;
use std::collections::VecDeque;

use byteorder::{ByteOrder, LittleEndian};

use mio::tcp::TcpStream;
use mio::{TryWrite, TryRead, EventSet};

use super::super::messages::{RawMessage, MessageBuffer, HEADER_SIZE};

const MAX_MESSAGE_LEN: usize = 1024 * 1024; //1 MB

#[derive(Debug, PartialEq)]
pub struct MessageReader {
    raw: Vec<u8>,
    position: usize,
}

impl MessageReader {
    pub fn empty() -> MessageReader {
        MessageReader {
            raw: vec![0; HEADER_SIZE],
            position: 0,
        }
    }

    pub fn read_finished(&self) -> bool {
        self.position >= HEADER_SIZE && self.position == self.total_len()
    }

    pub fn actual_len(&self) -> usize {
        self.raw.len()
    }

    pub fn total_len(&self) -> usize {
        LittleEndian::read_u32(&self.raw[4..8]) as usize
    }

    pub fn allocate(&mut self) -> io::Result<()> {
        let size = self.total_len();
        if size > MAX_MESSAGE_LEN {
            Err(io::Error::new(io::ErrorKind::Other,
                               format!("Received message is too long: {}", size)))
        } else {
            self.raw.resize(size, 0);
            Ok(())
        }
    }

    pub fn into_raw(self) -> MessageBuffer {
        MessageBuffer::from_vec(self.raw)
    }

    pub fn read(&mut self, socket: &mut TcpStream) -> io::Result<Option<usize>> {
        // FIXME: we shouldn't read more than HEADER_SIZE or total_length()
        // TODO: read into growable Vec, not into [u8]
        if self.position == HEADER_SIZE && self.actual_len() == HEADER_SIZE {
            self.allocate()?;
        }
        let pos = self.position;
        let r = socket.try_read(&mut self.raw[pos..])?;
        if let Some(n) = r {
            self.position += n;
        }
        Ok(r)
    }
}

pub struct MessageWriter {
    queue: VecDeque<RawMessage>,
    position: usize,
}

impl MessageWriter {
    pub fn empty() -> MessageWriter {
        MessageWriter {
            queue: VecDeque::new(),
            position: 0,
        }
    }

    pub fn write(&mut self, socket: &mut TcpStream) -> io::Result<()> {
        // TODO: use try_write_buf
        while let Some(message) = self.queue.front().cloned() {
            let buf = message.as_ref().as_ref();
            if buf.len() > MAX_MESSAGE_LEN {
                self.queue.pop_front();
                return Err(io::Error::new(io::ErrorKind::Other,
                                          "Attempted to send too long message. It will be \
                                           dropped."));
            }
            match socket.try_write(&buf[self.position..])? {
                None | Some(0) => {
                    break;
                }
                Some(n) => {
                    self.position += n;
                    if n == message.len() {
                        self.queue.pop_front();
                        self.position = 0;
                    }
                }
            }
        }
        Ok(())
    }

    pub fn is_idle(&self) -> bool {
        self.queue.is_empty()
    }
}

pub trait Connection {
    fn socket(&self) -> &TcpStream;
    fn address(&self) -> &SocketAddr;
    fn interest(&self) -> EventSet;
}

pub struct IncomingConnection {
    socket: TcpStream,
    address: SocketAddr,
    reader: MessageReader,
}

pub struct OutgoingConnection {
    socket: TcpStream,
    address: SocketAddr,
    writer: MessageWriter,
}

impl IncomingConnection {
    pub fn new(socket: TcpStream, address: SocketAddr) -> IncomingConnection {
        IncomingConnection {
            socket: socket,
            address: address,

            reader: MessageReader::empty(),
        }
    }

    pub fn try_read(&mut self) -> io::Result<Option<MessageBuffer>> {
        // TODO: raw length == 0?
        // TODO: maximum raw length?
        loop {
            match self.reader.read(&mut self.socket)? {
                None | Some(0) => return Ok(None),
                Some(_) => {
                    if self.reader.read_finished() {
                        let mut raw = MessageReader::empty();
                        swap(&mut raw, &mut self.reader);
                        return Ok(Some(raw.into_raw()));
                    }
                }
            }
        }
    }
}

impl OutgoingConnection {
    pub fn new(socket: TcpStream, address: SocketAddr) -> OutgoingConnection {
        OutgoingConnection {
            socket: socket,
            address: address,
            writer: MessageWriter::empty(),
        }
    }

    pub fn try_write(&mut self) -> io::Result<()> {
        // TODO: reregister
        self.writer.write(&mut self.socket).or_else(|e| {
            match e.kind() {
                io::ErrorKind::WouldBlock |
                io::ErrorKind::WriteZero => {
                    warn!("Unable to write to socket {}, socket is blocked",
                          self.address);
                    Ok(())
                }
                _ => Err(e),
            }
        })
    }

    pub fn send(&mut self, message: RawMessage) -> io::Result<()> {
        // TODO: capacity overflow
        // TODO: reregister
        self.writer.queue.push_back(message);
        // TODO proper test that we can write immediately
        self.try_write()
    }

    pub fn is_idle(&self) -> bool {
        self.writer.is_idle()
    }

    pub fn writer_state(&self) -> (usize, usize) {
        let len = self.writer.queue.len();
        let bytes = if len > 0 {
            self.writer.queue[0].len() - self.writer.position
        } else {
            0
        };
        (len, bytes)
    }
}

impl Connection for IncomingConnection {
    fn socket(&self) -> &TcpStream {
        &self.socket
    }

    fn address(&self) -> &SocketAddr {
        &self.address
    }

    fn interest(&self) -> EventSet {
        EventSet::hup() | EventSet::error() | EventSet::readable()
    }
}
impl Connection for OutgoingConnection {
    fn socket(&self) -> &TcpStream {
        &self.socket
    }

    fn address(&self) -> &SocketAddr {
        &self.address
    }

    fn interest(&self) -> EventSet {
        // readable interest is needed to receive hup event on macos if socket closed by other side.
        let mut set = EventSet::readable() | EventSet::hup() | EventSet::error();
        if !self.is_idle() {
            set = set | EventSet::writable();
        }
        set
    }
}
<commit_msg>Warn about too long message instead drop<commit_after>use std::io;
use std::mem::swap;
use std::net::SocketAddr;
use std::collections::VecDeque;

use byteorder::{ByteOrder, LittleEndian};

use mio::tcp::TcpStream;
use mio::{TryWrite, TryRead, EventSet};

use super::super::messages::{RawMessage, MessageBuffer, HEADER_SIZE};

const MAX_MESSAGE_LEN: usize = 1024 * 1024; //1 MB

#[derive(Debug, PartialEq)]
pub struct MessageReader {
    raw: Vec<u8>,
    position: usize,
}

impl MessageReader {
    pub fn empty() -> MessageReader {
        MessageReader {
            raw: vec![0; HEADER_SIZE],
            position: 0,
        }
    }

    pub fn read_finished(&self) -> bool {
        self.position >= HEADER_SIZE && self.position == self.total_len()
    }

    pub fn actual_len(&self) -> usize {
        self.raw.len()
    }

    pub fn total_len(&self) -> usize {
        LittleEndian::read_u32(&self.raw[4..8]) as usize
    }

    pub fn allocate(&mut self) -> io::Result<()> {
        let size = self.total_len();
        if size > MAX_MESSAGE_LEN {
            Err(io::Error::new(io::ErrorKind::Other,
                               format!("Received message is too long: {}", size)))
        } else {
            self.raw.resize(size, 0);
            Ok(())
        }
    }

    pub fn into_raw(self) -> MessageBuffer {
        MessageBuffer::from_vec(self.raw)
    }

    pub fn read(&mut self, socket: &mut TcpStream) -> io::Result<Option<usize>> {
        // FIXME: we shouldn't read more than HEADER_SIZE or total_length()
        // TODO: read into growable Vec, not into [u8]
        if self.position == HEADER_SIZE && self.actual_len() == HEADER_SIZE {
            self.allocate()?;
        }
        let pos = self.position;
        let r = socket.try_read(&mut self.raw[pos..])?;
        if let Some(n) = r {
            self.position += n;
        }
        Ok(r)
    }
}

pub struct MessageWriter {
    queue: VecDeque<RawMessage>,
    position: usize,
}

impl MessageWriter {
    pub fn empty() -> MessageWriter {
        MessageWriter {
            queue: VecDeque::new(),
            position: 0,
        }
    }

    pub fn write(&mut self, socket: &mut TcpStream) -> io::Result<()> {
        // TODO: use try_write_buf
        while let Some(message) = self.queue.front().cloned() {
            let buf = message.as_ref().as_ref();
            if buf.len() > MAX_MESSAGE_LEN {
                error!("Attempted to send too long message. len={}kb", buf.len() / 1024);
            }
            match socket.try_write(&buf[self.position..])? {
                None | Some(0) => {
                    break;
                }
                Some(n) => {
                    self.position += n;
                    if n == message.len() {
                        self.queue.pop_front();
                        self.position = 0;
                    }
                }
            }
        }
        Ok(())
    }

    pub fn is_idle(&self) -> bool {
        self.queue.is_empty()
    }
}

pub trait Connection {
    fn socket(&self) -> &TcpStream;
    fn address(&self) -> &SocketAddr;
    fn interest(&self) -> EventSet;
}

pub struct IncomingConnection {
    socket: TcpStream,
    address: SocketAddr,
    reader: MessageReader,
}

pub struct OutgoingConnection {
    socket: TcpStream,
    address: SocketAddr,
    writer: MessageWriter,
}

impl IncomingConnection {
    pub fn new(socket: TcpStream, address: SocketAddr) -> IncomingConnection {
        IncomingConnection {
            socket: socket,
            address: address,

            reader: MessageReader::empty(),
        }
    }

    pub fn try_read(&mut self) -> io::Result<Option<MessageBuffer>> {
        // TODO: raw length == 0?
        // TODO: maximum raw length?
        loop {
            match self.reader.read(&mut self.socket)? {
                None | Some(0) => return Ok(None),
                Some(_) => {
                    if self.reader.read_finished() {
                        let mut raw = MessageReader::empty();
                        swap(&mut raw, &mut self.reader);
                        return Ok(Some(raw.into_raw()));
                    }
                }
            }
        }
    }
}

impl OutgoingConnection {
    pub fn new(socket: TcpStream, address: SocketAddr) -> OutgoingConnection {
        OutgoingConnection {
            socket: socket,
            address: address,
            writer: MessageWriter::empty(),
        }
    }

    pub fn try_write(&mut self) -> io::Result<()> {
        // TODO: reregister
        self.writer.write(&mut self.socket).or_else(|e| {
            match e.kind() {
                io::ErrorKind::WouldBlock |
                io::ErrorKind::WriteZero => {
                    warn!("Unable to write to socket {}, socket is blocked",
                          self.address);
                    Ok(())
                }
                _ => Err(e),
            }
        })
    }

    pub fn send(&mut self, message: RawMessage) -> io::Result<()> {
        // TODO: capacity overflow
        // TODO: reregister
        self.writer.queue.push_back(message);
        // TODO proper test that we can write immediately
        self.try_write()
    }

    pub fn is_idle(&self) -> bool {
        self.writer.is_idle()
    }

    pub fn writer_state(&self) -> (usize, usize) {
        let len = self.writer.queue.len();
        let bytes = if len > 0 {
            self.writer.queue[0].len() - self.writer.position
        } else {
            0
        };
        (len, bytes)
    }
}

impl Connection for IncomingConnection {
    fn socket(&self) -> &TcpStream {
        &self.socket
    }

    fn address(&self) -> &SocketAddr {
        &self.address
    }

    fn interest(&self) -> EventSet {
        EventSet::hup() | EventSet::error() | EventSet::readable()
    }
}
impl Connection for OutgoingConnection {
    fn socket(&self) -> &TcpStream {
        &self.socket
    }

    fn address(&self) -> &SocketAddr {
        &self.address
    }

    fn interest(&self) -> EventSet {
        // readable interest is needed to receive hup event on macos if socket closed by other side.
        let mut set = EventSet::readable() | EventSet::hup() | EventSet::error();
        if !self.is_idle() {
            set = set | EventSet::writable();
        }
        set
    }
}
<|endoftext|>


<commit_before>use {Token, SyntaxKind, TextUnit};
use super::{Event};
use super::super::is_insignificant;
use syntax_kinds::{L_CURLY, R_CURLY, ERROR};

pub struct Parser<'t> {
    text: &'t str,
    raw_tokens: &'t [Token],
    non_ws_tokens: Vec<(usize, TextUnit)>,

    pos: usize,
    events: Vec<Event>,

    curly_level: i32,
    curly_limit: Option<i32>,
}

impl<'t> Parser<'t> {
    pub(crate) fn new(text: &'t str, raw_tokens: &'t [Token]) -> Parser<'t> {
        let mut non_ws_tokens = Vec::new();
        let mut len = TextUnit::new(0);
        for (idx, &token) in raw_tokens.iter().enumerate() {
            if !is_insignificant(token.kind) {
                non_ws_tokens.push((idx, len))
            }
            len += token.len;
        }

        Parser {
            text,
            raw_tokens,
            non_ws_tokens,

            pos: 0,
            events: Vec::new(),
            curly_level: 0,
            curly_limit: None,
        }
    }

    pub(crate) fn into_events(self) -> Vec<Event> {
        assert!(self.is_eof());
        self.events
    }

    pub(crate) fn is_eof(&self) -> bool {
        if self.pos == self.non_ws_tokens.len() {
            return true
        }
        if let Some(limit) = self.curly_limit {
            let idx = self.non_ws_tokens[self.pos].0;
            return limit == self.curly_level && self.raw_tokens[idx].kind == R_CURLY;
        }
        false
    }

    pub(crate) fn start(&mut self, kind: SyntaxKind) {
        self.event(Event::Start { kind });
    }

    pub(crate) fn finish(&mut self) {
        self.event(Event::Finish);
    }

    pub(crate) fn error<'p>(&'p mut self) -> ErrorBuilder<'p, 't> {
        ErrorBuilder::new(self)
    }

    pub(crate) fn current(&self) -> Option<SyntaxKind> {
        if self.is_eof() {
            return None;
        }
        let idx = self.non_ws_tokens[self.pos].0;
        Some(self.raw_tokens[idx].kind)
    }

    pub(crate) fn bump(&mut self) -> Option<SyntaxKind> {
        let kind = self.current()?;
        match kind {
            L_CURLY => self.curly_level += 1,
            R_CURLY => self.curly_level -= 1,
            _ => (),
        }
        self.pos += 1;
        self.event(Event::Token { kind, n_raw_tokens: 1 });
        Some(kind)
    }

    pub(crate) fn lookahead(&self, kinds: &[SyntaxKind]) -> bool {
        if self.non_ws_tokens[self.pos..].len() < kinds.len() {
            return false
        }
        kinds.iter().zip(self.non_ws_tokens[self.pos..].iter())
            .all(|(&k1, &(idx, _))| k1 == self.raw_tokens[idx].kind)
    }

    pub(crate) fn curly_block<F: FnOnce(&mut Parser)>(&mut self, f: F) -> bool {
        let old_level = self.curly_level;
        let old_limit = self.curly_limit;
        if !self.expect(L_CURLY) {
            return false
        }
        self.curly_limit = Some(self.curly_level);
        f(self);
        assert!(self.curly_level > old_level);
        self.curly_limit = old_limit;
        if !self.expect(R_CURLY) {
            self.start(ERROR);
            while self.curly_level > old_level {
                if self.bump().is_none() {
                    break;
                }
            }
            self.finish();
        }
        true
    }

    fn event(&mut self, event: Event) {
        self.events.push(event)
    }
}

pub(crate) struct ErrorBuilder<'p, 't: 'p> {
    message: Option<String>,
    parser: &'p mut Parser<'t>
}

impl<'t, 'p> ErrorBuilder<'p, 't> {
    fn new(parser: &'p mut Parser<'t>) -> Self {
        ErrorBuilder { message: None, parser }
    }

    pub fn message<M: Into<String>>(mut self, m: M) -> Self {
        self.message = Some(m.into());
        self
    }

    pub fn emit(self) {
        let message = self.message.expect("Error message not set");
        self.parser.event(Event::Error { message });
    }
}
<commit_msg>Simiplify<commit_after>use {Token, SyntaxKind, TextUnit};
use super::{Event};
use super::super::is_insignificant;
use syntax_kinds::{L_CURLY, R_CURLY, ERROR};

pub struct Parser<'t> {
    text: &'t str,
    non_ws_tokens: Vec<(Token, TextUnit)>,

    pos: usize,
    events: Vec<Event>,

    curly_level: i32,
    curly_limit: Option<i32>,
}

impl<'t> Parser<'t> {
    pub(crate) fn new(text: &'t str, raw_tokens: &'t [Token]) -> Parser<'t> {
        let mut non_ws_tokens = Vec::new();
        let mut len = TextUnit::new(0);
        for &token in raw_tokens.iter() {
            if !is_insignificant(token.kind) {
                non_ws_tokens.push((token, len))
            }
            len += token.len;
        }

        Parser {
            text,
            non_ws_tokens,

            pos: 0,
            events: Vec::new(),
            curly_level: 0,
            curly_limit: None,
        }
    }

    pub(crate) fn into_events(self) -> Vec<Event> {
        assert!(self.is_eof());
        self.events
    }

    pub(crate) fn is_eof(&self) -> bool {
        if self.pos == self.non_ws_tokens.len() {
            return true
        }
        if let Some(limit) = self.curly_limit {
            let token = self.non_ws_tokens[self.pos].0;
            return limit == self.curly_level && token.kind == R_CURLY;
        }
        false
    }

    pub(crate) fn start(&mut self, kind: SyntaxKind) {
        self.event(Event::Start { kind });
    }

    pub(crate) fn finish(&mut self) {
        self.event(Event::Finish);
    }

    pub(crate) fn error<'p>(&'p mut self) -> ErrorBuilder<'p, 't> {
        ErrorBuilder::new(self)
    }

    pub(crate) fn current(&self) -> Option<SyntaxKind> {
        if self.is_eof() {
            return None;
        }
        let token = self.non_ws_tokens[self.pos].0;
        Some(token.kind)
    }

    pub(crate) fn bump(&mut self) -> Option<SyntaxKind> {
        let kind = self.current()?;
        match kind {
            L_CURLY => self.curly_level += 1,
            R_CURLY => self.curly_level -= 1,
            _ => (),
        }
        self.pos += 1;
        self.event(Event::Token { kind, n_raw_tokens: 1 });
        Some(kind)
    }

    pub(crate) fn lookahead(&self, kinds: &[SyntaxKind]) -> bool {
        if self.non_ws_tokens[self.pos..].len() < kinds.len() {
            return false
        }
        kinds.iter().zip(self.non_ws_tokens[self.pos..].iter().map(|&(t, _)| t.kind))
            .all(|(&k1, k2)| k1 == k2)
    }

    pub(crate) fn curly_block<F: FnOnce(&mut Parser)>(&mut self, f: F) -> bool {
        let old_level = self.curly_level;
        let old_limit = self.curly_limit;
        if !self.expect(L_CURLY) {
            return false
        }
        self.curly_limit = Some(self.curly_level);
        f(self);
        assert!(self.curly_level > old_level);
        self.curly_limit = old_limit;
        if !self.expect(R_CURLY) {
            self.start(ERROR);
            while self.curly_level > old_level {
                if self.bump().is_none() {
                    break;
                }
            }
            self.finish();
        }
        true
    }

    fn event(&mut self, event: Event) {
        self.events.push(event)
    }
}

pub(crate) struct ErrorBuilder<'p, 't: 'p> {
    message: Option<String>,
    parser: &'p mut Parser<'t>
}

impl<'t, 'p> ErrorBuilder<'p, 't> {
    fn new(parser: &'p mut Parser<'t>) -> Self {
        ErrorBuilder { message: None, parser }
    }

    pub fn message<M: Into<String>>(mut self, m: M) -> Self {
        self.message = Some(m.into());
        self
    }

    pub fn emit(self) {
        let message = self.message.expect("Error message not set");
        self.parser.event(Event::Error { message });
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! digital ocean metadata fetcher

use retry;
use metadata;
use network;
use ipnetwork;
use ipnetwork::{IpNetwork,Ipv4Network,Ipv6Network};
use pnet::util::MacAddr;

use std::str::FromStr;
use std::net::{IpAddr,Ipv4Addr,Ipv6Addr};
use std::collections::HashMap;

use errors::*;

#[derive(Clone,Deserialize)]
struct Address {
    ip_address: IpAddr,
    netmask: Option<IpAddr>,
    cidr: Option<u8>,
    gateway: IpAddr,
}

#[derive(Clone,Deserialize)]
struct Interface {
    ipv4: Option<Address>,
    ipv6: Option<Address>,
    anchor_ipv4: Option<Address>,
    mac: String,
    #[serde(rename = "type")]
    type_name: String,
}

#[derive(Clone,Deserialize)]
struct Interfaces {
    public: Option<Vec<Interface>>,
    private: Option<Vec<Interface>>,
}

#[derive(Clone,Deserialize)]
struct DNS {
    nameservers: Vec<IpAddr>
}

#[derive(Clone,Deserialize)]
struct Metadata {
    hostname: String,
    interfaces: Interfaces,
    public_keys: Vec<String>,
    region: String,
    dns: DNS,
}

pub fn fetch_metadata() -> Result<metadata::Metadata> {
    let client = retry::Client::new()?;
    let data: Metadata = client.get(retry::Json, "http://169.254.169.254/metadata/v1.json".to_owned()).send()?
        .ok_or("not found")?;

    let attrs = parse_attrs(&data)?;
    let interfaces = parse_network(&data)?;

    let mut m = metadata::Metadata::builder()
        .add_ssh_keys(data.public_keys)?
        .set_hostname(data.hostname);

    for (key,val) in attrs {
        m = m.add_attribute(key,val);
    }
    for iface in interfaces {
        m = m.add_network_interface(iface);
    }
    Ok(m.build())
}

fn parse_attrs(data: &Metadata) -> Result<Vec<(String,String)>> {
    let mut attrs = Vec::new();

    attrs.push(("DIGITALOCEAN_HOSTNAME".to_owned(), data.hostname.clone()));
    attrs.push(("DIGITALOCEAN_REGION".to_owned(), data.region.clone()));

    let mut public_counter = 0;
    let mut private_counter = 0;
    if let Some(ifaces) = data.interfaces.public.clone() {
        for a in ifaces {
            if a.ipv4.is_some() {
                attrs.push((
                    format!("DIGITALOCEAN_IPV4_PUBLIC_{}", public_counter),
                    format!("{}", a.ipv4.unwrap().ip_address)
                ));
            }
            if a.ipv6.is_some() {
                attrs.push((
                    format!("DIGITALOCEAN_IPV6_PUBLIC_{}", public_counter),
                    format!("{}", a.ipv6.unwrap().ip_address)
                ));
            }
            if a.anchor_ipv4.is_some() {
                attrs.push((
                    format!("DIGITALOCEAN_IPV4_ANCHOR_{}", public_counter),
                    format!("{}", a.anchor_ipv4.unwrap().ip_address)
                ));
            }
            public_counter += 1;
        }
    }
    if let Some(ifaces) = data.interfaces.private.clone() {
        for a in ifaces {
            if a.ipv4.is_some() {
                attrs.push((
                    format!("DIGITALOCEAN_IPV4_PRIVATE_{}", public_counter),
                    format!("{}", a.ipv4.unwrap().ip_address)
                ));
            }
            if a.ipv6.is_some() {
                attrs.push((
                    format!("DIGITALOCEAN_IPV6_PRIVATE_{}", private_counter),
                    format!("{}", a.ipv6.unwrap().ip_address)
                ));
            }
            private_counter += 1;
        }
    }
    Ok(attrs)
}

fn parse_network(data: &Metadata) -> Result<Vec<network::Interface>> {
    let mut interfaces = Vec::new();
    if let Some(ifaces) = data.interfaces.public.clone() {
        interfaces.extend(parse_interfaces(data, ifaces)?);
    }
    if let Some(ifaces) = data.interfaces.private.clone() {
        interfaces.extend(parse_interfaces(data, ifaces)?);
    }
    Ok(interfaces)
}

fn parse_interfaces(data: &Metadata, interfaces: Vec<Interface>) -> Result<Vec<network::Interface>> {
    let mut iface_config_map: HashMap<MacAddr,network::Interface> = HashMap::new();
    for iface in interfaces {
        let mac = MacAddr::from_str(&iface.mac)
            .map_err(|e| Error::from(format!("{:?}", e)))
            .chain_err(|| "failed to parse mac address")?;
        let (mut addrs, mut routes) = parse_interface(&iface)?;

        if let Some(existing_iface) = iface_config_map.get_mut(&mac) {
            addrs.extend(existing_iface.ip_addresses.clone());
            routes.extend(existing_iface.routes.clone());
        }
        iface_config_map.insert(mac, network::Interface{
            mac_address: Some(mac),
            nameservers: data.dns.nameservers.clone(),
            ip_addresses: addrs,
            routes: routes,
            bond: None,
            name: None,
            priority: None,
        });
    }
    let mut iface_configs = Vec::new();
    for i in iface_config_map.values() {
        iface_configs.push(i.clone());
    }
    Ok(iface_configs)
}

fn parse_interface(interface: &Interface) -> Result<(Vec<IpNetwork>,Vec<network::NetworkRoute>)> {
    let mut addrs = Vec::new();
    let mut routes = Vec::new();

    if interface.ipv4.is_some() {
        let netmask = interface.clone().ipv4.unwrap().netmask
            .ok_or("missing netmask for ipv4 address")?;
        let prefix = ipnetwork::ip_mask_to_prefix(netmask)
            .chain_err(|| "invalid network mask")?;
        let a = match interface.clone().ipv4.unwrap().ip_address {
            IpAddr::V4(a) => Some(a),
            IpAddr::V6(_) => None,
        }.ok_or("ipv6 address in ipv4 field")?;
        let net = IpNetwork::V4(Ipv4Network::new(a, prefix)
            .chain_err(|| "invalid ip address or prefix")?);
        addrs.push(net);
        routes.push(network::NetworkRoute{
            destination: net,
            gateway: interface.clone().ipv4.unwrap().gateway,
        });

        if interface.type_name == "public" {
            routes.push(network::NetworkRoute{
                destination: IpNetwork::V4(Ipv4Network::new(Ipv4Addr::new(0,0,0,0),0)
                                    .chain_err(|| "invalid ip address or prefix")?),
                gateway: interface.clone().ipv4.unwrap().gateway,
            });
        }
    }
    if interface.ipv6.is_some() {
        let cidr = interface.clone().ipv6.unwrap().cidr
            .ok_or("missing cidr for ipv6 address")?;
        let a = match interface.clone().ipv6.unwrap().ip_address {
            IpAddr::V4(_) => None,
            IpAddr::V6(a) => Some(a),
        }.ok_or("ipv4 address in ipv6 field")?;
        let net = IpNetwork::V6(Ipv6Network::new(a, cidr)
            .chain_err(|| "invalid ip address or prefix")?);
        addrs.push(net);
        routes.push(network::NetworkRoute{
            destination: net,
            gateway: interface.clone().ipv6.unwrap().gateway,
        });
        if interface.type_name == "public" {
            routes.push(network::NetworkRoute{
                destination: IpNetwork::V6(Ipv6Network::new(Ipv6Addr::new(0,0,0,0,0,0,0,0),0)
                                    .chain_err(|| "invalid ip address or prefix")?),
                gateway: interface.clone().ipv6.unwrap().gateway,
            });
        }
    }
    if interface.anchor_ipv4.is_some() {
        let netmask = interface.clone().anchor_ipv4.unwrap().netmask
            .ok_or("missing netmask for anchor ipv4 address")?;
        let prefix = ipnetwork::ip_mask_to_prefix(netmask)
            .chain_err(|| "invalid network mask")?;
        let a = match interface.clone().anchor_ipv4.unwrap().ip_address {
            IpAddr::V4(a) => Some(a),
            IpAddr::V6(_) => None,
        }.ok_or("ipv6 address in ipv4 field")?;
        let net = IpNetwork::V4(Ipv4Network::new(a, prefix)
            .chain_err(|| "invalid ip address or prefix")?);
        addrs.push(net);
        routes.push(network::NetworkRoute{
            destination: net,
            gateway: interface.clone().anchor_ipv4.unwrap().gateway,
        });
    }
    Ok((addrs,routes))
}
<commit_msg>providers/digitalocean: private ip index bug fix<commit_after>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! digital ocean metadata fetcher

use retry;
use metadata;
use network;
use ipnetwork;
use ipnetwork::{IpNetwork,Ipv4Network,Ipv6Network};
use pnet::util::MacAddr;

use std::str::FromStr;
use std::net::{IpAddr,Ipv4Addr,Ipv6Addr};
use std::collections::HashMap;

use errors::*;

#[derive(Clone,Deserialize)]
struct Address {
    ip_address: IpAddr,
    netmask: Option<IpAddr>,
    cidr: Option<u8>,
    gateway: IpAddr,
}

#[derive(Clone,Deserialize)]
struct Interface {
    ipv4: Option<Address>,
    ipv6: Option<Address>,
    anchor_ipv4: Option<Address>,
    mac: String,
    #[serde(rename = "type")]
    type_name: String,
}

#[derive(Clone,Deserialize)]
struct Interfaces {
    public: Option<Vec<Interface>>,
    private: Option<Vec<Interface>>,
}

#[derive(Clone,Deserialize)]
struct DNS {
    nameservers: Vec<IpAddr>
}

#[derive(Clone,Deserialize)]
struct Metadata {
    hostname: String,
    interfaces: Interfaces,
    public_keys: Vec<String>,
    region: String,
    dns: DNS,
}

pub fn fetch_metadata() -> Result<metadata::Metadata> {
    let client = retry::Client::new()?;
    let data: Metadata = client.get(retry::Json, "http://169.254.169.254/metadata/v1.json".to_owned()).send()?
        .ok_or("not found")?;

    let attrs = parse_attrs(&data)?;
    let interfaces = parse_network(&data)?;

    let mut m = metadata::Metadata::builder()
        .add_ssh_keys(data.public_keys)?
        .set_hostname(data.hostname);

    for (key,val) in attrs {
        m = m.add_attribute(key,val);
    }
    for iface in interfaces {
        m = m.add_network_interface(iface);
    }
    Ok(m.build())
}

fn parse_attrs(data: &Metadata) -> Result<Vec<(String,String)>> {
    let mut attrs = Vec::new();

    attrs.push(("DIGITALOCEAN_HOSTNAME".to_owned(), data.hostname.clone()));
    attrs.push(("DIGITALOCEAN_REGION".to_owned(), data.region.clone()));

    let mut public_counter = 0;
    let mut private_counter = 0;
    if let Some(ifaces) = data.interfaces.public.clone() {
        for a in ifaces {
            if a.ipv4.is_some() {
                attrs.push((
                    format!("DIGITALOCEAN_IPV4_PUBLIC_{}", public_counter),
                    format!("{}", a.ipv4.unwrap().ip_address)
                ));
            }
            if a.ipv6.is_some() {
                attrs.push((
                    format!("DIGITALOCEAN_IPV6_PUBLIC_{}", public_counter),
                    format!("{}", a.ipv6.unwrap().ip_address)
                ));
            }
            if a.anchor_ipv4.is_some() {
                attrs.push((
                    format!("DIGITALOCEAN_IPV4_ANCHOR_{}", public_counter),
                    format!("{}", a.anchor_ipv4.unwrap().ip_address)
                ));
            }
            public_counter += 1;
        }
    }
    if let Some(ifaces) = data.interfaces.private.clone() {
        for a in ifaces {
            if a.ipv4.is_some() {
                attrs.push((
                    format!("DIGITALOCEAN_IPV4_PRIVATE_{}", private_counter),
                    format!("{}", a.ipv4.unwrap().ip_address)
                ));
            }
            if a.ipv6.is_some() {
                attrs.push((
                    format!("DIGITALOCEAN_IPV6_PRIVATE_{}", private_counter),
                    format!("{}", a.ipv6.unwrap().ip_address)
                ));
            }
            private_counter += 1;
        }
    }
    Ok(attrs)
}

fn parse_network(data: &Metadata) -> Result<Vec<network::Interface>> {
    let mut interfaces = Vec::new();
    if let Some(ifaces) = data.interfaces.public.clone() {
        interfaces.extend(parse_interfaces(data, ifaces)?);
    }
    if let Some(ifaces) = data.interfaces.private.clone() {
        interfaces.extend(parse_interfaces(data, ifaces)?);
    }
    Ok(interfaces)
}

fn parse_interfaces(data: &Metadata, interfaces: Vec<Interface>) -> Result<Vec<network::Interface>> {
    let mut iface_config_map: HashMap<MacAddr,network::Interface> = HashMap::new();
    for iface in interfaces {
        let mac = MacAddr::from_str(&iface.mac)
            .map_err(|e| Error::from(format!("{:?}", e)))
            .chain_err(|| "failed to parse mac address")?;
        let (mut addrs, mut routes) = parse_interface(&iface)?;

        if let Some(existing_iface) = iface_config_map.get_mut(&mac) {
            addrs.extend(existing_iface.ip_addresses.clone());
            routes.extend(existing_iface.routes.clone());
        }
        iface_config_map.insert(mac, network::Interface{
            mac_address: Some(mac),
            nameservers: data.dns.nameservers.clone(),
            ip_addresses: addrs,
            routes: routes,
            bond: None,
            name: None,
            priority: None,
        });
    }
    let mut iface_configs = Vec::new();
    for i in iface_config_map.values() {
        iface_configs.push(i.clone());
    }
    Ok(iface_configs)
}

fn parse_interface(interface: &Interface) -> Result<(Vec<IpNetwork>,Vec<network::NetworkRoute>)> {
    let mut addrs = Vec::new();
    let mut routes = Vec::new();

    if interface.ipv4.is_some() {
        let netmask = interface.clone().ipv4.unwrap().netmask
            .ok_or("missing netmask for ipv4 address")?;
        let prefix = ipnetwork::ip_mask_to_prefix(netmask)
            .chain_err(|| "invalid network mask")?;
        let a = match interface.clone().ipv4.unwrap().ip_address {
            IpAddr::V4(a) => Some(a),
            IpAddr::V6(_) => None,
        }.ok_or("ipv6 address in ipv4 field")?;
        let net = IpNetwork::V4(Ipv4Network::new(a, prefix)
            .chain_err(|| "invalid ip address or prefix")?);
        addrs.push(net);
        routes.push(network::NetworkRoute{
            destination: net,
            gateway: interface.clone().ipv4.unwrap().gateway,
        });

        if interface.type_name == "public" {
            routes.push(network::NetworkRoute{
                destination: IpNetwork::V4(Ipv4Network::new(Ipv4Addr::new(0,0,0,0),0)
                                    .chain_err(|| "invalid ip address or prefix")?),
                gateway: interface.clone().ipv4.unwrap().gateway,
            });
        }
    }
    if interface.ipv6.is_some() {
        let cidr = interface.clone().ipv6.unwrap().cidr
            .ok_or("missing cidr for ipv6 address")?;
        let a = match interface.clone().ipv6.unwrap().ip_address {
            IpAddr::V4(_) => None,
            IpAddr::V6(a) => Some(a),
        }.ok_or("ipv4 address in ipv6 field")?;
        let net = IpNetwork::V6(Ipv6Network::new(a, cidr)
            .chain_err(|| "invalid ip address or prefix")?);
        addrs.push(net);
        routes.push(network::NetworkRoute{
            destination: net,
            gateway: interface.clone().ipv6.unwrap().gateway,
        });
        if interface.type_name == "public" {
            routes.push(network::NetworkRoute{
                destination: IpNetwork::V6(Ipv6Network::new(Ipv6Addr::new(0,0,0,0,0,0,0,0),0)
                                    .chain_err(|| "invalid ip address or prefix")?),
                gateway: interface.clone().ipv6.unwrap().gateway,
            });
        }
    }
    if interface.anchor_ipv4.is_some() {
        let netmask = interface.clone().anchor_ipv4.unwrap().netmask
            .ok_or("missing netmask for anchor ipv4 address")?;
        let prefix = ipnetwork::ip_mask_to_prefix(netmask)
            .chain_err(|| "invalid network mask")?;
        let a = match interface.clone().anchor_ipv4.unwrap().ip_address {
            IpAddr::V4(a) => Some(a),
            IpAddr::V6(_) => None,
        }.ok_or("ipv6 address in ipv4 field")?;
        let net = IpNetwork::V4(Ipv4Network::new(a, prefix)
            .chain_err(|| "invalid ip address or prefix")?);
        addrs.push(net);
        routes.push(network::NetworkRoute{
            destination: net,
            gateway: interface.clone().anchor_ipv4.unwrap().gateway,
        });
    }
    Ok((addrs,routes))
}
<|endoftext|>