From 9baf44e330a2e28ccbe44dfdb1df248fd7f4c693 Mon Sep 17 00:00:00 2001 From: James Date: Mon, 29 Jan 2018 21:27:54 +1100 Subject: [PATCH] Implement Github source backend --- src/main.rs | 9 ++++ src/rest.rs | 15 ++---- src/sources/github/mod.rs | 106 +++++++++++++++++++++++++++++++++++++- src/sources/mod.rs | 4 +- src/sources/types.rs | 6 +-- 5 files changed, 122 insertions(+), 18 deletions(-) diff --git a/src/main.rs b/src/main.rs index f5bdc5e..1efd60b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,11 @@ extern crate web_view; +extern crate futures; +extern crate hyper; +extern crate hyper_tls; +extern crate tokio_core; + extern crate includedir; extern crate phf; @@ -27,12 +32,16 @@ use installer::InstallerFramework; use rest::WebServer; +use sources::types::ReleaseSource; + // TODO: Fetch this over a HTTP request? static RAW_CONFIG: &'static str = include_str!("../config.toml"); fn main() { let config = Config::from_toml_str(RAW_CONFIG).unwrap(); + let github_releases = sources::github::GithubReleases{}; + println!("{:?}", github_releases.get_current_releases(&config.packages[0].source.config)); let app_name = config.general.name.clone(); let framework = InstallerFramework::new(config); diff --git a/src/rest.rs b/src/rest.rs index afdd361..925c0e7 100644 --- a/src/rest.rs +++ b/src/rest.rs @@ -3,23 +3,18 @@ /// Provides a HTTP/REST server for both frontend<->backend communication, as well /// as talking to external applications. -extern crate futures; -extern crate hyper; -extern crate hyper_tls; -extern crate tokio_core; - extern crate nfd; use rest::nfd::Response as NfdResponse; use serde_json; -use rest::futures::future; -use rest::futures::future::FutureResult; +use futures::future; +use futures::future::FutureResult; -use rest::hyper::{Error as HyperError, Get, StatusCode}; -use rest::hyper::header::{ContentLength, ContentType}; -use rest::hyper::server::{Http, Request, Response, Service}; +use hyper::{self, Error as HyperError, Get, StatusCode}; +use hyper::header::{ContentLength, ContentType}; +use hyper::server::{Http, Request, Response, Service}; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::thread::{self, JoinHandle}; diff --git a/src/sources/github/mod.rs b/src/sources/github/mod.rs index e0f1ba7..6e5340a 100644 --- a/src/sources/github/mod.rs +++ b/src/sources/github/mod.rs @@ -1,9 +1,24 @@ /// github/mod.rs +use futures::{Future, Stream}; + +use tokio_core::reactor::Core; + +use hyper::Client; +use hyper::Uri; +use hyper::Method; +use hyper::Request; +use hyper::header::UserAgent; + +use hyper_tls::HttpsConnector; + +use toml; + +use serde_json; + use sources::types::*; pub struct GithubReleases { - } /// The configuration for this release. @@ -14,6 +29,93 @@ struct GithubConfig { impl ReleaseSource for GithubReleases { fn get_current_releases(&self, config: &TomlValue) -> Result, String> { - unimplemented!() + // Reparse our Config as strongly typed + let config_string = match toml::to_string(config) { + Ok(v) => v, + Err(v) => return Err(format!("Failed to convert config: {:?}", v)) + }; + + let config : GithubConfig = match toml::from_str(&config_string) { + Ok(v) => v, + Err(v) => return Err(format!("Failed to convert config: {:?}", v)) + }; + + let mut core = match Core::new() { + Ok(v) => v, + Err(v) => return Err(format!("Failed to init Tokio: {:?}", v)) + }; + + // Build the HTTP client up + let client = Client::configure() + .connector(match HttpsConnector::new(4, &core.handle()) { + Ok(v) => v, + Err(v) => return Err(format!("Failed to init https: {:?}", v)) + }) + .build(&core.handle()); + + let mut results: Vec = Vec::new(); + let target_url : Uri = match format!("https://api.github.com/repos/{}/releases", + config.repo).parse() { + Ok(v) => v, + Err(v) => return Err(format!("Failed to generate target url: {:?}", v)) + }; + + let mut req = Request::new(Method::Get, target_url); + req.headers_mut().set(UserAgent::new("installer-rs (j-selby)")); + + // Build our future + let future = client.request(req).and_then(|res| { + res.body().concat2().and_then(move |body| { + let raw_json : Result + = match serde_json::from_slice(&body) { + Ok(v) => Ok(v), + Err(v) => Err(format!("Failed to parse response: {:?}", v)) + }; + + Ok(raw_json) + }) + }); + + // Unwrap the future's results + let result : serde_json::Value = match core.run(future) { + Ok(v) => v, + Err(v) => return Err(format!("Failed to fetch info: {:?}", v)) + }?; + + let result : &Vec = match result.as_array() { + Some(v) => v, + None => return Err(format!("JSON payload not an array")) + }; + + // Parse JSON from server + for entry in result.into_iter() { + let mut files = Vec::new(); + + let id : u64 = match entry["id"].as_u64() { + Some(v) => v, + None => return Err(format!("JSON payload missing information about ID")) + }; + + let assets = match entry["assets"].as_array() { + Some(v) => v, + None => return Err(format!("JSON payload not an array")) + }; + + for asset in assets.into_iter() { + let string = match asset["name"].as_str() { + Some(v) => v, + None => return Err(format!("JSON payload missing information about ID")) + }; + + files.push(string.to_owned()); + } + + results.push(Release { + version: Version::new_number(id), + files + }); + } + + Ok(results) } } diff --git a/src/sources/mod.rs b/src/sources/mod.rs index bbd9f18..21d1fb6 100644 --- a/src/sources/mod.rs +++ b/src/sources/mod.rs @@ -2,6 +2,6 @@ /// /// Contains backends to various release distribution services. -mod types; +pub mod types; -mod github; \ No newline at end of file +pub mod github; \ No newline at end of file diff --git a/src/sources/types.rs b/src/sources/types.rs index 5d8f9a4..b7ca075 100644 --- a/src/sources/types.rs +++ b/src/sources/types.rs @@ -4,8 +4,6 @@ use std::cmp::Ordering; -use installer::InstallerFramework; - pub use semver::Version as SemverVersion; pub use toml::value::Value as TomlValue; @@ -29,12 +27,12 @@ impl Version { } /// Returns a new Version, backed by semver. - fn new_semver(version : SemverVersion) -> Version { + pub fn new_semver(version : SemverVersion) -> Version { Version::Semver(version) } /// Returns a new Version, backed by a integer. - fn new_number(version : u64) -> Version { + pub fn new_number(version : u64) -> Version { Version::Integer(version) } }