From 668b917dd5b0b053536c26093dc31194db154a1f Mon Sep 17 00:00:00 2001 From: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> Date: Sat, 6 Jul 2024 10:53:53 +0530 Subject: [PATCH] [FEATURE]: Watttime (#5) * added registration of user Signed-off-by: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> * added login Signed-off-by: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> * added some TODOs Signed-off-by: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> * added getting loc to region in wattime Signed-off-by: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> * added get/forecast data Signed-off-by: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> * added co2_moer Signed-off-by: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> * done Signed-off-by: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> --------- Signed-off-by: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> --- Makefile | 33 +- README.md | 14 +- cli/Cargo.toml | 1 + cli/src/bindings.rs | 546 +++++++++++++++++++++++- cli/src/main.rs | 115 ++++- cli/wit/world.wit | 1 + githubapi/app.py | 11 +- goals.md | 9 +- watttime/app.py | 254 +++++++++++ watttime/green/__init__.py | 12 + watttime/green/exports/__init__.py | 32 ++ watttime/green/exports/watttime.py | 44 ++ watttime/green/imports/__init__.py | 0 watttime/green/imports/outgoing_http.py | 31 ++ watttime/green/types.py | 23 + watttime/wit/deps.lock | 4 + watttime/wit/deps.toml | 2 + watttime/wit/deps/httpclient/world.wit | 23 + watttime/wit/world.wit | 44 ++ 19 files changed, 1175 insertions(+), 24 deletions(-) create mode 100644 watttime/app.py create mode 100644 watttime/green/__init__.py create mode 100644 watttime/green/exports/__init__.py create mode 100644 watttime/green/exports/watttime.py create mode 100644 watttime/green/imports/__init__.py create mode 100644 watttime/green/imports/outgoing_http.py create mode 100644 watttime/green/types.py create mode 100644 watttime/wit/deps.lock create mode 100644 watttime/wit/deps.toml create mode 100644 watttime/wit/deps/httpclient/world.wit create mode 100644 watttime/wit/world.wit diff --git a/Makefile b/Makefile index 6e5be91..8b3069f 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,14 @@ gen-componentize-py-crypto: cd crypto && rm -rf crypto && \ componentize-py --wit-path wit/world.wit --world crypto bindings . + +.PHONY: gen-componentize-py-watttime +gen-componentize-py-watttime: + cd watttime && \ + wit-deps && \ + rm -rf green && \ + componentize-py --wit-path wit --world green bindings . + .PHONY: gen-componentize-py-githubapi gen-componentize-py-githubapi: cd githubapi && \ @@ -30,6 +38,7 @@ build_cli: wac plug cli/target/wasm32-wasi/release/cli.wasm \ --plug crypto/crypto.wasm \ --plug githubapi-composed.wasm \ + --plug watttime-composed.wasm \ --plug openai-composed.wasm \ -o composed.wasm @echo -e "${green}PASS${clear} wac plug for cli/" @@ -44,6 +53,20 @@ build_crypto: -o crypto.wasm @echo -e "${green}PASS${clear} Build for crypto/" +.PHONY: build_watttime +build_watttime: + cd watttime && \ + componentize-py \ + -d wit \ + -w green \ + componentize app \ + -o watttime.wasm + @echo -e "${green}PASS${clear} Build for watttime/" + wac plug watttime/watttime.wasm \ + --plug httpclient/target/wasm32-wasi/release/httpclient.wasm \ + -o watttime-composed.wasm + @echo -e "${green}PASS${clear} wac plug for watttime/" + .PHONY: build_github_api build_github_api: cd githubapi && \ @@ -79,7 +102,7 @@ build_httpclient: @echo -e "${green}PASS${clear} Build for httpclient/" .PHONY: build -build: build_httpclient build_crypto build_openai build_github_api build_cli +build: build_httpclient build_crypto build_openai build_watttime build_github_api build_cli @echo -e "${green}DONE${clear} Build all the components" @echo -e "next run the following commands make run_* to run the components" @@ -97,7 +120,11 @@ run_get_latest_release: .PHONY: run_openai run_openai: - wasmtime run -S http -S cli --dir=. composed.wasm -n dipankar --op openai + wasmtime run -S http --dir=. composed.wasm -n dipankar --op openai + +.PHONY: run_green +run_green: + wasmtime run -S http --dir=. composed.wasm -n dipankar --op green .PHONY: clean clean: @@ -105,10 +132,12 @@ clean: cli/target \ crypto/crypto.wasm \ githubapi/githubapi.wasm \ + watttime/watttime.wasm \ openai/openai.wasm \ httpclient/target \ wasihttpclient/target \ composed.wasm \ githubapi-composed.wasm \ + watttime-composed.wasm \ openai-composed.wasm @echo -e "${green}DONE${clear} removed all the compiled files" diff --git a/README.md b/README.md index f741cbc..a309311 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,20 @@ # Automate Using WASM -Why ti create this becuase this is the main selling point of the wasi to be able to create logic indenendent of the language and highly decoplied ways and with low latency and low footprint (Env Sustabanle ;>) +Why create this? +Becuase this is the main selling point of the wasi to be able to create logic indenendent of the language and highly decoplied ways and with low latency and low footprint (Env Sustabanle ;>) ## Skills to be achieved - use of wasm in real world uscase of FAAS - python openai, - rust cli - watttime api +- python +## How to use it +```shell +make build +make run_** +``` ## Dependency graph @@ -16,10 +23,13 @@ graph TD; cli(["`CLI Written **Rust**`"])-->crypto(["`Crypto Written **Python**`"]); cli-->githubapi(["`Githubapi Written **Python**`"]); cli-->openai(["`OpenAI LLM Written **Python**`"]); + cli-->watt(["`Watt_time client Written **Python**`"]); githubapi-->httpclient(["`HTTPClient Written **Rust**`"]); + watt-->httpclient; openai-->httpclient; httpclient-->wasi:http; ``` -`httpclient` uses `waki` crate for the http client +> `httpclient` uses `waki` crate for the http client + `wasihttpclient` uses the `wasi:http` crate for the http client which is actually used by `waki` diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 1f8acbb..6c4eaff 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -30,5 +30,6 @@ path = "wit" "dipankardas011:githubapi" = { path = "../githubapi/wit" } "dipankardas011:httpclient" = { path = "../httpclient/wit" } "dipankardas011:openai" = { path = "../openai/wit" } +"dipankardas011:watttime" = { path = "../watttime/wit" } [package.metadata.component.dependencies] diff --git a/cli/src/bindings.rs b/cli/src/bindings.rs index 765c17c..800b20b 100644 --- a/cli/src/bindings.rs +++ b/cli/src/bindings.rs @@ -186,6 +186,501 @@ pub mod dipankardas011 { } } } + #[allow(dead_code)] + pub mod watttime { + #[allow(dead_code, clippy::all)] + pub mod watttime { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + #[derive(Clone)] + pub struct PointData { + pub point_time: _rt::String, + pub value: f32, + } + impl ::core::fmt::Debug for PointData { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("PointData") + .field("point-time", &self.point_time) + .field("value", &self.value) + .finish() + } + } + #[derive(Clone)] + pub struct MetadataForecast { + pub data_point_period_seconds: i32, + pub region: _rt::String, + pub warnings: _rt::Vec<_rt::String>, + pub signal_type: _rt::String, + pub model: _rt::String, + pub units: _rt::String, + pub generated_at_period_seconds: i32, + pub generated_at: _rt::String, + } + impl ::core::fmt::Debug for MetadataForecast { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("MetadataForecast") + .field("data-point-period-seconds", &self.data_point_period_seconds) + .field("region", &self.region) + .field("warnings", &self.warnings) + .field("signal-type", &self.signal_type) + .field("model", &self.model) + .field("units", &self.units) + .field( + "generated-at-period-seconds", + &self.generated_at_period_seconds, + ) + .field("generated-at", &self.generated_at) + .finish() + } + } + #[derive(Clone)] + pub struct MetadataCo2MoerIndex { + pub data_point_period_seconds: i32, + pub region: _rt::String, + pub warnings: _rt::Vec<_rt::String>, + pub signal_type: _rt::String, + pub model: _rt::String, + pub units: _rt::String, + } + impl ::core::fmt::Debug for MetadataCo2MoerIndex { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("MetadataCo2MoerIndex") + .field("data-point-period-seconds", &self.data_point_period_seconds) + .field("region", &self.region) + .field("warnings", &self.warnings) + .field("signal-type", &self.signal_type) + .field("model", &self.model) + .field("units", &self.units) + .finish() + } + } + #[derive(Clone)] + pub struct Forecast { + pub data: _rt::Vec, + pub meta: MetadataForecast, + } + impl ::core::fmt::Debug for Forecast { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Forecast") + .field("data", &self.data) + .field("meta", &self.meta) + .finish() + } + } + #[derive(Clone)] + pub struct Co2MoerIndex { + pub data: PointData, + pub meta: MetadataCo2MoerIndex, + } + impl ::core::fmt::Debug for Co2MoerIndex { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Co2MoerIndex") + .field("data", &self.data) + .field("meta", &self.meta) + .finish() + } + } + #[allow(unused_unsafe, clippy::all)] + pub fn register(username: &str, password: &str, email: &str) -> bool { + unsafe { + let vec0 = username; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let vec1 = password; + let ptr1 = vec1.as_ptr().cast::(); + let len1 = vec1.len(); + let vec2 = email; + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "dipankardas011:watttime/watttime@0.1.0")] + extern "C" { + #[link_name = "register"] + fn wit_import( + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + ) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import( + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + ) -> i32 { + unreachable!() + } + let ret = wit_import( + ptr0.cast_mut(), + len0, + ptr1.cast_mut(), + len1, + ptr2.cast_mut(), + len2, + ); + _rt::bool_lift(ret as u8) + } + } + #[allow(unused_unsafe, clippy::all)] + pub fn get_token() -> Option<_rt::String> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let ptr0 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "dipankardas011:watttime/watttime@0.1.0")] + extern "C" { + #[link_name = "get-token"] + fn wit_import(_: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8) { + unreachable!() + } + wit_import(ptr0); + let l1 = i32::from(*ptr0.add(0).cast::()); + match l1 { + 0 => None, + 1 => { + let e = { + let l2 = *ptr0.add(4).cast::<*mut u8>(); + let l3 = *ptr0.add(8).cast::(); + let len4 = l3; + let bytes4 = _rt::Vec::from_raw_parts(l2.cast(), len4, len4); + + _rt::string_lift(bytes4) + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + #[allow(unused_unsafe, clippy::all)] + pub fn get_region(token: &str, signal_type: &str) -> Option<_rt::String> { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 12]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]); + let vec0 = token; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let vec1 = signal_type; + let ptr1 = vec1.as_ptr().cast::(); + let len1 = vec1.len(); + let ptr2 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "dipankardas011:watttime/watttime@0.1.0")] + extern "C" { + #[link_name = "get-region"] + fn wit_import(_: *mut u8, _: usize, _: *mut u8, _: usize, _: *mut u8); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: *mut u8, _: usize, _: *mut u8, _: usize, _: *mut u8) { + unreachable!() + } + wit_import(ptr0.cast_mut(), len0, ptr1.cast_mut(), len1, ptr2); + let l3 = i32::from(*ptr2.add(0).cast::()); + match l3 { + 0 => None, + 1 => { + let e = { + let l4 = *ptr2.add(4).cast::<*mut u8>(); + let l5 = *ptr2.add(8).cast::(); + let len6 = l5; + let bytes6 = _rt::Vec::from_raw_parts(l4.cast(), len6, len6); + + _rt::string_lift(bytes6) + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + #[allow(unused_unsafe, clippy::all)] + pub fn get_forecast(token: &str, region: &str, signal_type: &str) -> Option { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 68]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 68]); + let vec0 = token; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let vec1 = region; + let ptr1 = vec1.as_ptr().cast::(); + let len1 = vec1.len(); + let vec2 = signal_type; + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + let ptr3 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "dipankardas011:watttime/watttime@0.1.0")] + extern "C" { + #[link_name = "get-forecast"] + fn wit_import( + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import( + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + ) { + unreachable!() + } + wit_import( + ptr0.cast_mut(), + len0, + ptr1.cast_mut(), + len1, + ptr2.cast_mut(), + len2, + ptr3, + ); + let l4 = i32::from(*ptr3.add(0).cast::()); + match l4 { + 0 => None, + 1 => { + let e = { + let l5 = *ptr3.add(4).cast::<*mut u8>(); + let l6 = *ptr3.add(8).cast::(); + let base11 = l5; + let len11 = l6; + let mut result11 = _rt::Vec::with_capacity(len11); + for i in 0..len11 { + let base = base11.add(i * 12); + let e11 = { + let l7 = *base.add(0).cast::<*mut u8>(); + let l8 = *base.add(4).cast::(); + let len9 = l8; + let bytes9 = + _rt::Vec::from_raw_parts(l7.cast(), len9, len9); + let l10 = *base.add(8).cast::(); + + PointData { + point_time: _rt::string_lift(bytes9), + value: l10, + } + }; + result11.push(e11); + } + _rt::cabi_dealloc(base11, len11 * 12, 4); + let l12 = *ptr3.add(12).cast::(); + let l13 = *ptr3.add(16).cast::<*mut u8>(); + let l14 = *ptr3.add(20).cast::(); + let len15 = l14; + let bytes15 = _rt::Vec::from_raw_parts(l13.cast(), len15, len15); + let l16 = *ptr3.add(24).cast::<*mut u8>(); + let l17 = *ptr3.add(28).cast::(); + let base21 = l16; + let len21 = l17; + let mut result21 = _rt::Vec::with_capacity(len21); + for i in 0..len21 { + let base = base21.add(i * 8); + let e21 = { + let l18 = *base.add(0).cast::<*mut u8>(); + let l19 = *base.add(4).cast::(); + let len20 = l19; + let bytes20 = + _rt::Vec::from_raw_parts(l18.cast(), len20, len20); + + _rt::string_lift(bytes20) + }; + result21.push(e21); + } + _rt::cabi_dealloc(base21, len21 * 8, 4); + let l22 = *ptr3.add(32).cast::<*mut u8>(); + let l23 = *ptr3.add(36).cast::(); + let len24 = l23; + let bytes24 = _rt::Vec::from_raw_parts(l22.cast(), len24, len24); + let l25 = *ptr3.add(40).cast::<*mut u8>(); + let l26 = *ptr3.add(44).cast::(); + let len27 = l26; + let bytes27 = _rt::Vec::from_raw_parts(l25.cast(), len27, len27); + let l28 = *ptr3.add(48).cast::<*mut u8>(); + let l29 = *ptr3.add(52).cast::(); + let len30 = l29; + let bytes30 = _rt::Vec::from_raw_parts(l28.cast(), len30, len30); + let l31 = *ptr3.add(56).cast::(); + let l32 = *ptr3.add(60).cast::<*mut u8>(); + let l33 = *ptr3.add(64).cast::(); + let len34 = l33; + let bytes34 = _rt::Vec::from_raw_parts(l32.cast(), len34, len34); + + Forecast { + data: result11, + meta: MetadataForecast { + data_point_period_seconds: l12, + region: _rt::string_lift(bytes15), + warnings: result21, + signal_type: _rt::string_lift(bytes24), + model: _rt::string_lift(bytes27), + units: _rt::string_lift(bytes30), + generated_at_period_seconds: l31, + generated_at: _rt::string_lift(bytes34), + }, + } + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + #[allow(unused_unsafe, clippy::all)] + pub fn get_current_co2_moer_index( + token: &str, + region: &str, + signal_type: &str, + ) -> Option { + unsafe { + #[repr(align(4))] + struct RetArea([::core::mem::MaybeUninit; 60]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 60]); + let vec0 = token; + let ptr0 = vec0.as_ptr().cast::(); + let len0 = vec0.len(); + let vec1 = region; + let ptr1 = vec1.as_ptr().cast::(); + let len1 = vec1.len(); + let vec2 = signal_type; + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + let ptr3 = ret_area.0.as_mut_ptr().cast::(); + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "dipankardas011:watttime/watttime@0.1.0")] + extern "C" { + #[link_name = "get-current-CO2-MOER-index"] + fn wit_import( + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import( + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + _: usize, + _: *mut u8, + ) { + unreachable!() + } + wit_import( + ptr0.cast_mut(), + len0, + ptr1.cast_mut(), + len1, + ptr2.cast_mut(), + len2, + ptr3, + ); + let l4 = i32::from(*ptr3.add(0).cast::()); + match l4 { + 0 => None, + 1 => { + let e = { + let l5 = *ptr3.add(4).cast::<*mut u8>(); + let l6 = *ptr3.add(8).cast::(); + let len7 = l6; + let bytes7 = _rt::Vec::from_raw_parts(l5.cast(), len7, len7); + let l8 = *ptr3.add(12).cast::(); + let l9 = *ptr3.add(16).cast::(); + let l10 = *ptr3.add(20).cast::<*mut u8>(); + let l11 = *ptr3.add(24).cast::(); + let len12 = l11; + let bytes12 = _rt::Vec::from_raw_parts(l10.cast(), len12, len12); + let l13 = *ptr3.add(28).cast::<*mut u8>(); + let l14 = *ptr3.add(32).cast::(); + let base18 = l13; + let len18 = l14; + let mut result18 = _rt::Vec::with_capacity(len18); + for i in 0..len18 { + let base = base18.add(i * 8); + let e18 = { + let l15 = *base.add(0).cast::<*mut u8>(); + let l16 = *base.add(4).cast::(); + let len17 = l16; + let bytes17 = + _rt::Vec::from_raw_parts(l15.cast(), len17, len17); + + _rt::string_lift(bytes17) + }; + result18.push(e18); + } + _rt::cabi_dealloc(base18, len18 * 8, 4); + let l19 = *ptr3.add(36).cast::<*mut u8>(); + let l20 = *ptr3.add(40).cast::(); + let len21 = l20; + let bytes21 = _rt::Vec::from_raw_parts(l19.cast(), len21, len21); + let l22 = *ptr3.add(44).cast::<*mut u8>(); + let l23 = *ptr3.add(48).cast::(); + let len24 = l23; + let bytes24 = _rt::Vec::from_raw_parts(l22.cast(), len24, len24); + let l25 = *ptr3.add(52).cast::<*mut u8>(); + let l26 = *ptr3.add(56).cast::(); + let len27 = l26; + let bytes27 = _rt::Vec::from_raw_parts(l25.cast(), len27, len27); + + Co2MoerIndex { + data: PointData { + point_time: _rt::string_lift(bytes7), + value: l8, + }, + meta: MetadataCo2MoerIndex { + data_point_period_seconds: l9, + region: _rt::string_lift(bytes12), + warnings: result18, + signal_type: _rt::string_lift(bytes21), + model: _rt::string_lift(bytes24), + units: _rt::string_lift(bytes27), + }, + } + }; + Some(e) + } + _ => _rt::invalid_enum_discriminant(), + } + } + } + } + } } mod _rt { pub use alloc_crate::string::String; @@ -267,22 +762,61 @@ mod _rt { String::from_utf8_unchecked(bytes) } } + pub unsafe fn bool_lift(val: u8) -> bool { + if cfg!(debug_assertions) { + match val { + 0 => false, + 1 => true, + _ => panic!("invalid bool discriminant"), + } + } else { + val != 0 + } + } + pub unsafe fn invalid_enum_discriminant() -> T { + if cfg!(debug_assertions) { + panic!("invalid enum discriminant") + } else { + core::hint::unreachable_unchecked() + } + } + pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) { + if size == 0 { + return; + } + let layout = alloc::Layout::from_size_align_unchecked(size, align); + alloc::dealloc(ptr as *mut u8, layout); + } extern crate alloc as alloc_crate; + pub use alloc_crate::alloc; } #[cfg(target_arch = "wasm32")] #[link_section = "component-type:wit-bindgen:0.25.0:app:encoded world"] #[doc(hidden)] -pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 448] = *b"\ -\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xc6\x02\x01A\x02\x01\ -A\x06\x01B\x02\x01@\x01\x06lengthy\0s\x04\0\x0fgenerate-random\x01\0\x03\x01$dip\ +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1074] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xb8\x07\x01A\x02\x01\ +A\x08\x01B\x02\x01@\x01\x06lengthy\0s\x04\0\x0fgenerate-random\x01\0\x03\x01$dip\ ankardas011:crypto/password@0.1.0\x05\0\x01B\x05\x01@\x02\x03orgs\x04projs\0s\x04\ \0\x12get-latest-release\x01\0\x04\0\x10get-contributors\x01\0\x01@\x02\x03orgs\x04\ projs\0{\x04\0\x09get-stars\x01\x01\x03\x01'dipankardas011:githubapi/releases@0.\ 1.0\x05\x01\x01B\x03\x01@\0\x01\0\x04\0\x0ctext-to-text\x01\0\x04\0\x0dtext-to-i\ -mage\x01\0\x03\x01\x1fdipankardas011:openai/llm@0.1.0\x05\x02\x04\x01\x16dipanka\ -rdas011:cli/app\x04\0\x0b\x09\x01\0\x03app\x03\0\0\0G\x09producers\x01\x0cproces\ -sed-by\x02\x0dwit-component\x070.208.1\x10wit-bindgen-rust\x060.25.0"; +mage\x01\0\x03\x01\x1fdipankardas011:openai/llm@0.1.0\x05\x02\x01B\x19\x01r\x02\x0a\ +point-times\x05valuev\x04\0\x0apoint-data\x03\0\0\x01ps\x01r\x08\x19data-point-p\ +eriod-secondsz\x06regions\x08warnings\x02\x0bsignal-types\x05models\x05unitss\x1b\ +generated-at-period-secondsz\x0cgenerated-ats\x04\0\x11metadata-forecast\x03\0\x03\ +\x01r\x06\x19data-point-period-secondsz\x06regions\x08warnings\x02\x0bsignal-typ\ +es\x05models\x05unitss\x04\0\x17metadata-co2-moer-index\x03\0\x05\x01p\x01\x01r\x02\ +\x04data\x07\x04meta\x04\x04\0\x08forecast\x03\0\x08\x01r\x02\x04data\x01\x04met\ +a\x06\x04\0\x0eco2-moer-index\x03\0\x0a\x01@\x03\x08usernames\x08passwords\x05em\ +ails\0\x7f\x04\0\x08register\x01\x0c\x01ks\x01@\0\0\x0d\x04\0\x09get-token\x01\x0e\ +\x01@\x02\x05tokens\x0bsignal-types\0\x0d\x04\0\x0aget-region\x01\x0f\x01k\x09\x01\ +@\x03\x05tokens\x06regions\x0bsignal-types\0\x10\x04\0\x0cget-forecast\x01\x11\x01\ +k\x0b\x01@\x03\x05tokens\x06regions\x0bsignal-types\0\x12\x04\0\x1aget-current-C\ +O2-MOER-index\x01\x13\x03\x01&dipankardas011:watttime/watttime@0.1.0\x05\x03\x04\ +\x01\x16dipankardas011:cli/app\x04\0\x0b\x09\x01\0\x03app\x03\0\0\0G\x09producer\ +s\x01\x0cprocessed-by\x02\x0dwit-component\x070.208.1\x10wit-bindgen-rust\x060.2\ +5.0"; #[inline(never)] #[doc(hidden)] diff --git a/cli/src/main.rs b/cli/src/main.rs index 74bf96d..f5bd658 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -10,15 +10,17 @@ use bindings::dipankardas011::{ crypto::password::generate_random, githubapi::releases, openai::llm, + watttime, }; use anyhow::Result; use ansi_term; -use ansi_term::Colour::{Cyan,Black,Red, Green, Blue, Yellow}; +use ansi_term::Colour::{Cyan, Black, Red, Green, Blue, Yellow}; const FILE_PATH: &str = "README.md"; const OP_CRYPTO: &str = "crypto"; const OP_GITHUBAPI: &str = "githubapi"; const OP_OPENAI: &str = "openai"; +const OP_GREEN: &str = "green"; const OP_DEMO: &str = "demo"; #[derive(Parser, Debug)] @@ -27,7 +29,7 @@ struct CommandToPerform { #[arg(short = 'n', long = "name")] name: String, - #[arg(short='o', long="op", value_parser=[OP_CRYPTO, OP_GITHUBAPI, OP_DEMO, OP_OPENAI], default_value_t=OP_DEMO.to_string())] + #[arg(short='o', long="op", value_parser=[OP_CRYPTO, OP_GITHUBAPI, OP_DEMO, OP_OPENAI, OP_GREEN], default_value_t=OP_DEMO.to_string())] operation: String, } @@ -47,6 +49,115 @@ async fn main() -> Result<()> { hh(&args.name).await; match args.operation.as_str() { + OP_GREEN => { + println!("{}", Cyan.paint("> Enter [1] register [2] get region code based on curr loc [3] get forecast based on current loc [4] get current CO2 MOER index")); + let mut input = String::new(); + std::io::stdin().read_line(&mut input).expect("Failed to read line"); + let choice: i32 = input.trim().parse().expect("Invalid Input"); + if choice < 1 || choice > 4 { + eprintln!("{}", Red.bold().paint("Invalid choice")); + } + if choice == 1 { + println!("{}", Cyan.paint(" > Enter UserName")); + let mut input_username = String::new(); + std::io::stdin().read_line(&mut input_username).expect("Failed to read line"); + let username: String = input_username.trim().parse().expect("invalid organization"); + + println!("{}", Cyan.paint(" > Enter Password")); + let mut input_password = String::new(); + std::io::stdin().read_line(&mut input_password).expect("Failed to read line"); + let password: String = input_password.trim().parse().expect("invalid organization"); + + println!("{}", Cyan.paint(" > Enter Email")); + let mut input_email = String::new(); + std::io::stdin().read_line(&mut input_email).expect("Failed to read line"); + let email: String = input_email.trim().parse().expect("invalid organization"); + + watttime::watttime::register(&username, &password, &email); + } else if choice == 2 { + + println!("{}", Cyan.paint(" > Enter Watttime Signal type co2_moer or health_damage: ")); + let mut input = String::new(); + std::io::stdin().read_line(&mut input).expect("Failed to read line"); + let choice: String= input.trim().parse().expect("Invalid Input"); + if choice != "co2_moer" && choice != "health_damage" { + eprintln!("{}", Red.bold().paint("Invalid choice")); + } + + let token = watttime::watttime::get_token(); + if let None = token { + eprintln!("{}", Red.bold().paint("Failed to get token")); + } + let t = token.unwrap(); + let region_code = watttime::watttime::get_region(&t, &choice); + match region_code { + Some(code) => { + println!("{}: {code}", Green.bold().paint("Region Code")); + } + None => { + eprintln!("{}", Red.bold().paint("Failed to get region code")); + } + } + } else if choice == 3 { + println!("{}", Cyan.paint(" > Enter Watttime Signal type co2_moer or health_damage: ")); + let mut input = String::new(); + std::io::stdin().read_line(&mut input).expect("Failed to read line"); + let choice: String= input.trim().parse().expect("Invalid Input"); + if choice != "co2_moer" && choice != "health_damage" { + eprintln!("{}", Red.bold().paint("Invalid choice")); + } + + let token = watttime::watttime::get_token(); + if let None = token { + eprintln!("{}", Red.bold().paint("Failed to get token")); + } + let t = token.unwrap(); + let region_code = watttime::watttime::get_region(&t, &choice); + match region_code { + Some(code) => { + println!("{}: {code}", Green.bold().paint("Region Code")); + + let dd = watttime::watttime::get_forecast(&t, &code, &choice); + match dd { + Some(d) => { + println!("{}\n{d:?}", Blue.paint("Most recently generated forecast for the specified region and signal_type. Forecasts are generated periodically (e.g. at 5-minute frequency, this frequency is described in the generated_at_period_seconds metadata), and there is a data list made up of point_time and value pairs in the forecast horizon (e.g. a 24-hr forecast horizon with 5-min frequency results in 288 values). Each forecast response is valid starting from its generated_at time until it is superseded by a new forecast with a new generated_at time, and each point_time in the data list is valid from its point_time for the duration described in data_point_period_seconds")); + } + None => { + eprintln!("{}", Red.bold().paint("Failed to get forecast")); + } + } + } + None => { + eprintln!("{}", Red.bold().paint("Failed to get region code")); + } + } + } else { + let token = watttime::watttime::get_token(); + if let None = token { + eprintln!("{}", Red.bold().paint("Failed to get token")); + } + let t = token.unwrap(); + let region_code = watttime::watttime::get_region(&t, ""); + match region_code { + Some(code) => { + println!("{}: {code}", Green.bold().paint("Region Code")); + let dd = watttime::watttime::get_current_co2_moer_index(&t, &code, ""); // current + // only co2_moer + match dd { + Some(d) => { + println!("{}\n{d:?}", Blue.paint("Current Index value for the specified region for the co2_moer signal type. This 0-100 value is the statistical percentile of the current MOER relative to the upcoming 24 hours of forecast MOER values for the specified location (100=dirtiest, 0=cleanest). Values are updated periodically (e.g. at 5-minute frequency), and each value is valid starting from its point_time for the duration described in data_point_period_seconds. No historical query is available for this endpoint.")); + } + None => { + eprintln!("{}", Red.bold().paint("Failed to get forecast")); + } + } + } + None => { + eprintln!("{}", Red.bold().paint("Failed to get region code")); + } + } + } + } OP_OPENAI => { println!("{}", Cyan.paint("> Enter [1] text-to-text [2] text-to-image")); let mut input = String::new(); diff --git a/cli/wit/world.wit b/cli/wit/world.wit index cc7cb95..ae20574 100644 --- a/cli/wit/world.wit +++ b/cli/wit/world.wit @@ -4,5 +4,6 @@ world app { import dipankardas011:crypto/password@0.1.0; import dipankardas011:githubapi/releases@0.1.0; import dipankardas011:openai/llm@0.1.0; + import dipankardas011:watttime/watttime@0.1.0; } diff --git a/githubapi/app.py b/githubapi/app.py index 2b051e0..61a4eb7 100644 --- a/githubapi/app.py +++ b/githubapi/app.py @@ -3,6 +3,7 @@ from project.imports import outgoing_http import json import traceback +from termcolor import colored, cprint class Releases(exports.Releases): @@ -21,7 +22,8 @@ def get_latest_release(self, org: str, proj: str) -> str: data = json.loads(http_res.body) return data["tag_name"] except Exception as e: - print(f"Caught Exception: {e}") + text = colored(f"Caught Exception: {e}", "red", attrs=["reverse", "blink"]) + print(f"{text}") traceback.print_exc() return "Failed to get the response" @@ -48,7 +50,8 @@ def get_contributors(self, org: str, proj: str) -> str: return ret except Exception as e: - print(f"Caught Exception: {e}") + text = colored(f"Caught Exception: {e}", "red", attrs=["reverse", "blink"]) + print(f"{text}") traceback.print_exc() return "Failed to get the response" @@ -79,7 +82,7 @@ def get_stars(self, org: str, proj: str) -> int: return len(githubId) except Exception as e: - print(f"Caught Exception: {e}") + text = colored(f"Caught Exception: {e}", "red", attrs=["reverse", "blink"]) + print(f"{text}") traceback.print_exc() - print("Failed to get the response") return -999 diff --git a/goals.md b/goals.md index 825d225..2e478d6 100644 --- a/goals.md +++ b/goals.md @@ -57,18 +57,11 @@ Integrate the above two goals [3](#goal-3) [4](#goal-4) [5](#goal-5) ## Goal 7 -- [ ] Achieved? +- [x] Achieved? - Use wattime api https://docs.watttime.org/ -## Goal 8 - -- [ ] Achieved? - -- create a vault client for intereacting with it - - > [!IMPORTANT] > Finally deploy using these in a docker container and runtimeclass in K8s diff --git a/watttime/app.py b/watttime/app.py new file mode 100644 index 0000000..bbb963e --- /dev/null +++ b/watttime/app.py @@ -0,0 +1,254 @@ +from typing import override +from green import exports +from green.imports import outgoing_http +import json +import traceback +import os +from dotenv import load_dotenv +import base64 +from termcolor import colored, cprint + + +class Watttime(exports.Watttime): + @override + def get_region(self, token: str, signal_type: str) -> str | None: + try: + http_res = outgoing_http.get_request( + method="GET", + headers=[ + outgoing_http.RequestHeader( + key="Content-Type", value="application/json", + ) + ], + url="https://ipinfo.io", + body=None) + + if http_res.status_code != 200: + raise Exception(f"StatusCode: {http_res.status_code}, Reason: {str(http_res.body)}") + + data = json.loads(http_res.body) + loc = data['loc'] + lat_lon = loc.split(",") + if signal_type == "": + signal_type = "co2_moer" + url = f"https://api.watttime.org/v3/region-from-loc?latitude={lat_lon[0]}&longitude={lat_lon[1]}&signal_type={signal_type}" + http_res = outgoing_http.get_request( + method="GET", + headers=[ + outgoing_http.RequestHeader( + key="Authorization", value=f"Bearer {token}", + ) + ], + url=url, + body=None) + + if http_res.status_code != 200: + raise Exception(f"StatusCode: {http_res.status_code}, Reason: {str(http_res.body)}") + + data = json.loads(http_res.body) + return data['region'] + + except Exception as e: + text = colored(f"Caught Exception: {e}", "red", attrs=["reverse", "blink"]) + print(f"{text}") + traceback.print_exc() + return None + + @override + def get_forecast(self, token: str, region: str, signal_type) -> exports.watttime.Forecast | None: + try: + if signal_type == "": + signal_type = "co2_moer" + url = f"https://api.watttime.org/v3/forecast?region={region}&horizon_hours=1&signal_type={signal_type}" + http_res = outgoing_http.get_request( + method="GET", + headers=[ + outgoing_http.RequestHeader( + key="Authorization", value=f"Bearer {token}", + ) + ], + url=url, + body=None) + + if http_res.status_code == 403: + data = json.loads(http_res.body) + print(colored(f"Trying to recover and use default region 'CAISO_NORTH' {data['error']}=>{data['message']}", "light_yellow")) + url = f"https://api.watttime.org/v3/forecast?region=CAISO_NORTH&horizon_hours=1&signal_type={signal_type}" + http_res = outgoing_http.get_request( + method="GET", + headers=[ + outgoing_http.RequestHeader( + key="Authorization", value=f"Bearer {token}", + ) + ], + url=url, + body=None) + if http_res.status_code != 200: + raise Exception(f"StatusCode: {http_res.status_code}, Reason: {str(http_res.body)}") + + elif http_res.status_code != 200: + raise Exception(f"StatusCode: {http_res.status_code}, Reason: {str(http_res.body)}") + + data = json.loads(http_res.body) + data_pointers = [exports.watttime.PointData( + point_time=item['point_time'], + value=item['value']) for item in data['data']] + + meta_pointers = data['meta'] + meta_warnings = [f"{item['type']}:{item['message']}" for item in meta_pointers['warnings']] + + obj = exports.watttime.Forecast( + data=data_pointers, + meta=exports.watttime.MetadataForecast( + data_point_period_seconds=meta_pointers['data_point_period_seconds'], + region=meta_pointers['region'], + signal_type=meta_pointers['signal_type'], + model=meta_pointers['model']['date'], + warnings=meta_warnings, + units=meta_pointers['units'], + generated_at=meta_pointers['generated_at'], + generated_at_period_seconds=meta_pointers['generated_at_period_seconds'], + ) + ) + return obj + + except Exception as e: + text = colored(f"Caught Exception: {e}", "red", attrs=["reverse", "blink"]) + print(f"{text}") + traceback.print_exc() + return None + + def get_current_co2_moer_index(self, token: str, region: str, signal_type: str) -> exports.watttime.Co2MoerIndex | None: + try: + if signal_type == "": + signal_type = "co2_moer" + url = f"https://api.watttime.org/v3/signal-index?region={region}&signal_type={signal_type}" + http_res = outgoing_http.get_request( + method="GET", + headers=[ + outgoing_http.RequestHeader( + key="Authorization", value=f"Bearer {token}", + ) + ], + url=url, + body=None) + + if http_res.status_code == 403: + data = json.loads(http_res.body) + print(colored(f"Trying to recover and use default region 'CAISO_NORTH' {data['error']}=>{data['message']}", "light_yellow")) + url = f"https://api.watttime.org/v3/signal-index?region=CAISO_NORTH&signal_type={signal_type}" + http_res = outgoing_http.get_request( + method="GET", + headers=[ + outgoing_http.RequestHeader( + key="Authorization", value=f"Bearer {token}", + ) + ], + url=url, + body=None) + if http_res.status_code != 200: + raise Exception(f"StatusCode: {http_res.status_code}, Reason: {str(http_res.body)}") + + elif http_res.status_code != 200: + raise Exception(f"StatusCode: {http_res.status_code}, Reason: {str(http_res.body)}") + + data = json.loads(http_res.body) + data_pointers = [exports.watttime.PointData( + point_time=item['point_time'], + value=item['value']) for item in data['data']] + + meta_pointers = data['meta'] + meta_warnings = [f"{item['type']}:{item['message']}" for item in meta_pointers['warnings']] + + obj = exports.watttime.Co2MoerIndex( + data=data_pointers[0], + meta=exports.watttime.MetadataCo2MoerIndex( + data_point_period_seconds=meta_pointers['data_point_period_seconds'], + region=meta_pointers['region'], + signal_type=meta_pointers['signal_type'], + model=f"{meta_pointers['model']}", + warnings=meta_warnings, + units=meta_pointers['units'], + ) + ) + return obj + + except Exception as e: + text = colored(f"Caught Exception: {e}", "red", attrs=["reverse", "blink"]) + print(f"{text}") + traceback.print_exc() + return None + + @override + def register(self, username: str, password: str, email: str) -> bool: + + try: + body = { + "username": username, + "password": password, + "email": email, + } + r_body = json.dumps(body) + + http_res = outgoing_http.get_request( + method="POST", + headers=[ + outgoing_http.RequestHeader( + key="Content-Type", value="application/json", + ) + ], + url="https://api.watttime.org/register", + body=r_body.encode('utf-8')) + + if http_res.status_code != 200: + raise Exception(f"StatusCode: {http_res.status_code}, Reason: {str(http_res.body)}") + + data = json.loads(http_res.body) + print(f"Registration successful {data}") + return True + except Exception as e: + text = colored(f"Caught Exception: {e}", "red", attrs=["reverse", "blink"]) + print(f"{text}") + traceback.print_exc() + return False + + @override + def get_token(self) -> str | None: + load_dotenv() + try: + + token_tt = os.getenv("WATTTIME_TOKEN") + if token_tt is not None: + print(f"{colored("Using Token present in .env", "green")}") + return token_tt + + token_usr = os.getenv("WATTTIME_USERNAME") + if token_usr is None: + raise Exception("env:$WATTTIME_USERNAME is not set") + token_pass = os.getenv("WATTTIME_PASSWORD") + if token_pass is None: + raise Exception("env:$WATTTIME_PASSWORD is not set") + + encoded_data = base64.b64encode(f"{token_usr}:{token_pass}".encode('utf-8')).decode('utf-8') + + http_res = outgoing_http.get_request( + method="GET", + headers=[ + outgoing_http.RequestHeader( + key="Authorization", value=f"Basic {encoded_data}", + ) + ], + url="https://api.watttime.org/login", + body=None) + + if http_res.status_code != 200: + raise Exception(f"StatusCode: {http_res.status_code}, Reason: {str(http_res.body)}") + + data = json.loads(http_res.body) + resp = data['token'] + return resp + + except Exception as e: + text = colored(f"Caught Exception: {e}", "red", attrs=["reverse", "blink"]) + print(f"{text}") + traceback.print_exc() diff --git a/watttime/green/__init__.py b/watttime/green/__init__.py new file mode 100644 index 0000000..d40d2fe --- /dev/null +++ b/watttime/green/__init__.py @@ -0,0 +1,12 @@ +from typing import TypeVar, Generic, Union, Optional, Protocol, Tuple, List, Any, Self +from enum import Flag, Enum, auto +from dataclasses import dataclass +from abc import abstractmethod +import weakref + +from .types import Result, Ok, Err, Some + + + +class Green(Protocol): + pass diff --git a/watttime/green/exports/__init__.py b/watttime/green/exports/__init__.py new file mode 100644 index 0000000..96a536d --- /dev/null +++ b/watttime/green/exports/__init__.py @@ -0,0 +1,32 @@ +from typing import TypeVar, Generic, Union, Optional, Protocol, Tuple, List, Any, Self +from enum import Flag, Enum, auto +from dataclasses import dataclass +from abc import abstractmethod +import weakref + +from ..types import Result, Ok, Err, Some +from ..exports import watttime + +class Watttime(Protocol): + + @abstractmethod + def register(self, username: str, password: str, email: str) -> bool: + raise NotImplementedError + + @abstractmethod + def get_token(self) -> Optional[str]: + raise NotImplementedError + + @abstractmethod + def get_region(self, token: str, signal_type: str) -> Optional[str]: + raise NotImplementedError + + @abstractmethod + def get_forecast(self, token: str, region: str, signal_type: str) -> Optional[watttime.Forecast]: + raise NotImplementedError + + @abstractmethod + def get_current_co2_moer_index(self, token: str, region: str, signal_type: str) -> Optional[watttime.Co2MoerIndex]: + raise NotImplementedError + + diff --git a/watttime/green/exports/watttime.py b/watttime/green/exports/watttime.py new file mode 100644 index 0000000..89e04d6 --- /dev/null +++ b/watttime/green/exports/watttime.py @@ -0,0 +1,44 @@ +from typing import TypeVar, Generic, Union, Optional, Protocol, Tuple, List, Any, Self +from enum import Flag, Enum, auto +from dataclasses import dataclass +from abc import abstractmethod +import weakref + +from ..types import Result, Ok, Err, Some + + +@dataclass +class PointData: + point_time: str + value: float + +@dataclass +class MetadataForecast: + data_point_period_seconds: int + region: str + warnings: List[str] + signal_type: str + model: str + units: str + generated_at_period_seconds: int + generated_at: str + +@dataclass +class MetadataCo2MoerIndex: + data_point_period_seconds: int + region: str + warnings: List[str] + signal_type: str + model: str + units: str + +@dataclass +class Forecast: + data: List[PointData] + meta: MetadataForecast + +@dataclass +class Co2MoerIndex: + data: PointData + meta: MetadataCo2MoerIndex + diff --git a/watttime/green/imports/__init__.py b/watttime/green/imports/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/watttime/green/imports/outgoing_http.py b/watttime/green/imports/outgoing_http.py new file mode 100644 index 0000000..614e604 --- /dev/null +++ b/watttime/green/imports/outgoing_http.py @@ -0,0 +1,31 @@ +from typing import TypeVar, Generic, Union, Optional, Protocol, Tuple, List, Any, Self +from enum import Flag, Enum, auto +from dataclasses import dataclass +from abc import abstractmethod +import weakref + +from ..types import Result, Ok, Err, Some + + +@dataclass +class Response: + status_code: int + headers: str + body: bytes + +@dataclass +class RequestHeader: + key: str + value: str + +@dataclass +class Reserror: + msg: str + + +def get_request(method: str, headers: List[RequestHeader], url: str, body: Optional[bytes]) -> Response: + """ + Raises: `green.types.Err(green.imports.outgoing_http.Reserror)` + """ + raise NotImplementedError + diff --git a/watttime/green/types.py b/watttime/green/types.py new file mode 100644 index 0000000..77ad379 --- /dev/null +++ b/watttime/green/types.py @@ -0,0 +1,23 @@ +from typing import TypeVar, Generic, Union, Optional, Protocol, Tuple, List, Any, Self +from enum import Flag, Enum, auto +from dataclasses import dataclass +from abc import abstractmethod +import weakref + + +S = TypeVar('S') +@dataclass +class Some(Generic[S]): + value: S + +T = TypeVar('T') +@dataclass +class Ok(Generic[T]): + value: T + +E = TypeVar('E') +@dataclass(frozen=True) +class Err(Generic[E], Exception): + value: E + +Result = Union[Ok[T], Err[E]] diff --git a/watttime/wit/deps.lock b/watttime/wit/deps.lock new file mode 100644 index 0000000..f25ed23 --- /dev/null +++ b/watttime/wit/deps.lock @@ -0,0 +1,4 @@ +[httpclient] +path = "../../httpclient/wit" +sha256 = "6d36dd8541e60e2a29c709e4cf2a97af9cbcd9d350970be1d08b4a20dfcd05e4" +sha512 = "1fe36dd68c61d8c5ef9a1115f5e944f10a9998d161dbca57a41603a4775a8876ae3564b246f2ab0c9b3f1457ec23d8ffbdb8dd1e8052f19698c3ed901c5e17a6" diff --git a/watttime/wit/deps.toml b/watttime/wit/deps.toml new file mode 100644 index 0000000..c5401bd --- /dev/null +++ b/watttime/wit/deps.toml @@ -0,0 +1,2 @@ +# wit/deps.toml +httpclient = "../../httpclient/wit" diff --git a/watttime/wit/deps/httpclient/world.wit b/watttime/wit/deps/httpclient/world.wit new file mode 100644 index 0000000..ba41284 --- /dev/null +++ b/watttime/wit/deps/httpclient/world.wit @@ -0,0 +1,23 @@ +package dipankardas011:httpclient@0.1.0; + +interface outgoing-http { + record response { + status-code: u16, + headers: string, + body: list + } + + record request-header { + key: string, + value: string + } + + record reserror { + msg: string + } + get-request: func(method: string, headers: list, url: string, body: option>) -> result; +} + +world http { + export outgoing-http; +} diff --git a/watttime/wit/world.wit b/watttime/wit/world.wit new file mode 100644 index 0000000..8ad7bef --- /dev/null +++ b/watttime/wit/world.wit @@ -0,0 +1,44 @@ +package dipankardas011:watttime@0.1.0; + +interface watttime { + record point-data { + point-time: string, + value: f32 + } + record metadata-forecast { + data-point-period-seconds: s32, + region: string, + warnings: list, + signal-type: string, + model: string, + units: string, + generated-at-period-seconds: s32, + generated-at: string + } + record metadata-co2-moer-index { + data-point-period-seconds: s32, + region: string, + warnings: list, + signal-type: string, + model: string, + units: string, + } + record forecast { + data: list, + meta: metadata-forecast + } + record co2-moer-index { + data: point-data, + meta: metadata-co2-moer-index + } + register: func(username: string, password: string, email: string) -> bool; + get-token: func() -> option; + get-region: func(token: string, signal-type: string) -> option; + get-forecast: func(token: string, region: string, signal-type: string) -> option; + get-current-CO2-MOER-index: func(token: string, region: string, signal-type: string) -> option; +} + +world green { + export watttime; + import dipankardas011:httpclient/outgoing-http@0.1.0; +}