-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from WURFL/0.1.0
0.1.0
- Loading branch information
Showing
11 changed files
with
2,029 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,4 +2,24 @@ | |
name = "wmclient" | ||
version = "0.1.0" | ||
authors = ["Andrea Castello <[email protected]>"] | ||
edition = "2018" | ||
edition = "2018" | ||
license = "Apache-2.0" | ||
homepage = "https://www.scientiamobile.com" | ||
repository = "https://github.com/WURFL/wurfl-microservice-client-rust" | ||
readme = "README.md" | ||
description = "WURFL Microservice (by ScientiaMobile, Inc.) is a mobile device detection service that can quickly and accurately detect over 500 capabilities of visiting devices. It can differentiate between portable mobile devices, desktop devices, SmartTVs and any other types of devices that have a web browser." | ||
|
||
|
||
[dependencies] | ||
#ureq = { version = "2.2.0", features = ["json", "charset"] } | ||
reqwest = { version = "0.10", features = ["blocking", "json"] } | ||
openssl = { version = "^0.10", features = ["vendored"] } | ||
lru = "0.7.0" | ||
serde = { version = "1.0.130", features = ["derive"]} | ||
serde_json = "1.0" | ||
thiserror = "1.0" | ||
md5 = "0.7.0" | ||
# the following dependencies are needed to make the hyper example work. | ||
# you can comment them you don't want to keep or use it. | ||
hyper = { version = "0.14.13", features = ["full"] } | ||
tokio = { version = "1.12.0", features = ["full"] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
lru - https://crates.io/crates/lru - MIT License | ||
ureq - https://crates.io/crates/ureq - MIT and Apache 2.0 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
use std::collections::HashMap; | ||
use wmclient::WmClient; | ||
|
||
fn main() { | ||
// Let's create the WURFL microservice client by setting the connection data of out WURFL Microservice server | ||
let client_res = WmClient::new("http", "localhost", "8080", ""); | ||
// Client is mutable because because some its internal can be modified depending on its interaction with the user or | ||
// the server. | ||
let mut client: WmClient; | ||
if client_res.is_ok(){ | ||
client = client_res.unwrap(); | ||
println!("-----------------------------------------------------------------------------------"); | ||
println!("WURFL Microservice client created successfully. Rust client API version: {}", client.get_api_version()); | ||
println!("-----------------------------------------------------------------------------------"); | ||
} else { | ||
println!("Unable to create WURFL Microservice client: {}", client_res.err().unwrap().to_string()); | ||
return; | ||
} | ||
// Let's add the caching layer to the client | ||
client.set_cache_size(10000); | ||
// Let's gather some server info. | ||
let info_res = client.get_info(); | ||
if info_res.is_err(){ | ||
println!("Unable to get server info. Exiting."); | ||
return; | ||
} | ||
let info = info_res.unwrap(); | ||
println!("WURFL Microservice information:"); | ||
println!("Server version: {}", info.wm_version); | ||
println!("WURFL API version: {}", info.wurfl_api_version); | ||
println!("WURFL file info: {}", info.wurfl_info); | ||
|
||
// set the capabilities we want to receive from WM server | ||
// Static capabilities | ||
let static_caps = vec! {"model_name brand_name"}; | ||
client.set_requested_static_capabilities(Some(static_caps)); | ||
// Virtual capabilities | ||
let virtual_caps = vec! {"is_smartphone form_factor"}; | ||
client.set_requested_virtual_capabilities(Some(virtual_caps)); | ||
|
||
// use this headers to perform a device detection. | ||
let mut headers = HashMap::new(); | ||
headers.insert("Content-Type", "application/json"); | ||
headers.insert("Accept", "text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1"); | ||
headers.insert("Accept-Encoding", "gzip, deflate"); | ||
headers.insert("Accept-Language", "en"); | ||
headers.insert("Device-Stock-Ua", "Mozilla/5.0 (Linux; Android 8.1.0; SM-J610G Build/M1AJQ; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Mobile Safari/537.36"); | ||
headers.insert("Forwarded", "for=\"110.54.224.195:36350\""); | ||
headers.insert("Referer", "https://www.cram.com/flashcards/labor-and-delivery-questions-889210"); | ||
headers.insert("User-Agent", "Opera/9.80 (Android; Opera Mini/51.0.2254/184.121; U; en) Presto/2.12.423 Version/12.16"); | ||
headers.insert("X-Clacks-Overhead", "GNU ph"); | ||
headers.insert("X-Forwarded-For", "110.54.224.195, 82.145.210.235"); | ||
headers.insert("X-Operamini-Features", "advanced, camera, download, file_system, folding, httpping, pingback, routing, touch, viewport"); | ||
headers.insert("X-Operamini-Phone", "Android #"); | ||
headers.insert("X-Operamini-Phone-Ua", "Mozilla/5.0 (Linux; Android 8.1.0; SM-J610G Build/M1AJQ; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Mobile Safari/537.36"); | ||
|
||
let device_res = client.lookup_headers(headers); | ||
if device_res.is_err(){ | ||
println!("Unable to detect device from the given HTTP headers: {}", device_res.err().unwrap().to_string()); | ||
return; | ||
} | ||
// No error, let's get the device data | ||
let device = device_res.unwrap(); | ||
let wurfl_id_opt = device.capabilities.get("wurfl_id"); | ||
if wurfl_id_opt.is_some() { | ||
println!("-----------------------------------------------------------------------------------"); | ||
println!("Sample device detection using sample headers"); | ||
println!("WURFL device ID : {}", wurfl_id_opt.unwrap()); | ||
} | ||
// If you are sure the capability you're querying exists and is in your required set, just unwrap the capability option | ||
println!("This device is a : {} {}", device.capabilities.get("brand_name").unwrap(), device.capabilities.get("model_name").unwrap()); | ||
|
||
// check if device is a smartphone (a virtual capability) | ||
if device.capabilities.get("is_smartphone").unwrap() == "true" { | ||
println!("This is a smartphone") | ||
} | ||
println!("This device form_factor is: {}", device.capabilities.get("form_factor").unwrap()); | ||
|
||
// Get all the device manufacturers, and print the first twenty | ||
let makes_res = client.get_all_device_makes(); | ||
if makes_res.is_err() { | ||
let err_mk = makes_res.as_ref().err().unwrap(); | ||
println!("Error getting device makes data {}", err_mk.to_string()); | ||
} | ||
|
||
|
||
let mut device_makes = makes_res.unwrap(); | ||
device_makes.sort(); | ||
let limit = 20; | ||
println!("-----------------------------------------------------------------------------------"); | ||
println!("Print the first {} brand_names of {} found", limit, device_makes.len()); | ||
println!("-----------------------------------------------------------------------------------"); | ||
|
||
for _i in 0..limit { | ||
println!("{}", device_makes.get(_i).unwrap()); | ||
} | ||
|
||
// Now call the WM server to get all device model and marketing names produced by Apple | ||
let model_marketing_names_opt = client.get_all_devices_for_make("Apple".to_string()); | ||
if model_marketing_names_opt.is_err(){ | ||
let err_mmkt = model_marketing_names_opt.as_ref().err().unwrap(); | ||
println!("Error getting device model and marketing data for Apple: {}", err_mmkt.to_string()); | ||
} | ||
|
||
let mut model_marketing_names = model_marketing_names_opt.unwrap(); | ||
// Sort model_marketing_names structs by their model name, using natural ordering (thus Uppercase names come first, then lowercase) | ||
model_marketing_names.sort_by(|a,b| a.model_name.cmp(&b.model_name)); | ||
println!("-----------------------------------------------------------------------------------"); | ||
println!("Printing all model and marketing names for Apple brand"); | ||
println!("-----------------------------------------------------------------------------------"); | ||
for name in model_marketing_names{ | ||
println!("- {} {}", name.model_name, name.marketing_name); | ||
} | ||
|
||
// Now call the WM server to get all operating system names | ||
println!("-----------------------------------------------------------------------------------"); | ||
println!("Print the list of OSes"); | ||
println!("-----------------------------------------------------------------------------------"); | ||
let os_opt = client.get_all_oses(); | ||
if os_opt.is_err(){ | ||
let os_err = os_opt.as_ref().err().unwrap(); | ||
println!("Unable to get the list of operating systems: {}", os_err.to_string()); | ||
} | ||
let mut os_list = os_opt.unwrap(); | ||
os_list.sort(); | ||
for os in os_list { | ||
println!("- {}", os); | ||
} | ||
|
||
println!("-----------------------------------------------------------------------------------"); | ||
println!("Print all version numbers for Android OS"); | ||
println!("-----------------------------------------------------------------------------------"); | ||
let android_ver_opt = client.get_all_versions_for_os("Android"); | ||
if android_ver_opt.is_err(){ | ||
let ver_err = android_ver_opt.as_ref().err().unwrap(); | ||
println!("Unable to get versions for Android OS: {}", ver_err.to_string()); | ||
} | ||
let android_versions = android_ver_opt.unwrap(); | ||
for v in android_versions { | ||
println!("- {}", v); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
use std::convert::Infallible; | ||
use std::net::SocketAddr; | ||
use std::sync::{Arc, Mutex}; | ||
use hyper::{Body, Request, Response, Server}; | ||
use hyper::service::{make_service_fn, service_fn}; | ||
use wmclient::WmClient; | ||
|
||
#[tokio::main] | ||
pub async fn main() { | ||
// First, create a Wurfl microservice client instance and set a cache for it. | ||
// change your server data to your preferred settings | ||
let wmclient_res = WmClient::new("http", "localhost", "8080",""); | ||
let wm_client = match wmclient_res { | ||
Ok(wm_client) => wm_client, | ||
Err(error) => panic!("Problem initializing wurfl microservice client: {:?}", error), | ||
}; | ||
println!("Created WURFL microservice client API for Rust version: {}", wm_client.get_api_version()); | ||
// The wurfl microservice client is mutable because contains some updatable internal state, so we need to | ||
// wrap it into a Mutex to use it in the detect function | ||
let safe_wm_client = Arc::new(Mutex::new(wm_client)); | ||
// A `Service` is needed for every connection, so this | ||
// creates one wrapping our `detect` function. | ||
let make_svc = make_service_fn(move |_conn| { | ||
let mut safe_wm_client_clone = Arc::clone(&safe_wm_client); | ||
async { | ||
Ok::<_, Infallible>(service_fn(move |req| { | ||
let response = detect(req, &mut safe_wm_client_clone); | ||
async { Ok::<_, Infallible>(Response::new(Body::from(response))) } | ||
})) | ||
} | ||
}); | ||
|
||
// We'll bind the server to 127.0.0.1:3000 | ||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); | ||
let server = Server::bind(&addr).serve(make_svc); | ||
match server.await { | ||
Err(_) => panic!("An error occurred while running WURFL microservice hyper server example, shutting down"), | ||
_ => (), | ||
} | ||
} | ||
|
||
// Actual device detection: returns a string with wurfl_id and virtual capability complete_device_name | ||
fn detect(_req: Request<Body>, safe_client: &mut Arc<Mutex<WmClient>>) -> String { | ||
let mut client_guard = safe_client.lock().unwrap(); | ||
let device = match client_guard.lookup_headers(_req.headers()) { | ||
Ok(d) => d, | ||
Err(_) => panic!("Error during lookup") | ||
}; | ||
drop(client_guard); | ||
let body = format!("Detected device: {} - {} ", device.capabilities.get("wurfl_id").unwrap(), | ||
device.capabilities.get("complete_device_name").unwrap()); | ||
return body; | ||
} |
Oops, something went wrong.