Comments (4)
Given that the most popular http client library (hyper
) is all in on tokio, that seems like it's the best place to start.
The nice thing about Rust is that threads and tokio can interoperate pretty easily; deferring to thread, or running a future in a tokio core on it's own thread are both easily possible
from magic-wormhole.rs.
Ah, thanks!
So I had an idea on the sans-io approach, after reading some of the advice on Brett Cannon's docs (linked above). Suppose we define the "wormhole core" object to take a set of mostly "send and forget" API calls, and a single call to retrieve the "action queue". For any given runtime/concurrency environment, the Core will be wrapped in a layer that knows about IO. That layer also exposes a concurrency-style-appropriate API to the app (maybe Deferreds, maybe Futures, maybe Delegation-style).
Ignoring for a moment the Transit and new Dilation features, I think the core API would look like this:
- w = create(args..) -> WormholeCore
- w.allocate_code() -> ()
- w.set_code(code) -> ()
- w.derive_key(purpose, length) -> key # only legal after key agreement
- w.send_message(message) -> ()
- w.close() -> ()
- w.websocket_connection_made(handle) -> ()
- w.websocket_message_received(handle, msg) -> ()
- w.websocket_connection_lost(handle) -> ()
- w.get_action() ->
Option<enum Actions>
and the rule is, after you've called one or more of the API functions, you're required to call get_action()
and do what it says until you get back a None. The "Actions" is a gigantic enum of everything the Wormhole might possibly want to tell the app (got_verifier, message_received, etc), plus everything the core might need the IO wrapper to do for it (open connection, send data, close connection).
That Actions enum would have the following variants:
- GotWelcome(welcome)
- GotCode(code)
- GotUnverifiedKey(key)
- GotVerifier(verifier)
- GotVersions(versions)
- GotMessage(message)
- GotClosed(result)
- WebsocketOpen(handle, url)
- WebsocketSendMessage(handle, msg)
- WebsocketClose(handle)
A Deferred-style wrapper would react to the various Got*
actions by stashing the value and firing any Deferreds that had been created earlier by one of the w.get_*
methods (using the OneShotObserver pattern). A Tokio-style wrapper would probably fire a Future that was created the same way. A Delegated-style wrapper would call the delegate's del.got_*()
methods.
To add Transit/Dilation, I think we add three more actions (TCPOpen, TCPSendBytes, TCPClose) and some corresponding input APIs. And we might also need a timer: w.TimerExpired(handle)
, Action: SetTimer(handle, timeout)
, and Action: CancelTimer(handle)
.
In each case, there's some driver that has to know how the IO and timers work. In Twisted that maps to the Reactor. In Rust, it could spin out a thread for each IO channel, maybe the top-level driver lives in a thread of its own (communicating with the actual application through a channel) and spends all of its time select-blocking on one of (request from app channel, response from a websocket/TCP channel, response from timer channel), and after any one of those sources yields an event, it notifies the WormholeCore and then drains the action queue, before going back to the select.
from magic-wormhole.rs.
Oh, flow-control will complicate the Transit/Dilation APIs. If we provide something like Twisted's IPushProducer model (pauseProducing
/resumeProducing
/stopProducing
), would that be generic enough to be adapted to other languages/environments models?
And we need extra API surface to manage Subchannels. In Twisted we handle this with Endpoints, so w.dilate()
returns a Deferred that fires with a triple of Endpoints, to which apps can attach whatever factories they want. Here, I guess we'll be dealing in terms of open/data/close and let the adapter do whatever seems reasonable. So the inbound API would grow methods like:
- w.allocate_subchannel() -> handle
- w.open_subchannel(handle) -> ()
- w.send_subchannel_data(handle, data) -> ()
- w.close_subchannel(handle) -> ()
- w.pause_subchannel(handle) -> ()
- w.resume_subchannel(handle) -> ()
and Actions would grow:
- SubchannelOpened(handle)
- SubchannelDataReceived(handle, data)
- SubchannelClosed(handle)
- SubchannelPauseProducing(handle)
- SubchannelResumeProducing(handle)
- SubchannelStopProducing(handle)
I think that could all be mapped to Endpoints. Allocating the subchannel without opening it is a bit weird. Maybe we could use a different sort of handle to bind those parts together (allocate
takes a user-provided allocation handle, then SubchannelOpened
returns both that allocation handle and the new subchannel-id, and then all the other commands would reference the subchannel-id). Or use the user-provided allocation handle for everything, and the subchannel-id is hidden internally. Or remove allocate
and let open
return the handle that you pass into everything else, and remove SubchannelOpened
(except that subchannels can be opened by the remote end too).
from magic-wormhole.rs.
Oops, that commit referenced an issue on my fork and shouldn't have closed it.
Anyway, that PR still closes this issue (with some other commits though). Basically, I've decided to use async-std instead of tokio because it's more intuitive (async-std didn't even exist at the time this issue was discussed lol).
I've decided against sans-io approaches to keep the implementation more simple for now.
from magic-wormhole.rs.
Related Issues (20)
- Tab completion HOT 5
- Gather transit connection information programmatically HOT 4
- Sender hangs when the file size is a multiple of 4096 HOT 3
- Provide example code in source form HOT 6
- Add 32bit build on Windows HOT 4
- Allow compiling without clipboard support HOT 1
- transfer: receive wormhole close should not throw error when failed HOT 5
- transfer: program not exiting when sending an empty file HOT 15
- Panics when IPv6 is disabled HOT 5
- Cancellation doesn't work in all cases
- Detect broken TCP connection to peer HOT 1
- Port forwarding crashes HOT 4
- AddrNotAvailable error for IPv4 on Windows HOT 1
- RUSTSEC-2022-0048: xml-rs is Unmaintained HOT 1
- Using tcp relay with tcp:hostname syntax will panic
- Feature Request: cli installable using cargo-install HOT 2
- feature request: support ssh invite/ssh accept modes HOT 5
- Add function to get claimed nameplates
- Flaky tests
- rand >= 0.8 break WASM support HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from magic-wormhole.rs.