Mercurial > lbo > hg > async-google-apis
changeset 8:755f08722795
Work on generating services
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sat, 17 Oct 2020 13:04:25 +0200 |
parents | f098e2637387 |
children | bcd017d6c863 |
files | generate/generate.py manual_demo/Cargo.lock manual_demo/Cargo.toml manual_demo/src/main.rs |
diffstat | 4 files changed, 99 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/generate/generate.py Sat Oct 17 12:06:44 2020 +0200 +++ b/generate/generate.py Sat Oct 17 13:04:25 2020 +0200 @@ -3,6 +3,7 @@ import argparse import chevron import json +import re import requests from os import path @@ -134,11 +135,60 @@ print(e) raise e +def resolve_parameters(string, paramsname='params', suffix='.unwrap()'): + """Returns a Rust syntax for formatting the given string with API + parameters, and a list of (snake-case) API parameters that are used. """ + pat = re.compile('\{(\w+)\}') + params = re.findall(pat, string) + snakeparams = [snake_case(p) for p in params] + format_params = ','.join(['{}={}.{}{}'.format(p, paramsname, sp, suffix) for (p, sp) in zip(params, snakeparams)]) + return 'format!("{}", {})'.format(string, format_params), snakeparams + +def generate_service(resource, methods, discdoc): + service = capitalize_first(resource) + + parts = [] + parts.append('pub struct {}Service {{'.format(service)) + parts.append(' client: TlsClient,') + parts.append(' authenticator: Authenticator,') + parts.append('}') + parts.append('') + + parts.append('impl {}Service {{'.format(service)) + + for methodname, method in methods['methods'].items(): + params_name = service+capitalize_first(methodname)+'Params' + in_type = method['request']['$ref'] if 'request' in method else '()' + out_type = method['response']['$ref'] if 'response' in method else '()' + is_upload = 'mediaUpload' in method + + if is_upload: + parts.append(' fn {}(&mut self, params: {}, req: {}) -> Result<{}> {{'.format( + snake_case(methodname), params_name, in_type, out_type)) + else: + parts.append(' fn {}(&mut self, params: {}, req: {}, data: &hyper::body::Bytes) -> Result<{}> {{'.format( + snake_case(methodname), params_name, in_type, out_type)) + + formatted_path, required_params = resolve_parameters(method['path']) + for rp in required_params: + parts.append(' if params.{}.is_none() {{'.format(rp)) + parts.append(' return Err(Error::new(ApiError::InputDataError("Parameter {} is missing!".to_string())));'.format(rp)) + parts.append(' }') + parts.append(' let relpath = {};'.format(formatted_path)) + parts.append(' unimplemented!()') + parts.append(' }') + + parts.append('}') + parts.append('') + + return '\n'.join(parts) + def generate_structs(discdoc): schemas = discdoc['schemas'] resources = discdoc['resources'] structs = [] + services = [] for name, desc in schemas.items(): typ, substructs = type_of_property(name, desc) structs.extend(substructs) @@ -156,17 +206,42 @@ '{}{}Params'.format(capitalize_first(name), capitalize_first(methodname)), typ) structs.extend(substructs) + for resource, methods in resources.items(): + services.append(generate_service(resource, methods, discdoc)) + modname = (discdoc['id'] + '_types').replace(':', '_') with open(path.join('gen', modname + '.rs'), 'w') as f: f.writelines([ - 'use serde::{Deserialize, Serialize};\n', 'use chrono::{DateTime, Utc};\n', - 'use std::collections::HashMap;\n' + 'use serde::{Deserialize, Serialize};\n', + 'use chrono::{DateTime, Utc};\n', + 'use anyhow::{Error, Result};\n', + 'use std::collections::HashMap;\n', + ''' +type TlsConnr = hyper_rustls::HttpsConnector<hyper::client::HttpConnector>; +type TlsClient = hyper::Client<TlsConnr, hyper::Body>; +type Authenticator = yup_oauth2::authenticator::Authenticator<TlsConnr>; + +#[derive(Debug, Clone)] +pub enum ApiError { + InputDataError(String), +} + +impl std::error::Error for ApiError {} +impl std::fmt::Display for ApiError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Debug::fmt(self, f) + } +} +''', ]) for s in structs: for field in s['fields']: if field.get('comment', None): field['comment'] = field['comment'].replace('\n', ' ') f.write(chevron.render(ResourceStructTmpl, s)) + for s in services: + f.write(s) + f.write('\n') def fetch_discovery_base(url, apis):
--- a/manual_demo/Cargo.lock Sat Oct 17 12:06:44 2020 +0200 +++ b/manual_demo/Cargo.lock Sat Oct 17 13:04:25 2020 +0200 @@ -1,6 +1,12 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] +name = "anyhow" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c" + +[[package]] name = "arc-swap" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -399,6 +405,7 @@ name = "manual_demo" version = "0.1.0" dependencies = [ + "anyhow", "chrono", "hyper", "hyper-rustls",
--- a/manual_demo/Cargo.toml Sat Oct 17 12:06:44 2020 +0200 +++ b/manual_demo/Cargo.toml Sat Oct 17 13:04:25 2020 +0200 @@ -15,3 +15,4 @@ serde_json = "~1.0" tokio = { version = "~0.2", features = ["full"] } yup-oauth2 = "~4" +anyhow = "~1.0"
--- a/manual_demo/src/main.rs Sat Oct 17 12:06:44 2020 +0200 +++ b/manual_demo/src/main.rs Sat Oct 17 13:04:25 2020 +0200 @@ -23,6 +23,18 @@ cl } +struct FilesService { + client: TlsClient, + authenticator: Authenticator +} + +impl FilesService { + fn create(&mut self, parameters: drive::FilesCreateParams, file: drive::File, data: &hyper::body::Bytes) -> hyper::Result<drive::File> { + + unimplemented!() + } +} + async fn upload_file(cl: &mut TlsClient, auth: &mut Authenticator, f: &Path) { let posturl = "https://www.googleapis.com/upload/drive/v3/files?uploadType=media"; let tok = auth.token(&["https://www.googleapis.com/auth/drive.file"]).await.unwrap(); @@ -31,7 +43,8 @@ let file = fs::OpenOptions::new().read(true).open(f).unwrap(); let len = file.metadata().unwrap().len(); - let body = hyper::Body::from(fs::read(&f).unwrap()); + let bytes = hyper::body::Bytes::from(fs::read(&f).unwrap()); + let body = hyper::Body::from(bytes); let req = hyper::Request::post(posturl.to_string()+&authtok).header("Content-Length", format!("{}", len)) .body(body).unwrap(); let resp = cl.request(req).await.unwrap();