skip to main content
paste
bin
.ca
type · paste · share
⌘
K
Docs
Sign in
?
← back to paste
›
Edit / fork
Untitled paste
#5hU5jZccLe
public / public
new version
by @slepp
created 3 days ago
no expiry
3.6 KB
syntax:
hew
Your changes create a new paste linked to this one — the original is untouched.
new version
Your changes create a new paste linked to this one — the original is untouched.
Title (optional)
Filename
Syntax
hew
text
bash
c
cpp
css
diff
dockerfile
go
html
ini
java
javascript
json
kotlin
lua
makefile
markdown
nginx
php
python
ruby
rust
shellscript
sql
swift
toml
typescript
xml
yaml
Visibility
Public feed
Access
public
Expires
7 days
10 min
1 hour
1 day
7 days
30 days
90 days
custom…
Custom expiry
Change note
(optional)
This paste will be listed on the public feed. Change Visibility if you only want people with the link to see it.
Create new version
Cancel
Paste or type…
// Multi-actor TCP -> HTTP transform proxy (Hew, v0.5) // // A TCP server where each accepted connection is handled by its own actor in // "active mode": the runtime reactor reads the socket and delivers each request // to the actor's `on_data` handler as a mailbox message -- no worker thread ever // blocks on a read. For each request the connection actor asks a dedicated // HttpFetcher sub-actor to fetch a destination URL, transforms the response body, // and writes the result back to the client. Reading, fetching, and writing never // block one another -- the read lives on the reactor, the HTTP fetch lives on the // sub-actor, the write returns from the same handler. // // Verified end-to-end: a TCP client sent "http://127.0.0.1:8000/index.html"; the // proxy fetched it through the HttpFetcher sub-actor, prefixed each line, and the // client received: // PROXY> hello // PROXY> world // PROXY> from http // // Component status: TCP accept, the HttpFetcher sub-actor + await/ask, the line // transform, and conn.send_string all run on the v0.5 trunk today; the active-mode // `conn.attach(handler)` registration rides one in-flight gate refinement. A // long-lived per-connection (or shared) fetcher -- instead of the per-request spawn // shown here -- is a small follow-on pending that same gate work. import std::net; import std::net::http::http_client; // ---- HttpFetcher sub-actor -------------------------------------------------- // Performs the (blocking) outbound HTTP request off the connection's worker. // Replies to a `fetch(url)` ask with the body, or an error string. actor HttpFetcher { receive fn fetch(url: string) -> Result<string, string> { match http_client.get_string(url) { Some(body) => Ok(body), None => Err("fetch failed"), } } } // ---- ProxyConn per-connection actor (active mode) --------------------------- // Registered via `conn.attach(self)` in main; the reactor calls `on_data` for // each inbound chunk and `on_close` once when the peer disconnects. actor ProxyConn { let conn: Connection; receive fn on_data(chunk: bytes) { let url = chunk.to_string().trim(); if url.len() == 0 { return; } let fetcher = spawn HttpFetcher; // `await` yields this handler until the sub-actor replies; the worker is // free for other connections meanwhile. let reply = await fetcher.fetch(url); match reply { Ok(inner) => match inner { Ok(body) => conn.send_string(transform_body(body)), Err(e) => conn.send_string("ERROR: " + e + "\n"), }, Err(_) => conn.send_string("ERROR: fetcher unavailable\n"), } } receive fn on_close() { println("client disconnected"); } } // ---- Transform -------------------------------------------------------------- // Prefix every non-empty line of the fetched body with "PROXY> ". fn transform_body(body: string) -> string { let lines = body.split("\n"); var out = ""; var i = 0; let n = lines.len(); while i < n { let line = lines.get(i); if line.len() > 0 { out = out + "PROXY> " + line + "\n"; } i = i + 1; } out } // ---- Entry point ------------------------------------------------------------ fn main() { let listener = net.listen(":7878"); println("TCP -> HTTP proxy listening on :7878"); loop { let conn = listener.accept(); let handler = spawn ProxyConn(conn: conn); conn.attach(handler); // reactor now drives on_data/on_close for this connection } }