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
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
pub extern crate prost;
pub extern crate wascap_codec;

use crate::guestmem::Stack;
use crate::kv::HostKeyValueStore;
use crate::kv::KeyValueStore;
use prost::Message;
use wascap_codec as codec;


pub type Result<T> = std::result::Result<T, errors::Error>;

pub const SOURCE_GUEST: &'static str = "guest";

#[link(wasm_import_module = "wascap")]
extern "C" {
    fn __throw(a: *const u8, b: usize) -> !;
    fn __console_log(ptr: *const u8, len: usize);
    fn __host_call(ptr: *const u8, len: usize, retptr: *const u8) -> i32;
}

pub(crate) fn do_host_call(cmd: &codec::core::Command) -> Result<codec::core::Event> {
    let mut cmdbytes = Vec::new();
    cmd.encode(&mut cmdbytes)?;

    let result_slice = unsafe {
        let mut __stack = { guestmem::GlobalStack::new() };
        let buf: Vec<u8> = Vec::new();
        let retptr = buf.as_ptr();
        //__stack.push(buf.as_ptr() as u32);
        let result_len = { __host_call(cmdbytes.as_ptr(), cmdbytes.len() as _, retptr) };
        std::slice::from_raw_parts(retptr as _, result_len as _)
    };

    let event = codec::core::Event::decode(result_slice)?;
    Ok(event)
}

#[macro_export]
macro_rules! call_handler {
    ($user_handler:ident) => {
        #[no_mangle]
        pub extern "C" fn __guest_call(param_ptr: i32, len: i32) -> i32 {
            use std::slice;
            use $crate::guestmem;
            use $crate::guestmem::Stack;
            use $crate::prost::Message;

            let req = {
                let mut __stack = unsafe { guestmem::GlobalStack::new() };
                let slice = unsafe { slice::from_raw_parts(param_ptr as _, len as _) };
                let cmd = $crate::wascap_codec::core::Command::decode(&slice).unwrap();
                //let req = Request::from(raw_req);

                let ctx = $crate::CapabilitiesContext::new();

                ctx.log("Invoking handler...");
                let event: $crate::wascap_codec::core::Event = match $user_handler(&ctx, &cmd) {
                    Ok(evt) => evt,
                    Err(e) => {
                        ctx.log(&format!("Handler failed: {}", e));
                        $crate::wascap_codec::core::Event {
                            success: false,
                            error: Some($crate::wascap_codec::core::Error {
                                code: 500,
                                description: format!("{}", e),
                            }),
                            payload: None,
                        }
                    }
                };

                let mut buf = Vec::with_capacity(event.encoded_len());
                let _res = event.encode(&mut buf).unwrap();
                __stack.push(buf.as_ptr() as u32);
                //__stack.push(buf.len() as u32);

                buf.len() as _
            };
            req
        }
    };
}

#[cold]
#[inline(never)]
pub(crate) fn throw_str(s: &str) -> ! {
    unsafe {
        __throw(s.as_ptr(), s.len());
    }
}

#[cold]
#[inline(never)]
pub(crate) fn console_log(s: &str) {
    unsafe {
        __console_log(s.as_ptr(), s.len());
    }
}

pub struct CapabilitiesContext {
    kv: HostKeyValueStore,
}

impl CapabilitiesContext {
    pub fn new() -> CapabilitiesContext {
        CapabilitiesContext {
            kv: HostKeyValueStore::new(),
        }
    }

    pub fn kv(&self) -> &impl KeyValueStore {
        &self.kv
    }

    pub fn log(&self, msg: &str) {
        console_log(msg);
    }
}

mod errors;
pub mod guestmem;
pub mod http;
mod kv;
pub mod prelude;