PortFunnel allows you easily use multiple port modules.
You create a single outgoing/incoming pair of ports, and PortFunnel does the rest.
Some very simple JavaScript boilerplate directs PortFunnel.js to load and wire up all the other PortFunnel-aware JavaScript files. You write one simple case statement to choose which port package's message is coming in, and then write package-specific code to handle each one.
Everything we need to know to route one module's messages.
Package up an application's functions for accessing one funnel module's state.
A generic message that goes over the wire to/from the module JavaScript.
This is used to force a major version bump when the JS changes.
You'll usually not use it for anything.
Make a ModuleDesc.
A module-specific one of these is available from a PortFunnel-aware module. The args are:
name encoder decoder processorname is the name of the module, it must match the name of the JS file.
encoder turns your custom Message type into a GenericMessage.
decoder turns a GenericMessage into your custom message type.
processor is called when a message comes in over the subscription port. It's very similar to a standard application update function. substate is your module's State type, not to be confused with state, which is the user's application state type.
Get the name from a ModuleDesc.
A commander for a FunnelSpec that always returns Cmd.none
Useful for funnels that do not send themselves messages.
Send a GenericMessage over a Cmd port.
Send a message over a Cmd port.
Process a Value from your subscription port.
processValue funnels appTrampoline value state modelParse the Value into a GenericMessage.
If successful, use the moduleName from there to look up a funnel from the Dict you provide.
If the lookup succeeds, call your appTrampoline, to unbox the funnel and call PortFunnel.appProcess to do the rest of the processing.
See example/boilerplate.elm and example/simple.elm for examples of using this.
Finish the processing begun in processValue.
Process a GenericMessage.
This is low-level processing. Most applications will call this through appProcess via processValue.
Value and GenericMessageLow-level GenericMessage encoder.
Turn a Value from the Sub port into a GenericMessage.
Decoder for a GenericMessage.
Convert a message to a JSON Value
Convert a message to a JSON Value and encode it as a string.
Simulate a Cmd port, outgoing to a funnel's backend.
makeSimulatedFunnelCmdPort moduleDesc simulator tagger valueUsually, a funnel Module will provide one of these by leaving off the last two args, tagger and value:
simulator : Message -> Maybe Message
simulator message =
...
makeSimulatedCmdPort : (Value -> msg) -> Value -> Cmd msg
makeSimulatedCmdPort =
PortFunnel.makeSimulatedFunnelCmdPort
moduleDesc
simulatorThen the application code will call simulatedPort with a tagger, which turns a Value into the application msg type. That gives something with the same signature, Value -> Cmd msg as a Cmd port:
type Msg
= Receive Value
| ...
simulatedModuleCmdPort : Value -> Cmd msg
simulatedModuleCmdPort =
Module.makeSimulatedPort ReceiveThis can only simulate synchronous message responses, but that's sufficient to test a lot. And it works in elm reactor, with no port JavaScript code.
Note that this ignores errors in decoding a Value to a GenericMessage and from there to a message, returning Cmd.none if it gets an error from either. Funnel developers will have to test their encoders and decoders separately.
All the information needed to use a PortFunnel-aware application
with a single PortFunnel-aware module.
StateAccessorsis provided by the application.ModuleDescis provided by the module, usually via amoduleDescvariable.commanderis provided by the module, usually via acommandervariable.handleris provided by the application.