<commit_before>use super::super::{Device, RawDevice, RawSurface, Surface};
use super::Error;

use drm::control::{connector, crtc, framebuffer, Device as ControlDevice, Mode};
use failure::ResultExt;
use gbm::{self, BufferObject, BufferObjectFlags, Format as GbmFormat, SurfaceBufferHandle};
use image::{ImageBuffer, Rgba};

use std::cell::{Cell, RefCell};
use std::rc::Rc;

use crate::backend::graphics::CursorBackend;

pub(super) struct GbmSurfaceInternal<D: RawDevice + 'static> {
    pub(super) dev: Rc<RefCell<gbm::Device<D>>>,
    pub(super) surface: RefCell<gbm::Surface<framebuffer::Handle>>,
    pub(super) crtc: <D as Device>::Surface,
    pub(super) cursor: Cell<(BufferObject<()>, (u32, u32))>,
    pub(super) current_frame_buffer: Cell<Option<framebuffer::Handle>>,
    pub(super) front_buffer: Cell<Option<SurfaceBufferHandle<framebuffer::Handle>>>,
    pub(super) next_buffer: Cell<Option<SurfaceBufferHandle<framebuffer::Handle>>>,
    pub(super) recreated: Cell<bool>,
    pub(super) logger: ::slog::Logger,
}

impl<D: RawDevice + 'static> GbmSurfaceInternal<D> {
    pub(super) fn unlock_buffer(&self) {
        // after the page swap is finished we need to release the rendered buffer.
        // this is called from the PageFlipHandler
        trace!(self.logger, "Releasing old front buffer");
        self.front_buffer.set(self.next_buffer.replace(None));
        // drop and release the old buffer
    }

    pub unsafe fn page_flip(&self) -> Result<(), Error<<<D as Device>::Surface as Surface>::Error>> {
        let res = {
            let nb = self.next_buffer.take();
            let res = nb.is_some();
            self.next_buffer.set(nb);
            res
        };
        if res {
            // We cannot call lock_front_buffer anymore without releasing the previous buffer, which will happen when the page flip is done
            warn!(self.logger, "Tried to swap with an already queued flip");
            return Err(Error::FrontBuffersExhausted);
        }

        // supporting only one buffer would cause a lot of inconvinience and
        // would most likely result in a lot of flickering.
        // neither weston, wlc or wlroots bother with that as well.
        // so we just assume we got at least two buffers to do flipping.
        let mut next_bo = self
            .surface
            .borrow()
            .lock_front_buffer()
            .map_err(|_| Error::FrontBufferLockFailed)?;

        // create a framebuffer if the front buffer does not have one already
        // (they are reused by gbm)
        let maybe_fb = next_bo
            .userdata()
            .map_err(|_| Error::InvalidInternalState)?
            .cloned();
        let fb = if let Some(info) = maybe_fb {
            info
        } else {
            let fb = self
                .crtc
                .add_planar_framebuffer(&*next_bo, &[0; 4], 0)
                .compat()
                .map_err(Error::FramebufferCreationFailed)?;
            next_bo.set_userdata(fb).unwrap();
            fb
        };
        self.next_buffer.set(Some(next_bo));

        if self.recreated.get() {
            debug!(self.logger, "Commiting new state");
            self.crtc.commit(fb).map_err(Error::Underlying)?;
            self.recreated.set(false);
        } else {
            trace!(self.logger, "Queueing Page flip");
            RawSurface::page_flip(&self.crtc, fb).map_err(Error::Underlying)?;
        }

        self.current_frame_buffer.set(Some(fb));

        Ok(())
    }

    pub fn recreate(&self) -> Result<(), Error<<<D as Device>::Surface as Surface>::Error>> {
        let (w, h) = self.pending_mode().size();

        // Recreate the surface and the related resources to match the new
        // resolution.
        debug!(self.logger, "(Re-)Initializing surface (with mode: {}:{})", w, h);
        let surface = self
            .dev
            .borrow_mut()
            .create_surface(
                w as u32,
                h as u32,
                GbmFormat::XRGB8888,
                BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING,
            )
            .map_err(Error::SurfaceCreationFailed)?;

        // Clean up buffers
        self.clear_framebuffers();

        // Drop the old surface after cleanup
        *self.surface.borrow_mut() = surface;

        self.recreated.set(true);

        Ok(())
    }

    pub fn clear_framebuffers(&self) {
        if let Some(Ok(Some(fb))) = self.next_buffer.take().map(|mut bo| bo.take_userdata()) {
            if let Err(err) = self.crtc.destroy_framebuffer(fb) {
                warn!(
                    self.logger,
                    "Error releasing old back_buffer framebuffer: {:?}", err
                );
            }
        }

        if let Some(Ok(Some(fb))) = self.front_buffer.take().map(|mut bo| bo.take_userdata()) {
            if let Err(err) = self.crtc.destroy_framebuffer(fb) {
                warn!(
                    self.logger,
                    "Error releasing old front_buffer framebuffer: {:?}", err
                );
            }
        }
    }
}

impl<D: RawDevice + 'static> Surface for GbmSurfaceInternal<D> {
    type Connectors = <<D as Device>::Surface as Surface>::Connectors;
    type Error = Error<<<D as Device>::Surface as Surface>::Error>;

    fn crtc(&self) -> crtc::Handle {
        self.crtc.crtc()
    }

    fn current_connectors(&self) -> Self::Connectors {
        self.crtc.current_connectors()
    }

    fn pending_connectors(&self) -> Self::Connectors {
        self.crtc.pending_connectors()
    }

    fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
        self.crtc.add_connector(connector).map_err(Error::Underlying)
    }

    fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
        self.crtc.remove_connector(connector).map_err(Error::Underlying)
    }

    fn set_connectors(&self, connectors: &[connector::Handle]) -> Result<(), Self::Error> {
        self.crtc.set_connectors(connectors).map_err(Error::Underlying)
    }

    fn current_mode(&self) -> Mode {
        self.crtc.current_mode()
    }

    fn pending_mode(&self) -> Mode {
        self.crtc.pending_mode()
    }

    fn use_mode(&self, mode: Mode) -> Result<(), Self::Error> {
        self.crtc.use_mode(mode).map_err(Error::Underlying)
    }
}

#[cfg(feature = "backend_drm")]
impl<D: RawDevice + 'static> CursorBackend for GbmSurfaceInternal<D>
where
    <D as RawDevice>::Surface: CursorBackend<CursorFormat = dyn drm::buffer::Buffer>,
    <<D as RawDevice>::Surface as CursorBackend>::Error: ::std::error::Error + Send,
{
    type CursorFormat = ImageBuffer<Rgba<u8>, Vec<u8>>;
    type Error = Error<<<D as Device>::Surface as CursorBackend>::Error>;

    fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), Self::Error> {
        self.crtc.set_cursor_position(x, y).map_err(Error::Underlying)
    }

    fn set_cursor_representation(
        &self,
        buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>,
        hotspot: (u32, u32),
    ) -> Result<(), Self::Error> {
        let (w, h) = buffer.dimensions();
        debug!(self.logger, "Importing cursor");

        // import the cursor into a buffer we can render
        let mut cursor = self
            .dev
            .borrow_mut()
            .create_buffer_object(
                w,
                h,
                GbmFormat::ARGB8888,
                BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
            )
            .map_err(Error::BufferCreationFailed)?;

        cursor
            .write(&**buffer)
            .map_err(|_| Error::DeviceDestroyed)?
            .map_err(Error::BufferWriteFailed)?;

        trace!(self.logger, "Setting the new imported cursor");

        self.crtc
            .set_cursor_representation(&cursor, hotspot)
            .map_err(Error::Underlying)?;

        // and store it
        self.cursor.set((cursor, hotspot));
        Ok(())
    }
}

impl<D: RawDevice + 'static> Drop for GbmSurfaceInternal<D> {
    fn drop(&mut self) {
        // Drop framebuffers attached to the userdata of the gbm surface buffers.
        // (They don't implement drop, as they need the device)
        self.clear_framebuffers();
    }
}

/// Gbm surface for rendering
pub struct GbmSurface<D: RawDevice + 'static>(pub(super) Rc<GbmSurfaceInternal<D>>);

impl<D: RawDevice + 'static> GbmSurface<D> {
    /// Flips the underlying buffers.
    ///
    /// The surface will report being already flipped until the matching event
    /// was processed either by calling [`Device::process_events`] manually after the flip
    /// (bad idea performance-wise) or by binding the device to an event-loop by using
    /// [`device_bind`](::backend::drm::device_bind).
    ///
    /// *Note*: This might trigger a full modeset on the underlying device,
    /// potentially causing some flickering. In that case this operation is
    /// blocking until the crtc is in the desired state.
    ///
    /// # Safety
    ///
    /// When used in conjunction with an EGL context, this must be called exactly once
    /// after page-flipping the associated context.
    pub unsafe fn page_flip(&self) -> ::std::result::Result<(), <Self as Surface>::Error> {
        self.0.page_flip()
    }

    /// Recreate underlying gbm resources.
    ///
    /// This recreates the gbm surfaces resources, which might be needed after e.g.
    /// calling [`Surface::use_mode`](Surface::use_mode).
    /// You may check if your [`GbmSurface`] needs recreation through
    /// [`needs_recreation`](GbmSurface::needs_recreation).
    pub fn recreate(&self) -> Result<(), <Self as Surface>::Error> {
        self.0.recreate()
    }

    /// Check if underlying gbm resources need to be recreated.
    pub fn needs_recreation(&self) -> bool {
        self.0.crtc.commit_pending()
    }
}

impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
    type Connectors = <<D as Device>::Surface as Surface>::Connectors;
    type Error = Error<<<D as Device>::Surface as Surface>::Error>;

    fn crtc(&self) -> crtc::Handle {
        self.0.crtc()
    }

    fn current_connectors(&self) -> Self::Connectors {
        self.0.current_connectors()
    }

    fn pending_connectors(&self) -> Self::Connectors {
        self.0.pending_connectors()
    }

    fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
        self.0.add_connector(connector)
    }

    fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
        self.0.remove_connector(connector)
    }

    fn set_connectors(&self, connectors: &[connector::Handle]) -> Result<(), Self::Error> {
        self.0.set_connectors(connectors)
    }

    fn current_mode(&self) -> Mode {
        self.0.current_mode()
    }

    fn pending_mode(&self) -> Mode {
        self.0.pending_mode()
    }

    fn use_mode(&self, mode: Mode) -> Result<(), Self::Error> {
        self.0.use_mode(mode)
    }
}

#[cfg(feature = "backend_drm")]
impl<D: RawDevice + 'static> CursorBackend for GbmSurface<D>
where
    <D as RawDevice>::Surface: CursorBackend<CursorFormat = dyn drm::buffer::Buffer>,
    <<D as RawDevice>::Surface as CursorBackend>::Error: ::std::error::Error + Send,
{
    type CursorFormat = ImageBuffer<Rgba<u8>, Vec<u8>>;
    type Error = Error<<<D as Device>::Surface as CursorBackend>::Error>;

    fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), Self::Error> {
        self.0.set_cursor_position(x, y)
    }

    fn set_cursor_representation(
        &self,
        buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>,
        hotspot: (u32, u32),
    ) -> Result<(), Self::Error> {
        self.0.set_cursor_representation(buffer, hotspot)
    }
}
<commit_msg>gbm: do not block buffer forever if commit/page_flip fails<commit_after>use super::super::{Device, RawDevice, RawSurface, Surface};
use super::Error;

use drm::control::{connector, crtc, framebuffer, Device as ControlDevice, Mode};
use failure::ResultExt;
use gbm::{self, BufferObject, BufferObjectFlags, Format as GbmFormat, SurfaceBufferHandle};
use image::{ImageBuffer, Rgba};

use std::cell::{Cell, RefCell};
use std::rc::Rc;

use crate::backend::graphics::CursorBackend;

pub(super) struct GbmSurfaceInternal<D: RawDevice + 'static> {
    pub(super) dev: Rc<RefCell<gbm::Device<D>>>,
    pub(super) surface: RefCell<gbm::Surface<framebuffer::Handle>>,
    pub(super) crtc: <D as Device>::Surface,
    pub(super) cursor: Cell<(BufferObject<()>, (u32, u32))>,
    pub(super) current_frame_buffer: Cell<Option<framebuffer::Handle>>,
    pub(super) front_buffer: Cell<Option<SurfaceBufferHandle<framebuffer::Handle>>>,
    pub(super) next_buffer: Cell<Option<SurfaceBufferHandle<framebuffer::Handle>>>,
    pub(super) recreated: Cell<bool>,
    pub(super) logger: ::slog::Logger,
}

impl<D: RawDevice + 'static> GbmSurfaceInternal<D> {
    pub(super) fn unlock_buffer(&self) {
        // after the page swap is finished we need to release the rendered buffer.
        // this is called from the PageFlipHandler
        trace!(self.logger, "Releasing old front buffer");
        self.front_buffer.set(self.next_buffer.replace(None));
        // drop and release the old buffer
    }

    pub unsafe fn page_flip(&self) -> Result<(), Error<<<D as Device>::Surface as Surface>::Error>> {
        let res = {
            let nb = self.next_buffer.take();
            let res = nb.is_some();
            self.next_buffer.set(nb);
            res
        };
        if res {
            // We cannot call lock_front_buffer anymore without releasing the previous buffer, which will happen when the page flip is done
            warn!(self.logger, "Tried to swap with an already queued flip");
            return Err(Error::FrontBuffersExhausted);
        }

        // supporting only one buffer would cause a lot of inconvinience and
        // would most likely result in a lot of flickering.
        // neither weston, wlc or wlroots bother with that as well.
        // so we just assume we got at least two buffers to do flipping.
        let mut next_bo = self
            .surface
            .borrow()
            .lock_front_buffer()
            .map_err(|_| Error::FrontBufferLockFailed)?;

        // create a framebuffer if the front buffer does not have one already
        // (they are reused by gbm)
        let maybe_fb = next_bo
            .userdata()
            .map_err(|_| Error::InvalidInternalState)?
            .cloned();
        let fb = if let Some(info) = maybe_fb {
            info
        } else {
            let fb = self
                .crtc
                .add_planar_framebuffer(&*next_bo, &[0; 4], 0)
                .compat()
                .map_err(Error::FramebufferCreationFailed)?;
            next_bo.set_userdata(fb).unwrap();
            fb
        };
        self.next_buffer.set(Some(next_bo));

        let result = if self.recreated.get() {
            debug!(self.logger, "Commiting new state");
            let res = self.crtc.commit(fb).map_err(Error::Underlying);
            self.recreated.set(false);
            res
        } else {
            trace!(self.logger, "Queueing Page flip");
            RawSurface::page_flip(&self.crtc, fb).map_err(Error::Underlying)
        };

        match result {
            Ok(_) => {
                self.current_frame_buffer.set(Some(fb));
                Ok(())
            },
            Err(err) => {
                self.unlock_buffer();
                Err(err)
            }
        }
    }

    pub fn recreate(&self) -> Result<(), Error<<<D as Device>::Surface as Surface>::Error>> {
        let (w, h) = self.pending_mode().size();

        // Recreate the surface and the related resources to match the new
        // resolution.
        debug!(self.logger, "(Re-)Initializing surface (with mode: {}:{})", w, h);
        let surface = self
            .dev
            .borrow_mut()
            .create_surface(
                w as u32,
                h as u32,
                GbmFormat::XRGB8888,
                BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING,
            )
            .map_err(Error::SurfaceCreationFailed)?;

        // Clean up buffers
        self.clear_framebuffers();

        // Drop the old surface after cleanup
        *self.surface.borrow_mut() = surface;

        self.recreated.set(true);

        Ok(())
    }

    pub fn clear_framebuffers(&self) {
        if let Some(Ok(Some(fb))) = self.next_buffer.take().map(|mut bo| bo.take_userdata()) {
            if let Err(err) = self.crtc.destroy_framebuffer(fb) {
                warn!(
                    self.logger,
                    "Error releasing old back_buffer framebuffer: {:?}", err
                );
            }
        }

        if let Some(Ok(Some(fb))) = self.front_buffer.take().map(|mut bo| bo.take_userdata()) {
            if let Err(err) = self.crtc.destroy_framebuffer(fb) {
                warn!(
                    self.logger,
                    "Error releasing old front_buffer framebuffer: {:?}", err
                );
            }
        }
    }
}

impl<D: RawDevice + 'static> Surface for GbmSurfaceInternal<D> {
    type Connectors = <<D as Device>::Surface as Surface>::Connectors;
    type Error = Error<<<D as Device>::Surface as Surface>::Error>;

    fn crtc(&self) -> crtc::Handle {
        self.crtc.crtc()
    }

    fn current_connectors(&self) -> Self::Connectors {
        self.crtc.current_connectors()
    }

    fn pending_connectors(&self) -> Self::Connectors {
        self.crtc.pending_connectors()
    }

    fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
        self.crtc.add_connector(connector).map_err(Error::Underlying)
    }

    fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
        self.crtc.remove_connector(connector).map_err(Error::Underlying)
    }

    fn set_connectors(&self, connectors: &[connector::Handle]) -> Result<(), Self::Error> {
        self.crtc.set_connectors(connectors).map_err(Error::Underlying)
    }

    fn current_mode(&self) -> Mode {
        self.crtc.current_mode()
    }

    fn pending_mode(&self) -> Mode {
        self.crtc.pending_mode()
    }

    fn use_mode(&self, mode: Mode) -> Result<(), Self::Error> {
        self.crtc.use_mode(mode).map_err(Error::Underlying)
    }
}

#[cfg(feature = "backend_drm")]
impl<D: RawDevice + 'static> CursorBackend for GbmSurfaceInternal<D>
where
    <D as RawDevice>::Surface: CursorBackend<CursorFormat = dyn drm::buffer::Buffer>,
    <<D as RawDevice>::Surface as CursorBackend>::Error: ::std::error::Error + Send,
{
    type CursorFormat = ImageBuffer<Rgba<u8>, Vec<u8>>;
    type Error = Error<<<D as Device>::Surface as CursorBackend>::Error>;

    fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), Self::Error> {
        self.crtc.set_cursor_position(x, y).map_err(Error::Underlying)
    }

    fn set_cursor_representation(
        &self,
        buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>,
        hotspot: (u32, u32),
    ) -> Result<(), Self::Error> {
        let (w, h) = buffer.dimensions();
        debug!(self.logger, "Importing cursor");

        // import the cursor into a buffer we can render
        let mut cursor = self
            .dev
            .borrow_mut()
            .create_buffer_object(
                w,
                h,
                GbmFormat::ARGB8888,
                BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
            )
            .map_err(Error::BufferCreationFailed)?;

        cursor
            .write(&**buffer)
            .map_err(|_| Error::DeviceDestroyed)?
            .map_err(Error::BufferWriteFailed)?;

        trace!(self.logger, "Setting the new imported cursor");

        self.crtc
            .set_cursor_representation(&cursor, hotspot)
            .map_err(Error::Underlying)?;

        // and store it
        self.cursor.set((cursor, hotspot));
        Ok(())
    }
}

impl<D: RawDevice + 'static> Drop for GbmSurfaceInternal<D> {
    fn drop(&mut self) {
        // Drop framebuffers attached to the userdata of the gbm surface buffers.
        // (They don't implement drop, as they need the device)
        self.clear_framebuffers();
    }
}

/// Gbm surface for rendering
pub struct GbmSurface<D: RawDevice + 'static>(pub(super) Rc<GbmSurfaceInternal<D>>);

impl<D: RawDevice + 'static> GbmSurface<D> {
    /// Flips the underlying buffers.
    ///
    /// The surface will report being already flipped until the matching event
    /// was processed either by calling [`Device::process_events`] manually after the flip
    /// (bad idea performance-wise) or by binding the device to an event-loop by using
    /// [`device_bind`](::backend::drm::device_bind).
    ///
    /// *Note*: This might trigger a full modeset on the underlying device,
    /// potentially causing some flickering. In that case this operation is
    /// blocking until the crtc is in the desired state.
    ///
    /// # Safety
    ///
    /// When used in conjunction with an EGL context, this must be called exactly once
    /// after page-flipping the associated context.
    pub unsafe fn page_flip(&self) -> ::std::result::Result<(), <Self as Surface>::Error> {
        self.0.page_flip()
    }

    /// Recreate underlying gbm resources.
    ///
    /// This recreates the gbm surfaces resources, which might be needed after e.g.
    /// calling [`Surface::use_mode`](Surface::use_mode).
    /// You may check if your [`GbmSurface`] needs recreation through
    /// [`needs_recreation`](GbmSurface::needs_recreation).
    pub fn recreate(&self) -> Result<(), <Self as Surface>::Error> {
        self.0.recreate()
    }

    /// Check if underlying gbm resources need to be recreated.
    pub fn needs_recreation(&self) -> bool {
        self.0.crtc.commit_pending()
    }
}

impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
    type Connectors = <<D as Device>::Surface as Surface>::Connectors;
    type Error = Error<<<D as Device>::Surface as Surface>::Error>;

    fn crtc(&self) -> crtc::Handle {
        self.0.crtc()
    }

    fn current_connectors(&self) -> Self::Connectors {
        self.0.current_connectors()
    }

    fn pending_connectors(&self) -> Self::Connectors {
        self.0.pending_connectors()
    }

    fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
        self.0.add_connector(connector)
    }

    fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error> {
        self.0.remove_connector(connector)
    }

    fn set_connectors(&self, connectors: &[connector::Handle]) -> Result<(), Self::Error> {
        self.0.set_connectors(connectors)
    }

    fn current_mode(&self) -> Mode {
        self.0.current_mode()
    }

    fn pending_mode(&self) -> Mode {
        self.0.pending_mode()
    }

    fn use_mode(&self, mode: Mode) -> Result<(), Self::Error> {
        self.0.use_mode(mode)
    }
}

#[cfg(feature = "backend_drm")]
impl<D: RawDevice + 'static> CursorBackend for GbmSurface<D>
where
    <D as RawDevice>::Surface: CursorBackend<CursorFormat = dyn drm::buffer::Buffer>,
    <<D as RawDevice>::Surface as CursorBackend>::Error: ::std::error::Error + Send,
{
    type CursorFormat = ImageBuffer<Rgba<u8>, Vec<u8>>;
    type Error = Error<<<D as Device>::Surface as CursorBackend>::Error>;

    fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), Self::Error> {
        self.0.set_cursor_position(x, y)
    }

    fn set_cursor_representation(
        &self,
        buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>,
        hotspot: (u32, u32),
    ) -> Result<(), Self::Error> {
        self.0.set_cursor_representation(buffer, hotspot)
    }
}
<|endoftext|>


<commit_before>//!
//! Implementation of the [`Session`](::backend::session::Session) trait through the libseat.
//!
//! This requires libseat to be available on the system.

use libseat::{Seat, SeatEvent};
use std::{
    cell::RefCell,
    collections::HashMap,
    os::unix::io::RawFd,
    path::Path,
    rc::{Rc, Weak},
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
};

use nix::{errno::Errno, fcntl::OFlag, unistd::close};

use calloop::{EventSource, Poll, Readiness, Token};

use crate::{
    backend::session::{AsErrno, Session, Signal as SessionSignal},
    signaling::Signaler,
};

#[derive(Debug)]
struct LibSeatSessionImpl {
    seat: RefCell<Seat>,
    active: Arc<AtomicBool>,
    devices: RefCell<HashMap<RawFd, i32>>,
    logger: ::slog::Logger,
}

impl Drop for LibSeatSessionImpl {
    fn drop(&mut self) {
        debug!(self.logger, "Closing seat")
    }
}

/// [`Session`] via the libseat
#[derive(Debug, Clone)]
pub struct LibSeatSession {
    internal: Weak<LibSeatSessionImpl>,
    seat_name: String,
}

/// [`SessionNotifier`] via the libseat
#[derive(Debug)]
pub struct LibSeatSessionNotifier {
    internal: Rc<LibSeatSessionImpl>,
    signaler: Signaler<SessionSignal>,
}

impl LibSeatSession {
    /// Tries to create a new session via libseat.
    pub fn new<L>(logger: L) -> Result<(LibSeatSession, LibSeatSessionNotifier), Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        let logger = crate::slog_or_fallback(logger)
            .new(o!("smithay_module" => "backend_session", "session_type" => "libseat"));

        let active = Arc::new(AtomicBool::new(false));
        let signaler = Signaler::new();

        let seat = {
            let log = logger.clone();
            let active = active.clone();
            let signaler = signaler.clone();

            Seat::open(
                move |seat, event| match event {
                    SeatEvent::Enable => {
                        debug!(log, "Enable callback called");
                        active.store(true, Ordering::SeqCst);
                        signaler.signal(SessionSignal::ActivateSession);
                    }
                    SeatEvent::Disable => {
                        debug!(log, "Disable callback called");
                        active.store(false, Ordering::SeqCst);
                        signaler.signal(SessionSignal::PauseSession);
                        seat.disable().unwrap();
                    }
                },
                logger.clone(),
            )
        };

        seat.map(|mut seat| {
            // In some cases enable_seat event is avalible right after startup
            // so, we can dispatch it
            seat.dispatch(0).unwrap();

            let seat_name = seat.name().to_owned();

            let internal = Rc::new(LibSeatSessionImpl {
                seat: RefCell::new(seat),
                active,
                devices: RefCell::new(HashMap::new()),
                logger,
            });

            (
                LibSeatSession {
                    internal: Rc::downgrade(&internal),
                    seat_name,
                },
                LibSeatSessionNotifier { internal, signaler },
            )
        })
        .map_err(|err| Error::FailedToOpenSession(Errno::from_i32(err.into())))
    }
}

impl Session for LibSeatSession {
    type Error = Error;

    fn open(&mut self, path: &Path, _flags: OFlag) -> Result<RawFd, Self::Error> {
        if let Some(session) = self.internal.upgrade() {
            debug!(session.logger, "Opening device: {:?}", path);

            session
                .seat
                .borrow_mut()
                .open_device(&path)
                .map(|(id, fd)| {
                    session.devices.borrow_mut().insert(fd, id);
                    fd
                })
                .map_err(|err| Error::FailedToOpenDevice(Errno::from_i32(err.into())))
        } else {
            Err(Error::SessionLost)
        }
    }

    fn close(&mut self, fd: RawFd) -> Result<(), Self::Error> {
        if let Some(session) = self.internal.upgrade() {
            debug!(session.logger, "Closing device: {:?}", fd);

            let dev = session.devices.borrow().get(&fd).map(|fd| *fd);

            let out = if let Some(dev) = dev {
                session
                    .seat
                    .borrow_mut()
                    .close_device(dev)
                    .map_err(|err| Error::FailedToCloseDevice(Errno::from_i32(err.into())))
            } else {
                Ok(())
            };

            close(fd).unwrap();

            out
        } else {
            Err(Error::SessionLost)
        }
    }

    fn change_vt(&mut self, vt: i32) -> Result<(), Self::Error> {
        if let Some(session) = self.internal.upgrade() {
            debug!(session.logger, "Session switch: {:?}", vt);
            session
                .seat
                .borrow_mut()
                .switch_session(vt)
                .map_err(|err| Error::FailedToChangeVt(Errno::from_i32(err.into())))
        } else {
            Err(Error::SessionLost)
        }
    }

    fn is_active(&self) -> bool {
        if let Some(internal) = self.internal.upgrade() {
            internal.active.load(Ordering::SeqCst)
        } else {
            false
        }
    }

    fn seat(&self) -> String {
        self.seat_name.clone()
    }
}

impl LibSeatSessionNotifier {
    /// Creates a new session object belonging to this notifier.
    pub fn session(&self) -> LibSeatSession {
        LibSeatSession {
            internal: Rc::downgrade(&self.internal),
            seat_name: self.internal.seat.borrow_mut().name().to_owned(),
        }
    }

    /// Get a handle to the Signaler of this session.
    ///
    /// You can use it to listen for signals generated by the session.
    pub fn signaler(&self) -> Signaler<SessionSignal> {
        self.signaler.clone()
    }
}

impl EventSource for LibSeatSessionNotifier {
    type Event = ();
    type Metadata = ();
    type Ret = ();

    fn process_events<F>(&mut self, _readiness: Readiness, _token: Token, _: F) -> std::io::Result<()>
    where
        F: FnMut((), &mut ()),
    {
        self.internal.seat.borrow_mut().dispatch(0).unwrap();
        Ok(())
    }

    fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> {
        poll.register(
            self.internal.seat.borrow_mut().get_fd().unwrap(),
            calloop::Interest::READ,
            calloop::Mode::Level,
            token,
        )
        .unwrap();
        Ok(())
    }

    fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> {
        poll.reregister(
            self.internal.seat.borrow_mut().get_fd().unwrap(),
            calloop::Interest::READ,
            calloop::Mode::Level,
            token,
        )
        .unwrap();
        Ok(())
    }

    fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> {
        poll.unregister(self.internal.seat.borrow_mut().get_fd().unwrap())
            .unwrap();
        Ok(())
    }
}

/// Errors related to direct/tty sessions
#[derive(thiserror::Error, Debug)]
pub enum Error {
    /// Failed to open session
    #[error("Failed to open session: {0}")]
    FailedToOpenSession(Errno),

    /// Failed to open device
    #[error("Failed to open device: {0}")]
    FailedToOpenDevice(Errno),

    /// Failed to close device
    #[error("Failed to close device: {0}")]
    FailedToCloseDevice(Errno),

    /// Failed to close device
    #[error("Failed to change vt: {0}")]
    FailedToChangeVt(Errno),

    /// Session is already closed,
    #[error("Session is already closed")]
    SessionLost,
}

impl AsErrno for Error {
    fn as_errno(&self) -> Option<i32> {
        match self {
            &Self::FailedToOpenSession(errno)
            | &Self::FailedToOpenDevice(errno)
            | &Self::FailedToCloseDevice(errno)
            | &Self::FailedToChangeVt(errno) => Some(errno as i32),
            _ => None,
        }
    }
}
<commit_msg>Fix libseat build<commit_after>//!
//! Implementation of the [`Session`](::backend::session::Session) trait through the libseat.
//!
//! This requires libseat to be available on the system.

use libseat::{Seat, SeatEvent};
use std::{
    cell::RefCell,
    collections::HashMap,
    os::unix::io::RawFd,
    path::Path,
    rc::{Rc, Weak},
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
};

use nix::{errno::Errno, fcntl::OFlag, unistd::close};

use calloop::{EventSource, Poll, Readiness, Token};

use crate::{
    backend::session::{AsErrno, Session, Signal as SessionSignal},
    signaling::Signaler,
};

use slog::{debug, error, o};

#[derive(Debug)]
struct LibSeatSessionImpl {
    seat: RefCell<Seat>,
    active: Arc<AtomicBool>,
    devices: RefCell<HashMap<RawFd, i32>>,
    logger: ::slog::Logger,
}

impl Drop for LibSeatSessionImpl {
    fn drop(&mut self) {
        debug!(self.logger, "Closing seat")
    }
}

/// [`Session`] via the libseat
#[derive(Debug, Clone)]
pub struct LibSeatSession {
    internal: Weak<LibSeatSessionImpl>,
    seat_name: String,
}

/// [`SessionNotifier`] via the libseat
#[derive(Debug)]
pub struct LibSeatSessionNotifier {
    internal: Rc<LibSeatSessionImpl>,
    signaler: Signaler<SessionSignal>,
}

impl LibSeatSession {
    /// Tries to create a new session via libseat.
    pub fn new<L>(logger: L) -> Result<(LibSeatSession, LibSeatSessionNotifier), Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        let logger = crate::slog_or_fallback(logger)
            .new(o!("smithay_module" => "backend_session", "session_type" => "libseat"));

        let active = Arc::new(AtomicBool::new(false));
        let signaler = Signaler::new();

        let seat = {
            let log = logger.clone();
            let active = active.clone();
            let signaler = signaler.clone();

            Seat::open(
                move |seat, event| match event {
                    SeatEvent::Enable => {
                        debug!(log, "Enable callback called");
                        active.store(true, Ordering::SeqCst);
                        signaler.signal(SessionSignal::ActivateSession);
                    }
                    SeatEvent::Disable => {
                        debug!(log, "Disable callback called");
                        active.store(false, Ordering::SeqCst);
                        signaler.signal(SessionSignal::PauseSession);
                        seat.disable().unwrap();
                    }
                },
                logger.clone(),
            )
        };

        seat.map(|mut seat| {
            // In some cases enable_seat event is avalible right after startup
            // so, we can dispatch it
            seat.dispatch(0).unwrap();

            let seat_name = seat.name().to_owned();

            let internal = Rc::new(LibSeatSessionImpl {
                seat: RefCell::new(seat),
                active,
                devices: RefCell::new(HashMap::new()),
                logger,
            });

            (
                LibSeatSession {
                    internal: Rc::downgrade(&internal),
                    seat_name,
                },
                LibSeatSessionNotifier { internal, signaler },
            )
        })
        .map_err(|err| Error::FailedToOpenSession(Errno::from_i32(err.into())))
    }
}

impl Session for LibSeatSession {
    type Error = Error;

    fn open(&mut self, path: &Path, _flags: OFlag) -> Result<RawFd, Self::Error> {
        if let Some(session) = self.internal.upgrade() {
            debug!(session.logger, "Opening device: {:?}", path);

            session
                .seat
                .borrow_mut()
                .open_device(&path)
                .map(|(id, fd)| {
                    session.devices.borrow_mut().insert(fd, id);
                    fd
                })
                .map_err(|err| Error::FailedToOpenDevice(Errno::from_i32(err.into())))
        } else {
            Err(Error::SessionLost)
        }
    }

    fn close(&mut self, fd: RawFd) -> Result<(), Self::Error> {
        if let Some(session) = self.internal.upgrade() {
            debug!(session.logger, "Closing device: {:?}", fd);

            let dev = session.devices.borrow().get(&fd).map(|fd| *fd);

            let out = if let Some(dev) = dev {
                session
                    .seat
                    .borrow_mut()
                    .close_device(dev)
                    .map_err(|err| Error::FailedToCloseDevice(Errno::from_i32(err.into())))
            } else {
                Ok(())
            };

            close(fd).unwrap();

            out
        } else {
            Err(Error::SessionLost)
        }
    }

    fn change_vt(&mut self, vt: i32) -> Result<(), Self::Error> {
        if let Some(session) = self.internal.upgrade() {
            debug!(session.logger, "Session switch: {:?}", vt);
            session
                .seat
                .borrow_mut()
                .switch_session(vt)
                .map_err(|err| Error::FailedToChangeVt(Errno::from_i32(err.into())))
        } else {
            Err(Error::SessionLost)
        }
    }

    fn is_active(&self) -> bool {
        if let Some(internal) = self.internal.upgrade() {
            internal.active.load(Ordering::SeqCst)
        } else {
            false
        }
    }

    fn seat(&self) -> String {
        self.seat_name.clone()
    }
}

impl LibSeatSessionNotifier {
    /// Creates a new session object belonging to this notifier.
    pub fn session(&self) -> LibSeatSession {
        LibSeatSession {
            internal: Rc::downgrade(&self.internal),
            seat_name: self.internal.seat.borrow_mut().name().to_owned(),
        }
    }

    /// Get a handle to the Signaler of this session.
    ///
    /// You can use it to listen for signals generated by the session.
    pub fn signaler(&self) -> Signaler<SessionSignal> {
        self.signaler.clone()
    }
}

impl EventSource for LibSeatSessionNotifier {
    type Event = ();
    type Metadata = ();
    type Ret = ();

    fn process_events<F>(&mut self, _readiness: Readiness, _token: Token, _: F) -> std::io::Result<()>
    where
        F: FnMut((), &mut ()),
    {
        self.internal.seat.borrow_mut().dispatch(0).unwrap();
        Ok(())
    }

    fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> {
        poll.register(
            self.internal.seat.borrow_mut().get_fd().unwrap(),
            calloop::Interest::READ,
            calloop::Mode::Level,
            token,
        )
        .unwrap();
        Ok(())
    }

    fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> {
        poll.reregister(
            self.internal.seat.borrow_mut().get_fd().unwrap(),
            calloop::Interest::READ,
            calloop::Mode::Level,
            token,
        )
        .unwrap();
        Ok(())
    }

    fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> {
        poll.unregister(self.internal.seat.borrow_mut().get_fd().unwrap())
            .unwrap();
        Ok(())
    }
}

/// Errors related to direct/tty sessions
#[derive(thiserror::Error, Debug)]
pub enum Error {
    /// Failed to open session
    #[error("Failed to open session: {0}")]
    FailedToOpenSession(Errno),

    /// Failed to open device
    #[error("Failed to open device: {0}")]
    FailedToOpenDevice(Errno),

    /// Failed to close device
    #[error("Failed to close device: {0}")]
    FailedToCloseDevice(Errno),

    /// Failed to close device
    #[error("Failed to change vt: {0}")]
    FailedToChangeVt(Errno),

    /// Session is already closed,
    #[error("Session is already closed")]
    SessionLost,
}

impl AsErrno for Error {
    fn as_errno(&self) -> Option<i32> {
        match self {
            &Self::FailedToOpenSession(errno)
            | &Self::FailedToOpenDevice(errno)
            | &Self::FailedToCloseDevice(errno)
            | &Self::FailedToChangeVt(errno) => Some(errno as i32),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright © 2018, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use lazy_static::lazy_static;
use mimir::rubber::{IndexSettings, Rubber};
use mimirsbrunn::addr_reader::{import_addresses_from_files, import_addresses_from_streams};
use mimirsbrunn::admin_geofinder::AdminGeoFinder;
use mimirsbrunn::{labels, utils};
use serde::{Deserialize, Serialize};
use slog_scope::{info, warn};
use std::io::stdin;
use std::ops::Deref;
use std::path::PathBuf;
use structopt::StructOpt;

lazy_static! {
    static ref DEFAULT_NB_THREADS: String = num_cpus::get().to_string();
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub struct OpenAddress {
    pub id: String,
    pub street: String,
    pub postcode: String,
    pub district: String,
    pub region: String,
    pub city: String,
    pub number: String,
    pub unit: String,
    pub lat: f64,
    pub lon: f64,
}

impl OpenAddress {
    pub fn into_addr(
        self,
        admins_geofinder: &AdminGeoFinder,
        use_old_index_format: bool,
    ) -> Result<mimir::Addr, mimirsbrunn::Error> {
        let street_id = format!("street:{}", self.id); // TODO check if thats ok
        let admins = admins_geofinder.get(&geo::Coordinate {
            x: self.lon,
            y: self.lat,
        });
        let country_codes = utils::find_country_codes(admins.iter().map(|a| a.deref()));

        let weight = admins.iter().find(|a| a.is_city()).map_or(0., |a| a.weight);
        // Note: for openaddress, we don't trust the admin hierarchy much (compared to bano)
        // so we use for the label the admins that we find in the DB
        let street_label = labels::format_street_label(
            &self.street,
            admins.iter().map(|a| a.deref()),
            &country_codes,
        );
        let (addr_name, addr_label) = labels::format_addr_name_and_label(
            &self.number,
            &self.street,
            admins.iter().map(|a| a.deref()),
            &country_codes,
        );

        let coord = mimir::Coord::new(self.lon, self.lat);
        let street = mimir::Street {
            id: street_id,
            name: self.street,
            label: street_label,
            administrative_regions: admins,
            weight: weight,
            zip_codes: vec![self.postcode.clone()],
            coord: coord.clone(),
            approx_coord: None,
            distance: None,
            country_codes: country_codes.clone(),
            context: None,
        };

        Ok(mimir::Addr {
            id: format!(
                "addr:{};{}{}",
                self.lon,
                self.lat,
                if use_old_index_format {
                    String::new()
                } else {
                    format!(
                        ":{}",
                        self.number
                            .replace(" ", "")
                            .replace("\t", "")
                            .replace("\r", "")
                            .replace("\n", "")
                            .replace("/", "-")
                            .replace(".", "-")
                            .replace(":", "-")
                            .replace(";", "-")
                    )
                }
            ),
            name: addr_name,
            label: addr_label,
            house_number: self.number,
            street: street,
            coord: coord.clone(),
            approx_coord: Some(coord.into()),
            weight: weight,
            zip_codes: vec![self.postcode],
            distance: None,
            country_codes,
            context: None,
        })
    }
}

#[derive(StructOpt, Debug)]
struct Args {
    /// OpenAddresses files. Can be either a directory or a file.
    /// If this is left empty, addresses are read from standard input.
    #[structopt(short = "i", long = "input", parse(from_os_str))]
    input: Option<PathBuf>,
    /// Elasticsearch parameters.
    #[structopt(
        short = "c",
        long = "connection-string",
        default_value = "http://localhost:9200/munin"
    )]
    connection_string: String,
    /// Name of the dataset.
    #[structopt(short = "d", long = "dataset", default_value = "fr")]
    dataset: String,
    /// Deprecated option.
    #[structopt(short = "C", long = "city-level")]
    city_level: Option<String>,
    /// Number of threads to use
    #[structopt(
        short = "t",
        long = "nb-threads",
        default_value = &DEFAULT_NB_THREADS
    )]
    nb_threads: usize,
    /// Number of shards for the es index
    #[structopt(short = "s", long = "nb-shards", default_value = "5")]
    nb_shards: usize,
    /// Number of replicas for the es index
    #[structopt(short = "r", long = "nb-replicas", default_value = "1")]
    nb_replicas: usize,
    /// If set to true, the number inside the address won't be used for the index generation,
    /// therefore, different addresses with the same position will disappear.
    #[structopt(long = "use-old-index-format")]
    use_old_index_format: bool,
}

fn run(args: Args) -> Result<(), failure::Error> {
    info!("importing open addresses into Mimir");

    if args.city_level.is_some() {
        warn!("city-level option is deprecated, it now has no effect.");
    }

    let mut rubber = Rubber::new(&args.connection_string);
    let index_settings = IndexSettings {
        nb_shards: args.nb_shards,
        nb_replicas: args.nb_replicas,
    };

    // Fetch and index admins for `into_addr`
    let into_addr = {
        let admins = rubber.get_all_admins().unwrap_or_else(|err| {
            warn!(
                "Administratives regions not found in es db for dataset {}. (error: {})",
                &args.dataset, err
            );
            vec![]
        });
        let admins_geofinder = admins.into_iter().collect();

        let use_old_index_format = args.use_old_index_format;
        move |a: OpenAddress| a.into_addr(&admins_geofinder, use_old_index_format)
    };

    if let Some(input_path) = args.input {
        // Import from file(s)
        if input_path.is_dir() {
            let paths = walkdir::WalkDir::new(&input_path);
            let path_iter = paths
                .into_iter()
                .map(|p| p.unwrap().into_path())
                .filter(|p| {
                    let f = p
                        .extension()
                        .and_then(|e| e.to_str())
                        .map(|e| e == "gz")
                        .unwrap_or(false);
                    if !f {
                        info!("skipping file {} as it is not a csv", p.display());
                    }
                    f
                });

            import_addresses_from_files(
                &mut rubber,
                true,
                args.nb_threads,
                index_settings,
                &args.dataset,
                path_iter,
                into_addr,
            )
        } else {
            import_addresses_from_files(
                &mut rubber,
                true,
                args.nb_threads,
                index_settings,
                &args.dataset,
                std::iter::once(input_path),
                into_addr,
            )
        }
    } else {
        // Import from stdin
        import_addresses_from_streams(
            &mut rubber,
            true,
            args.nb_threads,
            index_settings,
            &args.dataset,
            std::iter::once(stdin()),
            into_addr,
        )
    }
}

fn main() {
    mimirsbrunn::utils::launch_run(run);
}
<commit_msg>fix openaddresses2mimir skipping non-compressed files<commit_after>// Copyright © 2018, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use lazy_static::lazy_static;
use mimir::rubber::{IndexSettings, Rubber};
use mimirsbrunn::addr_reader::{import_addresses_from_files, import_addresses_from_streams};
use mimirsbrunn::admin_geofinder::AdminGeoFinder;
use mimirsbrunn::{labels, utils};
use serde::{Deserialize, Serialize};
use slog_scope::{info, warn};
use std::io::stdin;
use std::ops::Deref;
use std::path::PathBuf;
use structopt::StructOpt;

lazy_static! {
    static ref DEFAULT_NB_THREADS: String = num_cpus::get().to_string();
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub struct OpenAddress {
    pub id: String,
    pub street: String,
    pub postcode: String,
    pub district: String,
    pub region: String,
    pub city: String,
    pub number: String,
    pub unit: String,
    pub lat: f64,
    pub lon: f64,
}

impl OpenAddress {
    pub fn into_addr(
        self,
        admins_geofinder: &AdminGeoFinder,
        use_old_index_format: bool,
    ) -> Result<mimir::Addr, mimirsbrunn::Error> {
        let street_id = format!("street:{}", self.id); // TODO check if thats ok
        let admins = admins_geofinder.get(&geo::Coordinate {
            x: self.lon,
            y: self.lat,
        });
        let country_codes = utils::find_country_codes(admins.iter().map(|a| a.deref()));

        let weight = admins.iter().find(|a| a.is_city()).map_or(0., |a| a.weight);
        // Note: for openaddress, we don't trust the admin hierarchy much (compared to bano)
        // so we use for the label the admins that we find in the DB
        let street_label = labels::format_street_label(
            &self.street,
            admins.iter().map(|a| a.deref()),
            &country_codes,
        );
        let (addr_name, addr_label) = labels::format_addr_name_and_label(
            &self.number,
            &self.street,
            admins.iter().map(|a| a.deref()),
            &country_codes,
        );

        let coord = mimir::Coord::new(self.lon, self.lat);
        let street = mimir::Street {
            id: street_id,
            name: self.street,
            label: street_label,
            administrative_regions: admins,
            weight: weight,
            zip_codes: vec![self.postcode.clone()],
            coord: coord.clone(),
            approx_coord: None,
            distance: None,
            country_codes: country_codes.clone(),
            context: None,
        };

        Ok(mimir::Addr {
            id: format!(
                "addr:{};{}{}",
                self.lon,
                self.lat,
                if use_old_index_format {
                    String::new()
                } else {
                    format!(
                        ":{}",
                        self.number
                            .replace(" ", "")
                            .replace("\t", "")
                            .replace("\r", "")
                            .replace("\n", "")
                            .replace("/", "-")
                            .replace(".", "-")
                            .replace(":", "-")
                            .replace(";", "-")
                    )
                }
            ),
            name: addr_name,
            label: addr_label,
            house_number: self.number,
            street: street,
            coord: coord.clone(),
            approx_coord: Some(coord.into()),
            weight: weight,
            zip_codes: vec![self.postcode],
            distance: None,
            country_codes,
            context: None,
        })
    }
}

#[derive(StructOpt, Debug)]
struct Args {
    /// OpenAddresses files. Can be either a directory or a file.
    /// If this is left empty, addresses are read from standard input.
    #[structopt(short = "i", long = "input", parse(from_os_str))]
    input: Option<PathBuf>,
    /// Elasticsearch parameters.
    #[structopt(
        short = "c",
        long = "connection-string",
        default_value = "http://localhost:9200/munin"
    )]
    connection_string: String,
    /// Name of the dataset.
    #[structopt(short = "d", long = "dataset", default_value = "fr")]
    dataset: String,
    /// Deprecated option.
    #[structopt(short = "C", long = "city-level")]
    city_level: Option<String>,
    /// Number of threads to use
    #[structopt(
        short = "t",
        long = "nb-threads",
        default_value = &DEFAULT_NB_THREADS
    )]
    nb_threads: usize,
    /// Number of shards for the es index
    #[structopt(short = "s", long = "nb-shards", default_value = "5")]
    nb_shards: usize,
    /// Number of replicas for the es index
    #[structopt(short = "r", long = "nb-replicas", default_value = "1")]
    nb_replicas: usize,
    /// If set to true, the number inside the address won't be used for the index generation,
    /// therefore, different addresses with the same position will disappear.
    #[structopt(long = "use-old-index-format")]
    use_old_index_format: bool,
}

fn run(args: Args) -> Result<(), failure::Error> {
    info!("importing open addresses into Mimir");

    if args.city_level.is_some() {
        warn!("city-level option is deprecated, it now has no effect.");
    }

    let mut rubber = Rubber::new(&args.connection_string);
    let index_settings = IndexSettings {
        nb_shards: args.nb_shards,
        nb_replicas: args.nb_replicas,
    };

    // Fetch and index admins for `into_addr`
    let into_addr = {
        let admins = rubber.get_all_admins().unwrap_or_else(|err| {
            warn!(
                "Administratives regions not found in es db for dataset {}. (error: {})",
                &args.dataset, err
            );
            vec![]
        });
        let admins_geofinder = admins.into_iter().collect();

        let use_old_index_format = args.use_old_index_format;
        move |a: OpenAddress| a.into_addr(&admins_geofinder, use_old_index_format)
    };

    if let Some(input_path) = args.input {
        // Import from file(s)
        if input_path.is_dir() {
            let paths = walkdir::WalkDir::new(&input_path);
            let path_iter = paths
                .into_iter()
                .map(|p| p.unwrap().into_path())
                .filter(|p| {
                    let f = p
                        .file_name()
                        .and_then(|name| name.to_str())
                        .map(|name| name.ends_with(".csv") || name.ends_with(".csv.gz"))
                        .unwrap_or(false);
                    if !f {
                        info!("skipping file {} as it is not a csv", p.display());
                    }
                    f
                });

            import_addresses_from_files(
                &mut rubber,
                true,
                args.nb_threads,
                index_settings,
                &args.dataset,
                path_iter,
                into_addr,
            )
        } else {
            import_addresses_from_files(
                &mut rubber,
                true,
                args.nb_threads,
                index_settings,
                &args.dataset,
                std::iter::once(input_path),
                into_addr,
            )
        }
    } else {
        // Import from stdin
        import_addresses_from_streams(
            &mut rubber,
            true,
            args.nb_threads,
            index_settings,
            &args.dataset,
            std::iter::once(stdin()),
            into_addr,
        )
    }
}

fn main() {
    mimirsbrunn::utils::launch_run(run);
}
<|endoftext|>


<commit_before>extern crate clock_ticks;

use std::thread;
use std::cmp;
use std::io::Error;
use std::net::{SocketAddr, ToSocketAddrs};
use traits::socket::Socket;
use shared::udp_socket::UdpSocket;
use super::{Config, Connection, Handler};

/// Implementation of a single-server client implementation with handler based
/// event dispatching.
pub struct Client {
    closed: bool,
    config: Config,
    address: Option<SocketAddr>
}

impl Client {

    /// Creates a new client with the given configuration.
    pub fn new(config: Config) -> Client {
        Client {
            closed: false,
            config: config,
            address: None
        }
    }

    /// Returns the address of the server the client is currently connected to.
    pub fn peer_addr(&self) -> Option<SocketAddr> {
        self.address
    }

    /// Establishes a connection with the server at the specified address by
    /// creating a local socket for message sending.
    ///
    /// The server must use a compatible connection / packet configuration.
    ///
    /// The `handler` is a struct that implements the `Handler` trait in order
    /// to handle events from the client and its connection.
    pub fn connect<T: ToSocketAddrs>(
        &mut self, handler: &mut Handler<Client>, address: T
    ) -> Result<(), Error> {

        let socket = try!(UdpSocket::new(
            "127.0.0.1:0",
            self.config.packet_max_size
        ));

        self.connect_from_socket(handler, address, socket)

    }

    /// Establishes a connection with the server at the specified address by
    /// using the specified socket for message sending.
    ///
    /// The server must use a compatible connection / packet configuration.
    ///
    /// The `handler` is a struct that implements the `Handler` trait in order
    /// to handle events from the client and its connection.
    pub fn connect_from_socket<T: Socket, A: ToSocketAddrs>(
        &mut self, handler: &mut Handler<Client>, address: A, mut socket: T
    ) -> Result<(), Error> {

        // Parse remote address of server
        let peer_addr = try!(address.to_socket_addrs()).next().unwrap();

        // Extract bound address
        self.address = Some(try!(socket.local_addr()));

        // Create connection
        let mut connection = Connection::new(
            self.config,
            peer_addr,
            handler.rate_limiter(&self.config)
        );

        // Extract packet reader
        let reader = socket.reader().unwrap();

        // Invoke handler
        handler.connect(self);

        // Receive and send until we get closed.
        while !self.closed {

            // Get current time to correct tick delay in order to achieve
            // a more stable tick rate
            let begin = clock_ticks::precise_time_ns();

            // Receive all incoming UDP packets from the specified remote
            // address feeding them into out connection object for parsing
            while let Ok((addr, packet)) = reader.try_recv() {
                if addr == peer_addr {
                    connection.receive_packet(packet, self, handler);
                }
            }

            // Invoke handler
            handler.tick_connection(self, &mut connection);

            // Invoke the connection to send a outgoing packet
            connection.send_packet(&mut socket, &peer_addr, self, handler);

            // Limit ticks per second to the configured amount
            let spend = (clock_ticks::precise_time_ns() - begin) / 1000000 ;
            thread::sleep_ms(
                cmp::max(1000 / self.config.send_rate - spend as u32, 0)
            );

        }

        // Invoke handler
        handler.close(self);
        self.address = None;

        // Reset connection state
        connection.reset();

        // Close the UDP socket
        socket.shutdown();

        Ok(())

    }

    /// Closes the clients connections to the server.
    pub fn close(&mut self) {
        self.closed = true;
    }

}

#[cfg(test)]
mod tests {

    extern crate clock_ticks;

    use std::thread;
    use std::collections::HashMap;
    use super::super::{Connection, Config, Handler, Client};

    struct MockServerHandler {
        pub last_tick_time: u32,
        pub tick_count: u32,
        pub accumulated: u32
    }

    impl Handler<Client> for MockServerHandler {

        fn bind(&mut self, _: &mut Client) {
            self.last_tick_time = precise_time_ms();
        }

        fn tick_connection(
            &mut self, client: &mut Client,
            _: &mut Connection
        ) {

            // Accumulate time so we can check that the artifical delay
            // was correct for by the servers tick loop
            if self.tick_count > 1 {
                self.accumulated += precise_time_ms() - self.last_tick_time;
            }

            self.last_tick_time = precise_time_ms();
            self.tick_count += 1;

            if self.tick_count == 5 {
                client.close();
            }

            // Fake some load inside of the tick handler
            thread::sleep_ms(75);

        }

    }

    fn precise_time_ms() -> u32 {
        (clock_ticks::precise_time_ns() / 1000000) as u32
    }

    #[test]
    fn test_client_tick_delay() {

        let config = Config {
            send_rate: 10,
            .. Config::default()
        };

        let mut handler = MockServerHandler {
            last_tick_time: 0,
            tick_count: 0,
            accumulated: 0
        };

        let mut client = Client::new(config);
        client.connect(&mut handler, "127.0.0.1:0").unwrap();

        assert!(handler.accumulated <= 350);

    }

}

<commit_msg>Remove unused test import<commit_after>extern crate clock_ticks;

use std::thread;
use std::cmp;
use std::io::Error;
use std::net::{SocketAddr, ToSocketAddrs};
use traits::socket::Socket;
use shared::udp_socket::UdpSocket;
use super::{Config, Connection, Handler};

/// Implementation of a single-server client implementation with handler based
/// event dispatching.
pub struct Client {
    closed: bool,
    config: Config,
    address: Option<SocketAddr>
}

impl Client {

    /// Creates a new client with the given configuration.
    pub fn new(config: Config) -> Client {
        Client {
            closed: false,
            config: config,
            address: None
        }
    }

    /// Returns the address of the server the client is currently connected to.
    pub fn peer_addr(&self) -> Option<SocketAddr> {
        self.address
    }

    /// Establishes a connection with the server at the specified address by
    /// creating a local socket for message sending.
    ///
    /// The server must use a compatible connection / packet configuration.
    ///
    /// The `handler` is a struct that implements the `Handler` trait in order
    /// to handle events from the client and its connection.
    pub fn connect<T: ToSocketAddrs>(
        &mut self, handler: &mut Handler<Client>, address: T
    ) -> Result<(), Error> {

        let socket = try!(UdpSocket::new(
            "127.0.0.1:0",
            self.config.packet_max_size
        ));

        self.connect_from_socket(handler, address, socket)

    }

    /// Establishes a connection with the server at the specified address by
    /// using the specified socket for message sending.
    ///
    /// The server must use a compatible connection / packet configuration.
    ///
    /// The `handler` is a struct that implements the `Handler` trait in order
    /// to handle events from the client and its connection.
    pub fn connect_from_socket<T: Socket, A: ToSocketAddrs>(
        &mut self, handler: &mut Handler<Client>, address: A, mut socket: T
    ) -> Result<(), Error> {

        // Parse remote address of server
        let peer_addr = try!(address.to_socket_addrs()).next().unwrap();

        // Extract bound address
        self.address = Some(try!(socket.local_addr()));

        // Create connection
        let mut connection = Connection::new(
            self.config,
            peer_addr,
            handler.rate_limiter(&self.config)
        );

        // Extract packet reader
        let reader = socket.reader().unwrap();

        // Invoke handler
        handler.connect(self);

        // Receive and send until we get closed.
        while !self.closed {

            // Get current time to correct tick delay in order to achieve
            // a more stable tick rate
            let begin = clock_ticks::precise_time_ns();

            // Receive all incoming UDP packets from the specified remote
            // address feeding them into out connection object for parsing
            while let Ok((addr, packet)) = reader.try_recv() {
                if addr == peer_addr {
                    connection.receive_packet(packet, self, handler);
                }
            }

            // Invoke handler
            handler.tick_connection(self, &mut connection);

            // Invoke the connection to send a outgoing packet
            connection.send_packet(&mut socket, &peer_addr, self, handler);

            // Limit ticks per second to the configured amount
            let spend = (clock_ticks::precise_time_ns() - begin) / 1000000 ;
            thread::sleep_ms(
                cmp::max(1000 / self.config.send_rate - spend as u32, 0)
            );

        }

        // Invoke handler
        handler.close(self);
        self.address = None;

        // Reset connection state
        connection.reset();

        // Close the UDP socket
        socket.shutdown();

        Ok(())

    }

    /// Closes the clients connections to the server.
    pub fn close(&mut self) {
        self.closed = true;
    }

}

#[cfg(test)]
mod tests {

    extern crate clock_ticks;

    use std::thread;
    use super::super::{Connection, Config, Handler, Client};

    struct MockServerHandler {
        pub last_tick_time: u32,
        pub tick_count: u32,
        pub accumulated: u32
    }

    impl Handler<Client> for MockServerHandler {

        fn bind(&mut self, _: &mut Client) {
            self.last_tick_time = precise_time_ms();
        }

        fn tick_connection(
            &mut self, client: &mut Client,
            _: &mut Connection
        ) {

            // Accumulate time so we can check that the artifical delay
            // was correct for by the servers tick loop
            if self.tick_count > 1 {
                self.accumulated += precise_time_ms() - self.last_tick_time;
            }

            self.last_tick_time = precise_time_ms();
            self.tick_count += 1;

            if self.tick_count == 5 {
                client.close();
            }

            // Fake some load inside of the tick handler
            thread::sleep_ms(75);

        }

    }

    fn precise_time_ms() -> u32 {
        (clock_ticks::precise_time_ns() / 1000000) as u32
    }

    #[test]
    fn test_client_tick_delay() {

        let config = Config {
            send_rate: 10,
            .. Config::default()
        };

        let mut handler = MockServerHandler {
            last_tick_time: 0,
            tick_count: 0,
            accumulated: 0
        };

        let mut client = Client::new(config);
        client.connect(&mut handler, "127.0.0.1:0").unwrap();

        assert!(handler.accumulated <= 350);

    }

}

<|endoftext|>


<commit_before>use std::io::{BufRead, BufReader, Write};
use std::net::TcpStream;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
use std::thread;

use chatmap::{ChatMap, ClientInfo};
use message::Message;

pub fn create_client(stream: TcpStream, sender_to_router: Sender<Message>, chat_map: &Arc<Mutex<ChatMap>>) {
    println!("New client");
    let mut stream = stream;
    stream.write(&"Welcome to Smazy\n".to_string().into_bytes()).unwrap();
    stream.write(&"Please enter a username:\n".to_string().into_bytes()).unwrap();
    stream.flush().unwrap();
    let mut reader = BufReader::new(stream.try_clone().unwrap());
    let mut username = "".to_string();
    match reader.read_line(&mut username) {
        Ok(n) => {
            let username = username.trim().to_string();
            let (sender_to_client, receiver_from_router) = channel();
            {
                let mut guard = chat_map.lock().unwrap();
                if n > 0 && !guard.contains_key(&username) {
                    let client_info = ClientInfo{partner: None, sender_to_client: sender_to_client};
                    guard.insert(username.to_string(), client_info);
                    println!("New user: {}", username.to_string());
                }
            }
            let partner = choose_chat_partner(stream.try_clone().unwrap(), username.to_string(), chat_map);
            chat(stream, username, partner, sender_to_router, receiver_from_router);
        },
        Err(e) => println!("{}", e)
    }
}

fn choose_chat_partner(stream: TcpStream, username: String, chat_map: &Arc<Mutex<ChatMap>>) -> String {
    let mut stream = stream;

    stream.write(&"Here are the users available to chat:\n".to_string().into_bytes()).unwrap();
    {
        let guard = chat_map.lock().unwrap();
        for (name, client_info) in guard.iter() {
            if name.as_str() != username.as_str() && client_info.partner == None {
                stream.write(&name.to_string().into_bytes()).unwrap();
                stream.write(&"\n".to_string().into_bytes()).unwrap();
            }
        }
    }

    stream.write(&"Select who you want to chat with:\n".to_string().into_bytes()).unwrap();

    let mut reader = BufReader::new(stream.try_clone().unwrap());
    let mut partner = "".to_string();

    match reader.read_line(&mut partner) {
        Ok(_) => {
            partner = partner.trim().to_string();

            if !try_select_partner(chat_map, username.to_string(), partner.to_string()) {
                return choose_chat_partner(stream, username, chat_map);
            }
        }
        Err(e) => println!("{}", e)
    }

    partner
}

fn try_select_partner(chat_map: &Arc<Mutex<ChatMap>>, username: String, partner: String) -> bool {
    let success: bool;
    {
        let mut guard = chat_map.lock().unwrap();

        match guard.get_mut(&partner) {
            Some(clientinfo) => {
                if partner.as_str() != username.as_str()
                    && (clientinfo.partner == None
                        || clientinfo.partner == Some(username.to_string())) {
                    clientinfo.partner = Some(username.to_string());
                    success = true;
                } else {
                    success = false;
                }
            },
            None => success = false
        }
    }

    if success {
        let mut guard = chat_map.lock().unwrap();
        println!("Assigning partner {} to {}", partner, username);
        guard.get_mut(&username).unwrap().partner = Some(partner.to_string());
    }
    success
}

// TODO: Receiving a message while in the middle of typing a message
//       inserts received message into middle of your message
fn chat(stream: TcpStream, username: String, partner: String, sender_to_router: Sender<Message>, receiver_from_router: Receiver<Message>) {
    // Send messages
    {
        let username = username.clone();
        let reader = BufReader::new(stream.try_clone().unwrap());
        thread::spawn(move|| {
            let mut lines = reader.lines();
            while let Some(Ok(line)) = lines.next() {
                println!("{}",line);
                let msg = Message::new("Date".to_string(), username.to_string(), partner.to_string(), line.to_string());
                sender_to_router.send(msg).unwrap();
            }
        });
    }

    // Receive Messages
    {
        let username = username.clone();
        let mut stream = stream;
        thread::spawn(move|| {
            loop {
                match receiver_from_router.try_recv() {
                    Ok(msg) => {
                        println!("User {} received message: {}", &username, msg.content());
                        stream.write(&msg.from().to_string().into_bytes()).unwrap();
                        stream.write(&": ".to_string().into_bytes()).unwrap();
                        stream.write(&msg.content().to_string().into_bytes()).unwrap();
                        stream.write(&"\n".to_string().into_bytes()).unwrap();
                    }
                    Err(TryRecvError::Empty) => continue,
                    Err(TryRecvError::Disconnected) => panic!("User {} disconnected from router", &username)
                }
            }
        });
    }
}<commit_msg>Refactored message delivery into own function<commit_after>use std::io::{BufRead, BufReader, Write};
use std::net::TcpStream;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
use std::thread;

use chatmap::{ChatMap, ClientInfo};
use message::Message;

pub fn create_client(stream: TcpStream, sender_to_router: Sender<Message>, chat_map: &Arc<Mutex<ChatMap>>) {
    println!("New client");
    let mut stream = stream;
    stream.write(&"Welcome to Smazy\n".to_string().into_bytes()).unwrap();
    stream.write(&"Please enter a username:\n".to_string().into_bytes()).unwrap();
    stream.flush().unwrap();
    let mut reader = BufReader::new(stream.try_clone().unwrap());
    let mut username = "".to_string();
    match reader.read_line(&mut username) {
        Ok(n) => {
            let username = username.trim().to_string();
            let (sender_to_client, receiver_from_router) = channel();
            {
                let mut guard = chat_map.lock().unwrap();
                if n > 0 && !guard.contains_key(&username) {
                    let client_info = ClientInfo{partner: None, sender_to_client: sender_to_client};
                    guard.insert(username.to_string(), client_info);
                    println!("New user: {}", username.to_string());
                }
            }
            let partner = choose_chat_partner(stream.try_clone().unwrap(), username.to_string(), chat_map);
            chat(stream, username, partner, sender_to_router, receiver_from_router);
        },
        Err(e) => println!("{}", e)
    }
}

fn choose_chat_partner(stream: TcpStream, username: String, chat_map: &Arc<Mutex<ChatMap>>) -> String {
    let mut stream = stream;

    stream.write(&"Here are the users available to chat:\n".to_string().into_bytes()).unwrap();
    {
        let guard = chat_map.lock().unwrap();
        for (name, client_info) in guard.iter() {
            if name.as_str() != username.as_str() && client_info.partner == None {
                stream.write(&name.to_string().into_bytes()).unwrap();
                stream.write(&"\n".to_string().into_bytes()).unwrap();
            }
        }
    }

    stream.write(&"Select who you want to chat with:\n".to_string().into_bytes()).unwrap();

    let mut reader = BufReader::new(stream.try_clone().unwrap());
    let mut partner = "".to_string();

    match reader.read_line(&mut partner) {
        Ok(_) => {
            partner = partner.trim().to_string();

            if !try_select_partner(chat_map, username.to_string(), partner.to_string()) {
                return choose_chat_partner(stream, username, chat_map);
            }
        }
        Err(e) => println!("{}", e)
    }

    partner
}

fn try_select_partner(chat_map: &Arc<Mutex<ChatMap>>, username: String, partner: String) -> bool {
    let success: bool;
    {
        let mut guard = chat_map.lock().unwrap();

        match guard.get_mut(&partner) {
            Some(clientinfo) => {
                if partner.as_str() != username.as_str()
                    && (clientinfo.partner == None
                        || clientinfo.partner == Some(username.to_string())) {
                    clientinfo.partner = Some(username.to_string());
                    success = true;
                } else {
                    success = false;
                }
            },
            None => success = false
        }
    }

    if success {
        let mut guard = chat_map.lock().unwrap();
        println!("Assigning partner {} to {}", partner, username);
        guard.get_mut(&username).unwrap().partner = Some(partner.to_string());
    }
    success
}

// TODO: Receiving a message while in the middle of typing a message
//       inserts received message into middle of your message
fn chat(stream: TcpStream, username: String, partner: String, sender_to_router: Sender<Message>, receiver_from_router: Receiver<Message>) {
    // Send messages
    {
        let username = username.clone();
        let reader = BufReader::new(stream.try_clone().unwrap());
        thread::spawn(move|| {
            let mut lines = reader.lines();
            while let Some(Ok(line)) = lines.next() {
                println!("{}",line);
                let msg = Message::new("Date".to_string(), username.to_string(), partner.to_string(), line.to_string());
                sender_to_router.send(msg).unwrap();
            }
        });
    }

    // Receive Messages
    {
        let username = username.clone();
        thread::spawn(move|| {
            loop {
                let stream = stream.try_clone().unwrap();
                match receiver_from_router.try_recv() {
                    Ok(msg) => {
                        println!("User {} received message: {}", &username, msg.content());
                        deliver_message(stream, msg);
                    }
                    Err(TryRecvError::Empty) => continue,
                    Err(TryRecvError::Disconnected) => panic!("User {} disconnected from router", &username)
                }
            }
        });
    }
}

fn deliver_message(stream: TcpStream, msg: Message) {
    let mut stream = stream;
    let output = msg.from().to_string() + ": " + msg.content().as_str() + "\n";
    stream.write(&output.into_bytes()).unwrap();
}<|endoftext|>


<commit_before>use action;
use Document;
use Error;
use hyper;
use IntoDatabasePath;
use IntoDocumentPath;
use IntoViewPath;
use Revision;
use serde;
use transport::HyperTransport;

/// Types that are convertible into a URL.
pub trait IntoUrl: hyper::client::IntoUrl {
}

impl<T: hyper::client::IntoUrl> IntoUrl for T {}

pub struct Client {
    transport: HyperTransport,
}

impl Client {
    pub fn new<U: IntoUrl>(server_url: U) -> Result<Self, Error> {
        let server_url = try!(server_url.into_url().map_err(|e| Error::UrlParse { cause: e }));
        let transport = try!(HyperTransport::new(server_url));
        Ok((Client { transport: transport }))
    }
}

impl Client {
    pub fn create_database<'a, P>(&'a self,
                                  db_path: P)
                                  -> Result<action::CreateDatabase<'a, HyperTransport>, Error>
        where P: IntoDatabasePath<'a>
    {
        action::CreateDatabase::new(&self.transport, db_path)
    }

    pub fn create_document<'a, C, P>
        (&'a self,
         db_path: P,
         content: &'a C)
         -> Result<action::CreateDocument<'a, HyperTransport, C>, Error>
        where C: serde::Serialize,
              P: IntoDatabasePath<'a>
    {
        action::CreateDocument::new(&self.transport, db_path, content)
    }

    pub fn read_document<'a, P>(&'a self,
                                doc_path: P)
                                -> Result<action::ReadDocument<'a, HyperTransport>, Error>
        where P: IntoDocumentPath<'a>
    {
        action::ReadDocument::new(&self.transport, doc_path)
    }

    pub fn update_document<'a>(&'a self,
                               doc: &'a Document)
                               -> Result<action::UpdateDocument<'a, HyperTransport>, Error> {
        action::UpdateDocument::new(&self.transport, doc)
    }

    pub fn delete_document<'a, P>(&'a self,
                                  doc_path: P,
                                  revision: &'a Revision)
                                  -> Result<action::DeleteDocument<'a, HyperTransport>, Error>
        where P: IntoDocumentPath<'a>
    {
        action::DeleteDocument::new(&self.transport, doc_path, revision)
    }

    pub fn execute_view<'a, K, V, P>
        (&'a self,
         view_path: P)
         -> Result<action::ExecuteView<'a, HyperTransport, K, V>, Error>
        where K: serde::Deserialize + serde::Serialize,
              P: IntoViewPath<'a>,
              V: serde::Deserialize
    {
        action::ExecuteView::new(&self.transport, view_path)
    }
}
<commit_msg>New doc comments for Client<commit_after>use action;
use Document;
use Error;
use hyper;
use IntoDatabasePath;
use IntoDocumentPath;
use IntoViewPath;
use Revision;
use serde;
use transport::HyperTransport;

/// Types that are convertible into a URL.
pub trait IntoUrl: hyper::client::IntoUrl {
}

impl<T: hyper::client::IntoUrl> IntoUrl for T {}

/// Manages all communication with a CouchDB server.
///
/// A `Client` communicates with the CouchDB server via **actions**. Each action
/// abstracts a single HTTP request-response pair, such as to create a database
/// (i.e., PUT `/db`) or read a document (i.e., GET `/db/doc`).
///
/// A `Client` communicates with exactly one CouchDB server, as specified by the
/// URI set when the `Client` is constructed.
///
pub struct Client {
    transport: HyperTransport,
}

impl Client {
    /// Constructs a client for the given server.
    pub fn new<U: IntoUrl>(server_url: U) -> Result<Self, Error> {
        let server_url = try!(server_url.into_url().map_err(|e| Error::UrlParse { cause: e }));
        let transport = try!(HyperTransport::new(server_url));
        Ok((Client { transport: transport }))
    }

    /// Builds an action to create a database.
    pub fn create_database<'a, P>(&'a self,
                                  db_path: P)
                                  -> Result<action::CreateDatabase<'a, HyperTransport>, Error>
        where P: IntoDatabasePath<'a>
    {
        action::CreateDatabase::new(&self.transport, db_path)
    }

    /// Builds an action to create a document.
    pub fn create_document<'a, C, P>
        (&'a self,
         db_path: P,
         content: &'a C)
         -> Result<action::CreateDocument<'a, HyperTransport, C>, Error>
        where C: serde::Serialize,
              P: IntoDatabasePath<'a>
    {
        action::CreateDocument::new(&self.transport, db_path, content)
    }

    /// Builds an action to read a document.
    pub fn read_document<'a, P>(&'a self,
                                doc_path: P)
                                -> Result<action::ReadDocument<'a, HyperTransport>, Error>
        where P: IntoDocumentPath<'a>
    {
        action::ReadDocument::new(&self.transport, doc_path)
    }

    /// Builds an action to update a document.
    pub fn update_document<'a>(&'a self,
                               doc: &'a Document)
                               -> Result<action::UpdateDocument<'a, HyperTransport>, Error> {
        action::UpdateDocument::new(&self.transport, doc)
    }

    /// Builds an action to delete a document.
    pub fn delete_document<'a, P>(&'a self,
                                  doc_path: P,
                                  revision: &'a Revision)
                                  -> Result<action::DeleteDocument<'a, HyperTransport>, Error>
        where P: IntoDocumentPath<'a>
    {
        action::DeleteDocument::new(&self.transport, doc_path, revision)
    }

    /// Builds an action to execute a view.
    pub fn execute_view<'a, K, V, P>
        (&'a self,
         view_path: P)
         -> Result<action::ExecuteView<'a, HyperTransport, K, V>, Error>
        where K: serde::Deserialize + serde::Serialize,
              P: IntoViewPath<'a>,
              V: serde::Deserialize
    {
        action::ExecuteView::new(&self.transport, view_path)
    }
}
<|endoftext|>