Hexput Runtime
A WebSocket server for parsing and executing Hexput AST code with configurable security constraints.
Overview
Hexput Runtime is a Rust-based execution environment that allows clients to send code via WebSocket connections and receive execution results. The runtime provides:
- Code parsing to an AST representation
- Secure code execution with configurable constraints
- Built-in methods for common data types
- Function call bridging between the runtime and client
Installation
Prerequisites
- Rust and Cargo (1.56.0 or later)
- Dependencies are managed through Cargo
Building from source
# Clone the repository
# Build the project
# Run the server
Usage
# Run with default settings (127.0.0.1:9001)
# Specify address and port
# Enable debug logging
# Set specific log level
WebSocket API
Connecting to the Server
To connect to the Hexput Runtime server, use a WebSocket client to connect to the server's address and port. When the connection is established, the server will send a welcome message:
Handling WebSocket Connections Properly
For reliable WebSocket communication:
-
Connection Establishment:
- Connect to the server using the WebSocket protocol
- Wait for the welcome message before sending requests
- Handle connection failures gracefully with reconnection logic
-
Message Handling:
- Always include a unique ID with each request
- Process incoming messages asynchronously
- Keep track of pending requests and their corresponding responses
-
Connection Management:
- Implement ping/pong heartbeats to detect disconnections
- Gracefully close connections when they're no longer needed
- Handle reconnection with exponential backoff
-
Error Handling:
- Listen for error messages from the server
- Handle execution errors by correlating them with the original request ID
- Implement timeout mechanisms for requests that take too long
Message Formats
Requests
The server accepts the following request types:
- Parse Request:
- Execute Request:
- Function Check Request:
- Function Call Request:
Responses
- Parse Response:
- Execute Response:
- Error Response:
- Function Exists Response:
- Function Call Response:
Remote Function Calling
One of the most powerful features of Hexput Runtime is remote function calling. This capability allows code executing in the runtime to call functions that are implemented on the client side, enabling sandboxed code to safely interact with the host environment.
How Remote Function Calling Works
- Function Discovery: When the runtime encounters a function call that isn't defined in the local context, it sends a function existence check to the client.
- Function Execution: If the function exists on the client side, the runtime sends a function call request with arguments.
- Response Handling: The client executes the function and returns the result, which the runtime then integrates into the running code.
- Timeout Protection: Function calls have configurable timeouts to prevent hanging executions.
Remote Function Protocol
-
Check if Function Exists:
- Runtime sends:
{"id": "uuid", "action": "is_function_exists", "function_name": "myFunction"} - Client responds:
{"id": "uuid", "exists": true}
- Runtime sends:
-
Call Function:
- Runtime sends:
{"id": "uuid", "function_name": "myFunction", "arguments": [arg1, arg2, ...]} - Client responds:
{"id": "uuid", "result": functionResult}
- Runtime sends:
Example Implementation
This example shows how to implement a client that handles remote function calls:
// Usage example
const client = ;
// Register functions that can be called from the runtime
client.;
client.;
// Execute code that calls the registered functions
client.
.
.;
Handling Asynchronous Functions
For asynchronous operations, you can use Promises in your function handlers:
client.;
// In the runtime code
// let userData = fetchUserData("user123");
Security Considerations
When implementing remote function calling:
- Validate all inputs coming from the runtime
- Limit function capabilities to only what's necessary
- Handle timeouts for long-running operations
- Consider implementing permission systems for different functions
- Avoid exposing sensitive functions that could be misused
By carefully implementing these patterns, you can safely bridge between sandboxed code and your application's functionality.
Security Options
Hexput Runtime offers configurable security constraints to restrict what code can do:
no_object_constructions: Prevents creating new objectsno_array_constructions: Prevents creating new arraysno_object_navigation: Prevents accessing object propertiesno_variable_declaration: Prevents declaring new variablesno_loops: Prevents using loop constructsno_object_keys: Prevents getting object keysno_callbacks: Prevents defining and using callbacksno_conditionals: Prevents using if/else statementsno_return_statements: Prevents using return statementsno_loop_control: Prevents using break/continueno_operators: Prevents using mathematical operatorsno_equality: Prevents using equality operatorsno_assignments: Prevents assigning values to variables
Examples
Basic Execution
Client code to execute a simple expression:
const ws = ;
ws ;
ws ;
Function Bridging
Server-side function execution from client code:
// Client-side handler for server function calls
ws ;
// Execute code that calls client-side functions
ws.;
Built-in Methods
The runtime includes built-in methods for common data types:
String Methods
length(),len(): Returns string lengthisEmpty(): Checks if the string is emptysubstring(start, end): Extracts a portion of the stringtoLowerCase(): Converts to lowercasetoUpperCase(): Converts to uppercasetrim(): Removes whitespace from both endsincludes(substring),contains(substring): Checks if string contains a substringstartsWith(prefix): Checks if string starts with prefixendsWith(suffix): Checks if string ends with suffixindexOf(substring): Returns the position of the first occurrencesplit(delimiter): Splits string into an array
Array Methods
length(),len(): Returns array lengthisEmpty(): Checks if the array is emptyjoin(separator): Joins array elements into a stringfirst(): Returns the first elementlast(): Returns the last elementincludes(item),contains(item): Checks if array contains an itemslice(start, end): Extracts a portion of the array
Object Methods
keys(): Returns an array of property namesvalues(): Returns an array of property valuesisEmpty(): Checks if the object has no propertieshas(key): Checks if the object has a specific propertyentries(): Returns an array of [key, value] pairs