1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#![feature(proc_macro)]
// Copyright 2016 Mark Sta Ana.
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0>, at your option.
// This file may not be copied, modified, or distributed except
// according to those terms.

// Inspired by Fractals wifi-location (https://github.com/contra/wifi-location)

//! A crate to return your GPS location using WiFi hotspots.
//!
//! # Usage
//!
//! This crate is [on crates.io](https://crates.io/crates/wifilocation) and can be
//! used by adding `wifilocation` to the dependencies in your project's `Cargo.toml`.
//!
//! ```toml
//! [dependencies]
//! wifilocation = "0.3.*"
//! ```
//!
//! and this to your crate root:
//!
//! ```rust
//! extern crate wifilocation;
//! ```

extern crate wifiscanner;
extern crate reqwest;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use wifiscanner::Wifi;
use reqwest::header::Accept;


const BASE_URL: &'static str = "https://maps.googleapis.com/maps/api/browserlocation/json";
const BASE_PARAMS: &'static str = "?browser=firefox&sensor=true";

#[derive(Debug, PartialEq)]
pub enum Error {
    /// A JSON parsing error occurred.
    JSON,
}

/// GPS struct to return longitude and latitude coordinates; and accuracy of information.
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct GpsLocation {
    pub accuracy: u32,
    pub location: Location,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Location {
    pub lat: f64,
    pub lng: f64,
}

/// A wrapper around wifiscanner scan function to return a Vec of wifiscanner::Wifi.
/// The function was an artifact of the original node module and will probably not make
// the next iteration.
pub fn get_towers() -> Vec<Wifi> {
    wifiscanner::scan().unwrap() // sorry Cristi
}


/// Return GPS location using a Vec of wifiscanner::Wifi. Uses Google's GPS location service
pub fn get_location(towers: Vec<Wifi>) -> Result<GpsLocation, Error> {
    let mut url = String::new();
    url.push_str(BASE_URL);
    url.push_str(BASE_PARAMS);

    let mut url_params = String::new();
    for tower in towers {
        url_params.push_str(&format!("&wifi=mac:{}&7Cssid:{}&7Css:{}",
                                     tower.mac,
                                     tower.ssid,
                                     tower.signal_level)
                                 .to_string());

    }

    url.push_str(&url_params);
    let client = reqwest::Client::new().unwrap();
    let mut res = client.post(&url)
                        .header(Accept::json())
                        .send()
                        .expect("Failed to connect to google api!"); // sorry Cristi

    let gps = try!(res.json::<GpsLocation>().map_err(|_| Error::JSON));

    Ok(gps)
}