diff options
Diffstat (limited to 'src/handlers.rs')
-rw-r--r-- | src/handlers.rs | 168 |
1 files changed, 160 insertions, 8 deletions
diff --git a/src/handlers.rs b/src/handlers.rs index 517e146a1..480d7b6b8 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -1,7 +1,10 @@ // Copyright 2018 the Deno authors. All rights reserved. MIT license. +use binding; use binding::{deno_buf, deno_set_response, DenoC}; use flatbuffers; use from_c; +use futures; +use futures::sync::oneshot; use libc::c_char; use msg_generated::deno as msg; use std::ffi::CStr; @@ -24,6 +27,7 @@ pub fn deno_handle_msg_from_js(d: *const DenoC, buf: deno_buf) { } */ +// TODO(ry) Use Deno instead of DenoC as first arg. fn reply_error(d: *const DenoC, cmd_id: u32, msg: &String) { let mut builder = flatbuffers::FlatBufferBuilder::new(); // println!("reply_error{}", msg); @@ -35,16 +39,14 @@ fn reply_error(d: *const DenoC, cmd_id: u32, msg: &String) { set_response_base(d, &mut builder, &args) } -fn set_response_base( - d: *const DenoC, +fn create_msg( builder: &mut flatbuffers::FlatBufferBuilder, args: &msg::BaseArgs, -) { +) -> deno_buf { let base = msg::CreateBase(builder, &args); builder.finish(base); let data = builder.get_active_buf_slice(); - // println!("buf slice {} {} {} {} {}", data[0], data[1], data[2], data[3], data[4]); - let buf = deno_buf { + deno_buf { // TODO(ry) // The deno_buf / ImportBuf / ExportBuf semantics should be such that we do not need to yield // ownership. Temporarally there is a hack in ImportBuf that when alloc_ptr is null, it will @@ -53,12 +55,29 @@ fn set_response_base( alloc_len: 0, data_ptr: data.as_ptr() as *mut u8, data_len: data.len(), - }; - // println!("data_ptr {:p}", data_ptr); - // println!("data_len {}", data.len()); + } +} + +// TODO(ry) Use Deno instead of DenoC as first arg. +fn set_response_base( + d: *const DenoC, + builder: &mut flatbuffers::FlatBufferBuilder, + args: &msg::BaseArgs, +) { + let buf = create_msg(builder, args); unsafe { deno_set_response(d, buf) } } +// TODO(ry) Use Deno instead of DenoC as first arg. +fn send_base( + d: *const DenoC, + builder: &mut flatbuffers::FlatBufferBuilder, + args: &msg::BaseArgs, +) { + let buf = create_msg(builder, args); + unsafe { binding::deno_send(d, buf) } +} + // https://github.com/denoland/deno/blob/golang/os.go#L100-L154 #[no_mangle] pub extern "C" fn handle_code_fetch( @@ -131,3 +150,136 @@ pub extern "C" fn handle_code_cache( } // null response indicates success. } + +fn set_timeout<F>( + cb: F, + delay: u32, +) -> ( + impl Future<Item = (), Error = ()>, + futures::sync::oneshot::Sender<()>, +) +where + F: FnOnce() -> (), +{ + let (cancel_tx, cancel_rx) = oneshot::channel::<()>(); + let when = Instant::now() + Duration::from_millis(delay.into()); + let delay_task = Delay::new(when) + .map_err(|e| panic!("timer failed; err={:?}", e)) + .and_then(|_| { + cb(); + Ok(()) + }) + .select(cancel_rx) + .map(|_| ()) + .map_err(|_| ()); + + (delay_task, cancel_tx) +} + +fn set_interval<F>( + cb: F, + delay: u32, +) -> ( + impl Future<Item = (), Error = ()>, + futures::sync::oneshot::Sender<()>, +) +where + F: Fn() -> (), +{ + let (cancel_tx, cancel_rx) = oneshot::channel::<()>(); + let delay = Duration::from_millis(delay.into()); + let interval_task = future::lazy(move || { + Interval::new(Instant::now() + delay, delay) + .for_each(move |_| { + cb(); + future::ok(()) + }) + .into_future() + .map_err(|_| panic!()) + }).select(cancel_rx) + .map(|_| ()) + .map_err(|_| ()); + + (interval_task, cancel_tx) +} + +// TODO(ry) Use Deno instead of DenoC as first arg. +fn send_timer_ready(d: *const DenoC, timer_id: u32, done: bool) { + let mut builder = flatbuffers::FlatBufferBuilder::new(); + let msg = msg::CreateTimerReady( + &mut builder, + &msg::TimerReadyArgs { + id: timer_id, + done, + ..Default::default() + }, + ); + builder.finish(msg); + send_base( + d, + &mut builder, + &msg::BaseArgs { + msg: Some(msg.union()), + msg_type: msg::Any::TimerReady, + ..Default::default() + }, + ); +} + +// TODO(ry) Use Deno instead of DenoC as first arg. +fn remove_timer(d: *const DenoC, timer_id: u32) { + let deno = from_c(d); + deno.timers.remove(&timer_id); +} + +use std::time::{Duration, Instant}; +use tokio::prelude::*; +use tokio::timer::{Delay, Interval}; +// Prototype: https://github.com/ry/deno/blob/golang/timers.go#L25-L39 +#[no_mangle] +pub extern "C" fn handle_timer_start( + d: *const DenoC, + cmd_id: u32, + timer_id: u32, + interval: bool, + delay: u32, +) { + assert!(cmd_id == 0); + debug!("handle_timer_start"); + let deno = from_c(d); + + if interval { + let (interval_task, cancel_interval) = set_interval( + move || { + send_timer_ready(d, timer_id, false); + }, + delay, + ); + + deno.timers.insert(timer_id, cancel_interval); + deno.rt.spawn(interval_task); + } else { + let (delay_task, cancel_delay) = set_timeout( + move || { + remove_timer(d, timer_id); + send_timer_ready(d, timer_id, true); + }, + delay, + ); + + deno.timers.insert(timer_id, cancel_delay); + deno.rt.spawn(delay_task); + } +} + +// Prototype: https://github.com/ry/deno/blob/golang/timers.go#L40-L43 +#[no_mangle] +pub extern "C" fn handle_timer_clear( + d: *const DenoC, + cmd_id: u32, + timer_id: u32, +) { + assert!(cmd_id == 0); + debug!("handle_timer_clear"); + remove_timer(d, timer_id); +} |