From 413bcf20425992762a9a5a6e19caddc5ff160303 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 9 Aug 2018 13:24:30 -0400 Subject: [PATCH] Add readFileSync --- js/os.ts | 29 ++++++++++++++---- src/handlers.h | 1 + src/handlers.rs | 59 +++++++++++++++++++++++++++++++++++++ src/reply.cc | 7 +++++ tests/read_file_sync.ts | 18 +++++++++++ tests/read_file_sync.ts.out | 1 + 6 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 tests/read_file_sync.ts create mode 100644 tests/read_file_sync.ts.out diff --git a/js/os.ts b/js/os.ts index ab73395b3a..a3f45e467d 100644 --- a/js/os.ts +++ b/js/os.ts @@ -85,15 +85,34 @@ export function codeCache( } export function readFileSync(filename: string): Uint8Array { - assert(false, "Not Implemented"); - return null; - /* - const res = pubInternal("os", { + /* Ideally we could write + const res = send({ command: fbs.Command.READ_FILE_SYNC, readFileSyncFilename: filename }); return res.readFileSyncData; - */ + */ + const builder = new flatbuffers.Builder(); + const filename_ = builder.createString(filename); + fbs.ReadFileSync.startReadFileSync(builder); + fbs.ReadFileSync.addFilename(builder, filename_); + const msg = fbs.ReadFileSync.endReadFileSync(builder); + fbs.Base.startBase(builder); + fbs.Base.addMsg(builder, msg); + fbs.Base.addMsgType(builder, fbs.Any.ReadFileSync); + builder.finish(fbs.Base.endBase(builder)); + const resBuf = libdeno.send(builder.asUint8Array()); + assert(resBuf != null); + + const bb = new flatbuffers.ByteBuffer(new Uint8Array(resBuf)); + const baseRes = fbs.Base.getRootAsBase(bb); + if (fbs.Any.NONE === baseRes.msgType()) { + throw Error(baseRes.error()); + } + assert(fbs.Any.ReadFileSyncRes === baseRes.msgType()); + const res = new fbs.ReadFileSyncRes(); + assert(baseRes.msg(res) != null); + return new Uint8Array(res.dataArray()); } export function writeFileSync( diff --git a/src/handlers.h b/src/handlers.h index decbe59da7..715db3483e 100644 --- a/src/handlers.h +++ b/src/handlers.h @@ -14,5 +14,6 @@ void handle_code_cache(Deno* d, uint32_t cmd_id, const char* filename, void handle_timer_start(Deno* d, uint32_t cmd_id, uint32_t timer_id, bool interval, uint32_t delay); void handle_timer_clear(Deno* d, uint32_t cmd_id, uint32_t timer_id); +void handle_read_file_sync(Deno* d, uint32_t cmd_id, const char* filename); } // extern "C" #endif // HANDLERS_H_ diff --git a/src/handlers.rs b/src/handlers.rs index 480d7b6b88..f0c64e46e5 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -2,12 +2,17 @@ use binding; use binding::{deno_buf, deno_set_response, DenoC}; use flatbuffers; +use flatbuffers::ByteStringOffset; +use flatbuffers::LabeledUOffsetT; use from_c; +use fs; use futures; use futures::sync::oneshot; use libc::c_char; +use mem; use msg_generated::deno as msg; use std::ffi::CStr; +use std::path::Path; // Help. Is there a way to do this without macros? // Want: fn str_from_ptr(*const c_char) -> &str @@ -226,6 +231,60 @@ fn send_timer_ready(d: *const DenoC, timer_id: u32, done: bool) { ); } +// Prototype https://github.com/denoland/deno/blob/golang/os.go#L171-L184 +#[no_mangle] +pub extern "C" fn handle_read_file_sync( + d: *const DenoC, + cmd_id: u32, + filename: *const c_char, +) { + let filename = str_from_ptr!(filename); + + debug!("handle_read_file_sync {}", filename); + let result = fs::read_file_sync(Path::new(filename)); + if result.is_err() { + let err = result.unwrap_err(); + let errmsg = format!("{}", err); + reply_error(d, cmd_id, &errmsg); + return; + } + + // Build the response message. memcpy data into msg. + let mut builder = flatbuffers::FlatBufferBuilder::new(); + + let vec = result.unwrap(); + //let data = + // flatbuffers::LabeledUOffsetT::new(builder.push_bytes(vec.as_slice())); + + let data_ = builder.create_byte_vector(vec.as_slice()); + + // TODO(ry) This is a hack that can be removed once builder.create_byte_vector + // works properly. + let data = unsafe { + mem::transmute::, LabeledUOffsetT<&[i8]>>( + data_, + ) + }; + + let msg = msg::CreateReadFileSyncRes( + &mut builder, + &msg::ReadFileSyncResArgs { + data, + ..Default::default() + }, + ); + builder.finish(msg); + set_response_base( + d, + &mut builder, + &msg::BaseArgs { + msg: Some(msg.union()), + msg_type: msg::Any::ReadFileSyncRes, + ..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); diff --git a/src/reply.cc b/src/reply.cc index dada4e168b..62abe1364f 100644 --- a/src/reply.cc +++ b/src/reply.cc @@ -95,6 +95,13 @@ void deno_handle_msg_from_js(Deno* d, deno_buf buf) { break; } + case deno::Any_ReadFileSync: { + auto msg = base->msg_as_ReadFileSync(); + auto filename = msg->filename()->c_str(); + handle_read_file_sync(d, cmd_id, filename); + break; + } + case deno::Any_NONE: CHECK(false && "Got message with msg_type == Any_NONE"); break; diff --git a/tests/read_file_sync.ts b/tests/read_file_sync.ts new file mode 100644 index 0000000000..9e6c555c8d --- /dev/null +++ b/tests/read_file_sync.ts @@ -0,0 +1,18 @@ +// TODO(ry) Once unit_tests.js lands (#448) this file should be removed +// and replaced with a faster version like was done in the prototype. +// https://github.com/denoland/deno/blob/golang/tests.ts#L34-L45 +import * as deno from "deno"; + +const data = deno.readFileSync("package.json"); +if (!data.byteLength) { + throw Error( + `Expected positive value for data.byteLength ${data.byteLength}` + ); +} +const decoder = new TextDecoder("utf-8"); +const json = decoder.decode(data); +const pkg = JSON.parse(json); +if (pkg['devDependencies'] == null) { + throw Error("Expected a positive number of devDependencies"); +} +console.log("ok"); diff --git a/tests/read_file_sync.ts.out b/tests/read_file_sync.ts.out new file mode 100644 index 0000000000..9766475a41 --- /dev/null +++ b/tests/read_file_sync.ts.out @@ -0,0 +1 @@ +ok