2018-07-23 14:46:30 -04:00
|
|
|
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
2018-07-23 14:13:12 -04:00
|
|
|
use binding::{deno_buf, deno_set_response, DenoC};
|
|
|
|
use flatbuffers;
|
2018-07-06 11:27:36 -04:00
|
|
|
use libc::c_char;
|
2018-07-23 14:13:12 -04:00
|
|
|
use libc::uint32_t;
|
|
|
|
use msg_generated::deno as msg;
|
2018-07-06 11:27:36 -04:00
|
|
|
use std::ffi::CStr;
|
2018-07-13 03:24:07 -04:00
|
|
|
use std::fs::File;
|
|
|
|
use std::io::Read;
|
|
|
|
use std::path::Path;
|
2018-07-23 14:13:12 -04:00
|
|
|
use url;
|
2018-07-10 14:56:12 -04:00
|
|
|
use url::Url;
|
2018-07-06 11:27:36 -04:00
|
|
|
|
2018-07-13 03:24:07 -04:00
|
|
|
// TODO(ry) SRC_DIR is just a placeholder for future caching functionality.
|
|
|
|
static SRC_DIR: &str = "/Users/rld/.deno/src/";
|
|
|
|
const ASSET_PREFIX: &str = "/$asset$/";
|
|
|
|
|
2018-07-07 16:50:35 -04:00
|
|
|
#[test]
|
2018-07-10 14:56:12 -04:00
|
|
|
fn test_url() {
|
2018-07-19 21:14:32 -04:00
|
|
|
let issue_list_url = Url::parse("https://github.com/rust-lang").unwrap();
|
|
|
|
assert!(issue_list_url.scheme() == "https");
|
2018-07-07 16:50:35 -04:00
|
|
|
}
|
|
|
|
|
2018-07-13 03:24:07 -04:00
|
|
|
fn string_from_ptr(ptr: *const c_char) -> String {
|
2018-07-19 21:14:32 -04:00
|
|
|
let cstr = unsafe { CStr::from_ptr(ptr as *const i8) };
|
|
|
|
String::from(cstr.to_str().unwrap())
|
2018-07-13 03:24:07 -04:00
|
|
|
}
|
|
|
|
|
2018-07-23 14:13:12 -04:00
|
|
|
/*
|
|
|
|
// reply_start partially implemented here https://gist.github.com/ry/297c83e0ac8722c045db1b097cdb6afc
|
|
|
|
pub fn deno_handle_msg_from_js(d: *const DenoC, buf: deno_buf) {
|
|
|
|
let s = std::slice::from_raw_parts(buf.data_ptr, buf.data_len);
|
|
|
|
buf.data_ptr
|
|
|
|
get_root()
|
2018-07-13 03:24:07 -04:00
|
|
|
}
|
2018-07-23 14:13:12 -04:00
|
|
|
*/
|
2018-07-13 03:24:07 -04:00
|
|
|
|
|
|
|
// Prototype: https://github.com/ry/deno/blob/golang/os.go#L56-L68
|
|
|
|
#[allow(dead_code)]
|
|
|
|
fn src_file_to_url<P: AsRef<Path>>(filename: P) -> String {
|
2018-07-19 21:14:32 -04:00
|
|
|
assert!(SRC_DIR.len() > 0, "SRC_DIR shouldn't be empty");
|
2018-07-13 03:24:07 -04:00
|
|
|
|
2018-07-19 21:14:32 -04:00
|
|
|
let filename = filename.as_ref().to_path_buf();
|
|
|
|
let src = (SRC_DIR.as_ref() as &Path).to_path_buf();
|
2018-07-13 03:24:07 -04:00
|
|
|
|
2018-07-19 21:14:32 -04:00
|
|
|
if filename.starts_with(&src) {
|
|
|
|
let rest = filename.strip_prefix(&src).unwrap();
|
|
|
|
"http://".to_string() + rest.to_str().unwrap()
|
|
|
|
} else {
|
|
|
|
String::from(filename.to_str().unwrap())
|
|
|
|
}
|
2018-07-13 03:24:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_src_file_to_url() {
|
2018-07-19 21:14:32 -04:00
|
|
|
assert_eq!("hello", src_file_to_url("hello"));
|
|
|
|
assert_eq!("/hello", src_file_to_url("/hello"));
|
|
|
|
let x = SRC_DIR.to_string() + "hello";
|
|
|
|
assert_eq!("http://hello", src_file_to_url(&x));
|
|
|
|
let x = SRC_DIR.to_string() + "/hello";
|
|
|
|
assert_eq!("http://hello", src_file_to_url(&x));
|
2018-07-13 03:24:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Prototype: https://github.com/ry/deno/blob/golang/os.go#L70-L98
|
|
|
|
// Returns (module name, local filename)
|
|
|
|
fn resolve_module(
|
2018-07-19 21:14:32 -04:00
|
|
|
module_specifier: &String,
|
|
|
|
containing_file: &String,
|
2018-07-13 03:24:07 -04:00
|
|
|
) -> Result<(String, String), url::ParseError> {
|
2018-07-26 17:37:09 -04:00
|
|
|
debug!(
|
2018-07-19 21:14:32 -04:00
|
|
|
"resolve_module before module_specifier {} containing_file {}",
|
|
|
|
module_specifier, containing_file
|
|
|
|
);
|
|
|
|
|
|
|
|
//let module_specifier = src_file_to_url(module_specifier);
|
|
|
|
//let containing_file = src_file_to_url(containing_file);
|
|
|
|
//let base_url = Url::parse(&containing_file)?;
|
|
|
|
|
2018-07-22 02:52:39 +02:00
|
|
|
let j: Url =
|
|
|
|
if containing_file == "." || Path::new(module_specifier).is_absolute() {
|
|
|
|
Url::from_file_path(module_specifier).unwrap()
|
|
|
|
} else if containing_file.as_str().ends_with("/") {
|
|
|
|
let base = Url::from_directory_path(&containing_file).unwrap();
|
|
|
|
base.join(module_specifier)?
|
|
|
|
} else {
|
|
|
|
let base = Url::from_file_path(&containing_file).unwrap();
|
|
|
|
base.join(module_specifier)?
|
|
|
|
};
|
2018-07-19 21:14:32 -04:00
|
|
|
|
|
|
|
let mut p = j.to_file_path()
|
|
|
|
.unwrap()
|
|
|
|
.into_os_string()
|
|
|
|
.into_string()
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
if cfg!(target_os = "windows") {
|
|
|
|
// On windows, replace backward slashes to forward slashes.
|
|
|
|
// TODO(piscisaureus): This may not me be right, I just did it to make
|
|
|
|
// the tests pass.
|
|
|
|
p = p.replace("\\", "/");
|
|
|
|
}
|
|
|
|
|
|
|
|
let module_name = p.to_string();
|
|
|
|
let filename = p.to_string();
|
|
|
|
|
|
|
|
Ok((module_name, filename))
|
2018-07-13 03:24:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// https://github.com/ry/deno/blob/golang/os_test.go#L16-L87
|
|
|
|
#[test]
|
|
|
|
fn test_resolve_module() {
|
2018-07-19 21:14:32 -04:00
|
|
|
// The `add_root` macro prepends "C:" to a string if on windows; on posix
|
|
|
|
// systems it returns the input string untouched. This is necessary because
|
|
|
|
// `Url::from_file_path()` fails if the input path isn't an absolute path.
|
|
|
|
macro_rules! add_root {
|
|
|
|
($path:expr) => {
|
|
|
|
if cfg!(target_os = "windows") {
|
|
|
|
concat!("C:", $path)
|
|
|
|
} else {
|
|
|
|
$path
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
let test_cases = [
|
|
|
|
(
|
|
|
|
"./subdir/print_hello.ts",
|
|
|
|
add_root!(
|
|
|
|
"/Users/rld/go/src/github.com/ry/deno/testdata/006_url_imports.ts"
|
|
|
|
),
|
|
|
|
add_root!(
|
|
|
|
"/Users/rld/go/src/github.com/ry/deno/testdata/subdir/print_hello.ts"
|
|
|
|
),
|
|
|
|
add_root!(
|
|
|
|
"/Users/rld/go/src/github.com/ry/deno/testdata/subdir/print_hello.ts"
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"testdata/001_hello.js",
|
|
|
|
add_root!("/Users/rld/go/src/github.com/ry/deno/"),
|
|
|
|
add_root!("/Users/rld/go/src/github.com/ry/deno/testdata/001_hello.js"),
|
|
|
|
add_root!("/Users/rld/go/src/github.com/ry/deno/testdata/001_hello.js"),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
add_root!("/Users/rld/src/deno/hello.js"),
|
|
|
|
".",
|
|
|
|
add_root!("/Users/rld/src/deno/hello.js"),
|
|
|
|
add_root!("/Users/rld/src/deno/hello.js"),
|
|
|
|
),
|
2018-07-22 02:52:39 +02:00
|
|
|
(
|
|
|
|
add_root!("/this/module/got/imported.js"),
|
|
|
|
add_root!("/that/module/did/it.js"),
|
|
|
|
add_root!("/this/module/got/imported.js"),
|
|
|
|
add_root!("/this/module/got/imported.js"),
|
|
|
|
),
|
2018-07-19 21:14:32 -04:00
|
|
|
/*
|
2018-07-13 03:24:07 -04:00
|
|
|
(
|
|
|
|
"http://localhost:4545/testdata/subdir/print_hello.ts",
|
2018-07-19 08:39:18 +02:00
|
|
|
add_root!("/Users/rld/go/src/github.com/ry/deno/testdata/006_url_imports.ts"),
|
2018-07-13 03:24:07 -04:00
|
|
|
"http://localhost:4545/testdata/subdir/print_hello.ts",
|
|
|
|
path.Join(SrcDir, "localhost:4545/testdata/subdir/print_hello.ts"),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
path.Join(SrcDir, "unpkg.com/liltest@0.0.5/index.ts"),
|
|
|
|
".",
|
|
|
|
"http://unpkg.com/liltest@0.0.5/index.ts",
|
|
|
|
path.Join(SrcDir, "unpkg.com/liltest@0.0.5/index.ts"),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"./util",
|
|
|
|
path.Join(SrcDir, "unpkg.com/liltest@0.0.5/index.ts"),
|
|
|
|
"http://unpkg.com/liltest@0.0.5/util",
|
|
|
|
path.Join(SrcDir, "unpkg.com/liltest@0.0.5/util"),
|
|
|
|
),
|
|
|
|
*/
|
2018-07-19 21:14:32 -04:00
|
|
|
];
|
|
|
|
for &test in test_cases.iter() {
|
|
|
|
let module_specifier = String::from(test.0);
|
|
|
|
let containing_file = String::from(test.1);
|
|
|
|
let (module_name, filename) =
|
|
|
|
resolve_module(&module_specifier, &containing_file).unwrap();
|
|
|
|
assert_eq!(module_name, test.2);
|
|
|
|
assert_eq!(filename, test.3);
|
|
|
|
}
|
2018-07-13 03:24:07 -04:00
|
|
|
}
|
|
|
|
|
2018-07-23 14:13:12 -04:00
|
|
|
pub fn reply_code_fetch(
|
|
|
|
d: *const DenoC,
|
|
|
|
cmd_id: uint32_t,
|
|
|
|
module_name: &String,
|
|
|
|
filename: &String,
|
|
|
|
source_code: &String,
|
|
|
|
output_code: &String,
|
|
|
|
) {
|
|
|
|
let mut builder = flatbuffers::FlatBufferBuilder::new();
|
|
|
|
let msg_args = msg::CodeFetchResArgs {
|
|
|
|
module_name: builder.create_string(module_name),
|
|
|
|
filename: builder.create_string(filename),
|
|
|
|
source_code: builder.create_string(source_code),
|
|
|
|
output_code: builder.create_string(output_code),
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
let msg = msg::CreateCodeFetchRes(&mut builder, &msg_args);
|
|
|
|
builder.finish(msg);
|
|
|
|
let args = msg::BaseArgs {
|
|
|
|
cmdId: cmd_id,
|
|
|
|
msg: Some(msg.union()),
|
|
|
|
msg_type: msg::Any::CodeFetchRes,
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
set_response_base(d, &mut builder, &args)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn reply_error(d: *const DenoC, cmd_id: u32, msg: &String) {
|
|
|
|
let mut builder = flatbuffers::FlatBufferBuilder::new();
|
|
|
|
// println!("reply_error{}", msg);
|
|
|
|
let args = msg::BaseArgs {
|
|
|
|
cmdId: cmd_id,
|
|
|
|
error: builder.create_string(msg),
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
set_response_base(d, &mut builder, &args)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_response_base(
|
|
|
|
d: *const DenoC,
|
|
|
|
builder: &mut flatbuffers::FlatBufferBuilder,
|
|
|
|
args: &msg::BaseArgs,
|
|
|
|
) {
|
|
|
|
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 {
|
|
|
|
// 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
|
|
|
|
// memcpy the deno_buf into V8 instead of doing zero copy.
|
|
|
|
alloc_ptr: 0 as *mut u8,
|
|
|
|
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());
|
|
|
|
unsafe { deno_set_response(d, buf) }
|
|
|
|
}
|
|
|
|
|
2018-07-13 03:24:07 -04:00
|
|
|
// https://github.com/ry/deno/blob/golang/os.go#L100-L154
|
2018-07-06 11:27:36 -04:00
|
|
|
#[no_mangle]
|
|
|
|
pub extern "C" fn handle_code_fetch(
|
2018-07-19 21:14:32 -04:00
|
|
|
d: *const DenoC,
|
|
|
|
cmd_id: u32,
|
|
|
|
module_specifier_: *const c_char,
|
|
|
|
containing_file_: *const c_char,
|
2018-07-06 11:27:36 -04:00
|
|
|
) {
|
2018-07-19 21:14:32 -04:00
|
|
|
let module_specifier = string_from_ptr(module_specifier_);
|
|
|
|
let containing_file = string_from_ptr(containing_file_);
|
|
|
|
|
|
|
|
let result = resolve_module(&module_specifier, &containing_file);
|
|
|
|
if result.is_err() {
|
|
|
|
let err = result.unwrap_err();
|
|
|
|
let errmsg = format!("{} {} {}", err, module_specifier, containing_file);
|
2018-07-23 14:13:12 -04:00
|
|
|
reply_error(d, cmd_id, &errmsg);
|
2018-07-19 21:14:32 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
let (module_name, filename) = result.unwrap();
|
|
|
|
|
|
|
|
let mut source_code = String::new();
|
|
|
|
|
|
|
|
debug!(
|
2018-07-13 03:24:07 -04:00
|
|
|
"code_fetch. module_name = {} module_specifier = {} containing_file = {} filename = {}",
|
|
|
|
module_name, module_specifier, containing_file, filename
|
2018-07-06 11:27:36 -04:00
|
|
|
);
|
|
|
|
|
2018-07-19 21:14:32 -04:00
|
|
|
if is_remote(&module_name) {
|
|
|
|
unimplemented!();
|
|
|
|
} else if module_name.starts_with(ASSET_PREFIX) {
|
|
|
|
assert!(false, "Asset resolution should be done in JS, not Rust.");
|
|
|
|
} else {
|
|
|
|
assert!(
|
|
|
|
module_name == filename,
|
|
|
|
"if a module isn't remote, it should have the same filename"
|
|
|
|
);
|
|
|
|
let result = File::open(&filename);
|
|
|
|
if result.is_err() {
|
|
|
|
let err = result.unwrap_err();
|
|
|
|
let errmsg = format!("{} {}", err, filename);
|
2018-07-23 14:13:12 -04:00
|
|
|
reply_error(d, cmd_id, &errmsg);
|
2018-07-19 21:14:32 -04:00
|
|
|
return;
|
2018-07-13 03:24:07 -04:00
|
|
|
}
|
2018-07-19 21:14:32 -04:00
|
|
|
let mut f = result.unwrap();
|
|
|
|
let result = f.read_to_string(&mut source_code);
|
|
|
|
if result.is_err() {
|
|
|
|
let err = result.unwrap_err();
|
|
|
|
let errmsg = format!("{} {}", err, filename);
|
2018-07-23 14:13:12 -04:00
|
|
|
reply_error(d, cmd_id, &errmsg);
|
2018-07-19 21:14:32 -04:00
|
|
|
return;
|
2018-07-13 03:24:07 -04:00
|
|
|
}
|
2018-07-19 21:14:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
let output_code = String::new(); //load_output_code_cache(filename, source_code);
|
|
|
|
|
2018-07-23 14:13:12 -04:00
|
|
|
reply_code_fetch(
|
|
|
|
d,
|
|
|
|
cmd_id,
|
|
|
|
&module_name,
|
|
|
|
&filename,
|
|
|
|
&source_code,
|
|
|
|
&output_code,
|
|
|
|
)
|
2018-07-13 03:24:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn is_remote(_module_name: &String) -> bool {
|
2018-07-19 21:14:32 -04:00
|
|
|
false
|
2018-07-06 11:27:36 -04:00
|
|
|
}
|