Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions stdlib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub mod mock;
pub mod mongodb;
pub mod mysql;
pub mod net;
pub mod net_handler;
pub mod notification;
pub mod oauth;
pub mod os;
Expand Down
98 changes: 6 additions & 92 deletions stdlib/src/net.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
use crate::{StdFunction, StdlibModule, StdlibRegistry};
use indexmap::IndexMap;
use std::cell::RefCell;
use crate::{net_handler, StdFunction, StdlibModule, StdlibRegistry};
use std::collections::HashMap;
use std::rc::Rc;
use techscript_runtime::{
context::Capability,
error::{RuntimeError, RuntimeErrorKind},
value::RuntimeValue,
};
use techscript_runtime::context::Capability;

impl StdlibRegistry {
pub fn register_net(&mut self) {
Expand All @@ -19,28 +13,7 @@ impl StdlibRegistry {
Rc::new(StdFunction {
name: "tcp_listen".to_string(),
arity: 1,
callback: |ctx, args| {
let port = args[0].try_into_int()?;
let listener = std::net::TcpListener::bind(format!("127.0.0.1:{}", port))
.map_err(|e| {
RuntimeError::new(
RuntimeErrorKind::InvalidOperation(format!(
"TCP bind error: {}",
e
)),
None,
None,
)
})?;
let handle_id = ctx.resources.borrow_mut().insert(listener);
let mut listener_map = IndexMap::new();
listener_map.insert("port".to_string(), RuntimeValue::Int(port));
listener_map.insert("_handle".to_string(), RuntimeValue::Int(handle_id as i64));
Ok(RuntimeValue::Map {
entries: Rc::new(RefCell::new(listener_map)),
is_const: false,
})
},
callback: net_handler::tcp_listen,
}),
);

Expand All @@ -49,30 +22,7 @@ impl StdlibRegistry {
Rc::new(StdFunction {
name: "tcp_connect".to_string(),
arity: 2,
callback: |ctx, args| {
let ip = args[0].try_into_string()?;
let port = args[1].try_into_int()?;
let stream =
std::net::TcpStream::connect(format!("{}:{}", ip, port)).map_err(|e| {
RuntimeError::new(
RuntimeErrorKind::InvalidOperation(format!(
"TCP connect error: {}",
e
)),
None,
None,
)
})?;
let handle_id = ctx.resources.borrow_mut().insert(stream);
let mut stream_map = IndexMap::new();
stream_map.insert("ip".to_string(), RuntimeValue::Str(ip));
stream_map.insert("port".to_string(), RuntimeValue::Int(port));
stream_map.insert("_handle".to_string(), RuntimeValue::Int(handle_id as i64));
Ok(RuntimeValue::Map {
entries: Rc::new(RefCell::new(stream_map)),
is_const: false,
})
},
callback: net_handler::tcp_connect,
}),
);

Expand All @@ -81,23 +31,7 @@ impl StdlibRegistry {
Rc::new(StdFunction {
name: "tcp_send".to_string(),
arity: 2,
callback: |ctx, args| {
if let RuntimeValue::Map { entries, .. } = &args[0] {
let handle_id = entries
.borrow()
.get("_handle")
.cloned()
.unwrap_or(RuntimeValue::Null)
.try_into_int()? as u32;
let mut resources = ctx.resources.borrow_mut();
if let Some(stream) = resources.get_mut::<std::net::TcpStream>(handle_id) {
use std::io::Write;
let msg = args[1].try_into_string()?;
stream.write_all(msg.as_bytes()).ok();
}
}
Ok(RuntimeValue::Null)
},
callback: net_handler::tcp_send,
}),
);

Expand All @@ -106,27 +40,7 @@ impl StdlibRegistry {
Rc::new(StdFunction {
name: "tcp_recv".to_string(),
arity: 1,
callback: |ctx, args| {
if let RuntimeValue::Map { entries, .. } = &args[0] {
let handle_id = entries
.borrow()
.get("_handle")
.cloned()
.unwrap_or(RuntimeValue::Null)
.try_into_int()? as u32;
let mut resources = ctx.resources.borrow_mut();
if let Some(stream) = resources.get_mut::<std::net::TcpStream>(handle_id) {
use std::io::Read;
let mut buf = [0; 512];
if let Ok(n) = stream.read(&mut buf) {
return Ok(RuntimeValue::Str(
String::from_utf8_lossy(&buf[..n]).to_string(),
));
}
}
}
Ok(RuntimeValue::Str(String::new()))
},
callback: net_handler::tcp_recv,
}),
);

Expand Down
100 changes: 100 additions & 0 deletions stdlib/src/net_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use indexmap::IndexMap;
use std::cell::RefCell;
use std::rc::Rc;
use techscript_runtime::{
error::{RuntimeError, RuntimeErrorKind},
value::RuntimeValue,
RuntimeContext,
};

pub fn tcp_listen(
ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let port = args[0].try_into_int()?;
let listener = std::net::TcpListener::bind(format!("127.0.0.1:{}", port)).map_err(|e| {
RuntimeError::new(
RuntimeErrorKind::InvalidOperation(format!("TCP bind error: {}", e)),
None,
None,
)
})?;
let handle_id = ctx.resources.borrow_mut().insert(listener);
let mut listener_map = IndexMap::new();
listener_map.insert("port".to_string(), RuntimeValue::Int(port));
listener_map.insert("_handle".to_string(), RuntimeValue::Int(handle_id as i64));
Ok(RuntimeValue::Map {
entries: Rc::new(RefCell::new(listener_map)),
is_const: false,
})
}

pub fn tcp_connect(
ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let ip = args[0].try_into_string()?;
let port = args[1].try_into_int()?;
let stream = std::net::TcpStream::connect(format!("{}:{}", ip, port)).map_err(|e| {
RuntimeError::new(
RuntimeErrorKind::InvalidOperation(format!("TCP connect error: {}", e)),
None,
None,
)
})?;
let handle_id = ctx.resources.borrow_mut().insert(stream);
let mut stream_map = IndexMap::new();
stream_map.insert("ip".to_string(), RuntimeValue::Str(ip));
stream_map.insert("port".to_string(), RuntimeValue::Int(port));
stream_map.insert("_handle".to_string(), RuntimeValue::Int(handle_id as i64));
Ok(RuntimeValue::Map {
entries: Rc::new(RefCell::new(stream_map)),
is_const: false,
})
}

pub fn tcp_send(
ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
if let RuntimeValue::Map { entries, .. } = &args[0] {
let handle_id = entries
.borrow()
.get("_handle")
.cloned()
.unwrap_or(RuntimeValue::Null)
.try_into_int()? as u32;
let mut resources = ctx.resources.borrow_mut();
if let Some(stream) = resources.get_mut::<std::net::TcpStream>(handle_id) {
use std::io::Write;
let msg = args[1].try_into_string()?;
stream.write_all(msg.as_bytes()).ok();
}
}
Ok(RuntimeValue::Null)
}

pub fn tcp_recv(
ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
if let RuntimeValue::Map { entries, .. } = &args[0] {
let handle_id = entries
.borrow()
.get("_handle")
.cloned()
.unwrap_or(RuntimeValue::Null)
.try_into_int()? as u32;
let mut resources = ctx.resources.borrow_mut();
if let Some(stream) = resources.get_mut::<std::net::TcpStream>(handle_id) {
use std::io::Read;
let mut buf = [0; 512];
if let Ok(n) = stream.read(&mut buf) {
return Ok(RuntimeValue::Str(
String::from_utf8_lossy(&buf[..n]).to_string(),
));
}
}
}
Ok(RuntimeValue::Str(String::new()))
}
8 changes: 6 additions & 2 deletions stdlib/tests/stdlib_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,9 @@ fn test_http_module() {
&mut ctx_unprivileged,
vec![RuntimeValue::Str(format!("http://127.0.0.1:{}", port))],
);
assert!(matches!(res_get, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation")));
assert!(
matches!(res_get, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation"))
);

let post = http.exports.get("post").unwrap();
let res_post = post.call(
Expand All @@ -550,7 +552,9 @@ fn test_http_module() {
RuntimeValue::Str("body".to_string()),
],
);
assert!(matches!(res_post, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation")));
assert!(
matches!(res_post, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation"))
);

// Test with Network capability
let mut caps = HashSet::new();
Expand Down