wamp-proto / wamp-proto Goto Github PK
View Code? Open in Web Editor NEWThe Web Application Messaging Protocol
Home Page: https://wamp-proto.org/
The Web Application Messaging Protocol
Home Page: https://wamp-proto.org/
In Call messages you can send 0,1 or multiple arguments.
In CallResult and Event messages you have to send an unique argument, which can be null or a list of objects.
Why theses differences ? Shouldn't we always be able to send 0(null), 1 or multiple (without the use of list) arguments in all messages using arguments ?
What I mean is all messages using arguments should use the same specification.
What's the function of the "errorURI" in the TYPE_ID_CALLERROR message
sent to the client? I did read in the specification:/"If errorDetails is
present, it MUST be not null, and is used to communicate application
error details, defined by the errorURI."/ So I assume the error ID is
this errorURI? So, what happens if the client calls this errorURI
through RPC? Should that ever happen from the client and what should the
result be either way?The errorUri is to identify the actual error that occurred.
For example, if a RPC was made to some endpoint expecting a number, and that number was too large, the returned errorUri might be
"http://example.com/error#number_too_big"
and errorDesc
"The provided number was too big to consume."
and errorDetails absent.
On another example, say a list of numbers was expected, but not multiples of 3.
A call with argument [0,1,2,3] might then return with errorUri
"http://example.com/error#invalid_numbers"
and errorDesc "one or more numbers are multiples of 3".
The errorDetail then can be used to communicate the RPC specific details of the error:
errorDetails = [0, 3]
The interpretation of the value provided with errorDetails (if present) is up to the application, but should of course be documented for the respective errorUri.
The errorUri is merely for identifying error (in other frameworks, that could be "error code" - but with WAMP we use URIs for everything).
The errorUri is not meant for RPCs or topics. Calling an errorUri likely won't make any sense - though there is no formal requirement that you can't reuse an errorURI for identifying and RPC endpoint or topic. I would strongly recommend against that however.
Thank you for the clarification on this. I wasn't sure how to interpret this potential behavior as an edge case.
Should your WAMP spec reflect that the errorURI, while similar to an RPC or topic endpoint, should never be callable to prevent crafty programmers from abusing the spec?
Hi,
I'm reading the WAMP V2 specifications and starting to develop the my first alpha implementation of this protocol using Java, but first I need to know if my understanding of the specs are right.
Thanks.
Better explain metaevents:
Prefix Maps (CURIEs) serve two purposes:
URIs can occur in:
WAMP itself:
WAMP payloads:
Currently, a Prefix for some URI set can only be
When client 1 publishes an event containing CURIEs in the event payload, how does a client 2 know how to resolved those CURIEs when it doesn't have the prefix map of client 1?
Even if the server knew the payload structure of the published event and the prefix map of client 1, it needed to "reshrink" the URIs for each subscriber using that subscriber's respective prefix map.
That would make message dispatching to large numbers of subscribers grossly inefficient.
I really can see only 2 ways out of this dilemma:
The latter could be a little more relaxed: a publisher may use (his own) prefix map, the server - knowing the publisher's prefix map - could reshrink the URIs contained, and dispatch with fully qualified URIs.
However, even then, the server needs to know the event payload structure to be able to identify the "strings" that really are URIs, and potentially need reshrinking.
We should make 3 conditions mandatory with this design question:
If we dropped the "reduce wire payload" requirement and made URIs on the wire always fully qualified (that is forbid CURIEs on wire), then things are much easier ..
There is a proposed WebSocket extension doing frame-based compression. But: either that is only able to compress within 1 frame, not maintaining compression state across frames, or it would maintain such state, but then the server could not prepare a compresses octet sequence once and send that out on multiple connections.
We should make that clean and symmetric.
Each peer (client and server) has 2 prefix maps for a session:
From the server-side:
From the client-side:
Transport Roles:
PubSub Roles:
RPC Roles:
Currently, a client, that is the peer iniating the WS/TCP connection to the server, is only able to have the following PubSub and RPC roles:
There is no real reason for this. A client could as well fulfill other roles:
Essentially a peer can fulfill any subset of the PubSub or RPC roles.
This can have various use cases:
We should make WAMP fully symmetric.
AutobahnJS now includes an auto-reconnect feature. Does it make sense to incorporate this into WAMP? I was thinking a re-connect attempt would send the previous sessionId to the server to let it know it's a re-connect and not a new connection.
Topics and Procedures are identified by URIs.
A client needs to have builtin knowledge which topics/procedures are available, and for which it is authorized.
Probably a mechanism to discover available topics/procedures starting from a canonical entry point would be useful.
Probably even a mechanism to retrieve metadata about topics/procedures (i.e. arguments of a procedure, description, whatever) would be useful.
Self-desribing topics/procedures?
[GOODBYE, Reason|uri, Details|dict]
vs.
[ERROR, SUBSCRIBE.Request|id, Details|dict, Error|uri]
Not functionally important, but feels a bit weird.
An advanced broker may offer the option to publish an event, and storing the event persistently.
One way would be: PUBLISH.Options.persist|bool
.
Another would be to differentiate the "degree of persistence": in-memory, local persist, transactional, .. : PUBLISH.Options.persistence|string := "memory" | "local" | "transactional"
Goal:
Make it possible to automatically / adaptively keep the radio state on a mobile connection in low-latency, active state.
Did some experiments:
http://lists.w3.org/Archives/Public/ietf-http-wg/2012JanMar/1083.html
2 options: either make that some "standard RPC", but more cleanly, make it possible to implement within library/framework protocol implementation.
2 messages:
PING: [TYPE_ID_PING, echo, discard, reply_discard_length]
echo: <object | null>
discard: | null
reply_discard_length: >=0
The peer should reply with a PONG. The "echo" MUST be returned untouched. The "discard" is thrown away. The "reply_discard_length" specifies the length of "discard" in PONG.
The "discard" string SHOULD be randomly generated. Can be any cheap, unsecure pseudo RNG. Rationale: make it impossible for intermediaries to "optimize" away that payload.
Since the "discard" is effectively used to "pump up the up-/downstream traffic rate so that radio state can be kept up. I.e. target discard rate : 4kb/s ..
PONG: [TYPE_ID_PONG, echo, reply_discard]
echo: the echo'ed object | null
reply_discard: string
The reply_discard string SHOULD be a random string, and MUST be of length "reply_discard_length". When reply_discard_length = 0, then this is an empty string, (not null!).
a la MBWS connection recovery: http://tools.ietf.org/html/draft-hapner-hybi-messagebroker-subprotocol-01#section-2.1
In theory, MBWS is a thin low level layer that sits on top of WebSockets, which could be used to build higher level protocols (such as WAMP).
Reading this part of the specs:
... With the latter, a peer might "route" an incoming call directly to an implementing endpoint within the same program (and hence no actual messaging over a transport is happening) ...
I was thinking on this scenario:
Following the specifications, the communication between two peers is stablished using a Session (over a channel on the transport layer) and then sending the messages (ex.: HELLO/REGISTER/CALL/GOODBYE), but how can a peer register/call endpoints on himself?
To solve this problem what option is more convenient (or another that I'm not considering):
Thanks.
Meta events provide ability to track clients subscribe/unsubscribe "as they come".
Meta events do not provide i.e. a list of current subscribers, or a history of subscriptions.
Probably we need a function to retrieve the current list of subscribers per topic.
This feature would allow receiving RPC results in parts.
Essentially roughly similar to one-time ad-hoc subscriptions on an RPC result.
A client issues a RPC.
The server answer can be:
CFR
CPR, CPR, ..., CFR
CE
CFR = Call Final Result
CPR = Call Partial Result
CE = Call Error
Open issues:
What about
CPR, CPR, CE
?
It will break most of our client library designs. Those are based for RPC on Deferreds. A deferred can have it's resolve()/reject() callback only called once.
In JS, a deferred can have a progress() callback which can be called multiple times.
This is not true for Twisted Deferreds and also not for our AutobahnAndroid ad-hoc Deferreds.
We now have pattern-based (prefix and wildcard) subscriptions for PubSub.
We should add pattern-based registrations for RPC.
This will require the INVOCATION
to have a INVOCATION.Procedure
element.
On mobile cellular networks, websockets suffer multiple timeouts and disconnects, especially when hoping between cellular base stations (e.g. on a moving vehicle). With the increased prevalence of data-centric mobile devices (more smartphones / tablets than PCs today), this becomes an important matter to consider.
Is there a built-in recovery mechanism that resumes a websocket session, such that no messages are lost or duplicated. I understand right now that partial / corrupted single payloads should not be possible due to underlying transports of WAMP, but not duplication or complete loss.
There is also no way of ensuring atomicity via transactions:
Atomic = all changes are made (commit), or none (rollback).
Durable = committed changes survive various classes of failure.
I would like error handling & recovery to be part of WAMP design thinking, just like the excellent manifesto of ZeroRPC - "RPC so good you'll forget the R". Only then can system designers trust it for the mobility future.
We should use kwargs
in wamp.cra.request
instead of the positional auth_extra|dict
argument.
When retrieving event history on a topic by calling wamp.topic.history.last
, setting limit == 0
should retrieve the complete event history (if the broker allows to do that and/or the history does not exceed a broker limit).
Should the WAMP specification have (or the option) to inform an "identifier" of the publisher in the "EVENT message"
(like the client's "sessionId", or the text "server" when the EVENT is auto-generated by the server).
To maintain backward compatibility with existing clients, the "identifier" might be sent in the last position (4th argument),
And to maintain traffic payload of existing applications, this feature could only be enabled on demand by the clients with a new optional parameter in SUBSCRIBE message (i.e "identifyEventPublisher"=TRUE)
What do you think?
Follow the discussion at:
https://groups.google.com/forum/?fromgroups#!topic/wampws/hwNmvCapo-U
Bn: Broker n
Sn: Subscriber n
Pn: Publisher n
Dn: Dealer n
Cn: Caller n
En: Callee ("Endpoint") n
Regarding publishing, the order guarantee is as follows:
If S1 is subscribed to Topic 1 and Topic 2 and P1 publishes Event 1 to Topic 1, and then Event 2 to Topic 2, then S1 will receive first Event 1 and then Event 2. This also holds for Topic 1 == Topic 2.
Further, if S1 subscribes to Topic 1, the SUBSCRIBED messages will be sent by Broker before any EVENT for Topic 1.
But in general, SUBSCRIBE is asynchronous, and there is no guarantee on order of return for multiple SUBSCRIBEs. The first SUBSCRIBE might require the Broker to do a time-consuming lookup in some database, whereas the second might be permissible immediately.
Similar to PUBLISH
and EVENT
, we should provide ability to identify Callers (to Callees):
CALL.Options.disclose_me|integer
INVOCATION.Details.caller|id
Did you thought about any flow control in WAMP?
Not sure what you mean. Flow-control as in "slow TCP receiver, and fast send" or such?
Yes exactly. E.g. Browser does a heavy 3D-Rendering for every received event. Is this in the scope of the specification?
TCP flow control is handled at the TCP level by the networking stack in the OS kernel. This is unrelated to WAMP. But I guess this is not what you mean.
If you receive events, and your app cannot keep up processing, simply skip processing of events in your app. You will continue to receive all events, but only process a subset in your app.
If your downlink network connection cannot keep up with the volume of events sent by the WAMP broker, then it's an implementation detail of the WAMP broker how it behaves. It might just start dropping events (to that single slow consumer). Or it might start buffering, slowing down all receivers. Or it might deny further publications to the respective topic.
All above is not relevant to the WAMP protocol specficiation however. We should probably mention the stuff above that in the spec nevertheless.
In general, the idea is to specify core routing behavior for WAMPv2 so that Broker and Dealer implementations are interchangable, and have all application specific code inside Callers, Callees, Subscribers and Publishers.
In other words: Brokers and Dealers are not supposed to run application code.
HELLO
message.Currently, GOODBYE
is used for two different roles:
Additionally, currently only the Router can send a GOODBYE
during session establishment.
The Endpoint should also have this possibility. Use case:
HELLO
for 'realm1'Define message batching
WAMP-CRA = WAMP Challenge Response Authentication
Currently implemented in AutobahnPython (client+server), AutobahnJS (client).
Under development in AutobahnAndroid (client).
MetaEvents are generated
Whether MetaEvents are generated at all, for which topics, and if so which information is present in a generated event is
[SUBSCRIBE,
"http://awesometopic#1"]
=>
[METAEVENT,
"http://awesometopic#1",
"http://wamp.ws/pubsub#subscription-denied",
{"desc": "Topic is closed on Weekdays!",
"validdays": [6, 7]}]
From JS:
sess.subscribe("http://awesometopic#1", onEvent1, onMetaEvent1);
function onMetaEvent1 (topic, metatopic, metaevent) {
// topic == "http://awesometopic#1"
// metatopic == "http://wamp.ws/pubsub#subscription-denied"
// metaevent == {.. stuff above..}
}
MetaTopics are for identifying MetaEvents on base Topics. They are identified by _URI_s:
In case a Subscription or Registration is using "match" == "exact"
, there is no need to forward the PUBLISH.Topic
or CALL.Procedure
again within EVENT.Topic
or INVOCATION.Procedure
.
In this case, the Broker or Dealer SHOULD transmit ""
(the empty string) for the respective message elements.
With WAMP Challenge-Response Authentication, the client already gets a list of RPC endpoint URIs (and PubSub topics) he is authorized to use. WAMP-CRA is implemented on top of 2 predefined RPCs
http://api.wamp.ws/procedure#authreq
http://api.wamp.ws/procedure#auth
This could be extended by providing a reflection API:
http://api.wamp.ws/procedure#describeProcedure
http://api.wamp.ws/procedure#describeTopic
This should at least include developer documentation for the parameters and return values.
We could of course invent something along
http://json-schema.org/
http://tools.ietf.org/html/draft-zyp-json-schema-04
and return respective machine readable data with "describeProcedure".
This could be then used for validation and/or stub generation.
However, I don't believe in schemas for validation ..
Take the example here:
http://json-schema.org/example1.html
What if I want tags to follow some regular expression, but only if the user is not admin?
What if I want the minimum allowed product price to depend to on product category?
In any case: there is no need to extend the wire protocol.
It seems the only difference is that ABORT gets sent only before a session is established and GOODBYE gets sent only after a session is established. Is there a good reason why these shouldn't be the same message? (e.g. GOODBYE before the session is established means the session was aborted)
Easiest to discuss by example.
P1)
Message type 1: non-polymorphic
[1, type A]
P2)
Message type 2: polymorphic in number of elements
[2, type A]
[2, type A, type B]
[2, type A, type B, type C]
P3)
Message type 3: polymorphic in type of elements
[3, type A]
[3, type B]
[3, type C]
P4)
Message type 4: polymorphic in number and type of elements:
[4, type A]
[4, type B, type C]
[4, type B, type C, type D]
WAMPv1 uses : P1, P2 and P4
This is bad, since it doesn't really add value, and complicates things.
WAMPv2 should restrict itself to: P1 and P2, and have no messages of P3 or P4.
Type checking becomes very simple:
msg type = 2 and if len(msg) == 2, then arg1 must be of type A and arg2 must be of type B.
Simple == good.
With WAMPv1, publication of events is unacknowledged - always.
With WAMPv2, the PUBLISHED
(and PUBLISH_ERROR
) messages allow acknowledgement of publication.
We should probably make that optional, depending on PUBLISH.Options.ack == 1
.
I list this here for completeness. Currently, I am not very keen on that one.
The feature would be to be able to subscribe to whole sets of topics, the set being potentially open ended.
Example: subscribe to
U = http://example.com/books/*
The asterisk at the end is a wildcard.
The wildcarded topic would effectively match any topic that has the U as a prefix:
http://example.com/books/awesomebook1
http://example.com/books/comic123
An asterisk at the end (prefix wildcard) could also appear like so
which would match any of
http://example.com/books/awesomebook1
http://example.com/books/comic123
http://example.com/bookings#444
http://example.com/bookstore/orders/1
http://example.com/book#99
Allowing wildcards in the middle of a URI would likely only be sane if for URI parts separated by "/":
would match
http://example.com/bookstore/orders/1
but not
http://example.com/stores/store1/orders/1
The latter is how MQTT is doing it. However, they are not implementing real "set semantics" on top of wildcarded topics:
http://groups.google.com/group/mqtt/browse_thread/thread/7967f8e9fe9dd705
Also, they have nothing in the direction of MetaEvents .. which we also needed to answer how to make those work with wildcarded topics.
If at all, I'd only be voting for Wildcard at the very end. Topic prefix matching. Not for wildcards in the middle.
Implementing them only at a syntactical level would be straightforward, but IMHO just not right.
Like in CSS: x_...
(to avoid collisions).
Implementations that don't know about a specific x_..
attribute MUST silently ignore the attribute.
From the spec:
Keys in Options and Details MUST BE of type string and MUST match the regular expression
[a-z][a-z0-9_]{2,15}*
for WAMP predefined keys. Implementation MAY use implementation-specific key which MUST match the regular expression_[a-z0-9_]{2,15}*
.
This means that keys must be either 1 character OR 3 or more characters. This doesn't seem right, unless 2-character keys are special in some way.
In the original WAMP specification, the WELCOME message was sent first and specified the protocol version. This was nice behavior, because a client wouldn't have to know ahead of time what version of WAMP it's connecting to, it could be a runtime option.
Could this behavior be kept in v2? Maybe instead of changing WELCOME, create a new message type to maintain the old behavior with ID 0?
FAQ: Describe how WAMP differs from
There is space for a range of protocols to coexist, because they address different areas. In the messaging space, we’ve found over time that > whilst efforts to create a single protocol have been made, that has often ended up as focused around a particular set of qualities of service, and not optimised to cover the the whole range of them.
For example, if we look at IBM’s own messaging protocols – there are several. There’s WebSphere MQ which is all about reliable, transactional, solid, clusterable, enterprise, JMS and other APIs, etc etc.. WMQ itself isn’t ideal for very high-speed in-memory or multicast scenarios, so there is also WMQ Low Latency (interoperable with the new multicast feature in WMQ 7.1, but a separate protocol). Neither WMQ LLM or WMQ scales down to unreliable device networks and embedded systems, so there is WMQ Telemetry (aka MQTT), which was specifically designed for constrained devices and networks, and that can interoperate with the main queue manager, too. Oh, and sometimes you want to deal with files (WMQ File Transfer Edition), or access message data via HTTP (WMQ HTTP Bridge). You need to address a range of requirements in a messaging story.
Instead of complex QoS for message delivery, provide per-topic configurable persistent message history.
Client can request message history during subscribe or separately:
Events could need an EVENT_ID and/or EVENT_TIME.
Client is responsible to handle overlaps (duplicates) when it wants "exactly-once" message processing.
WAMPv1 uses JSON as a message payload format. This is simple, fulfills its purpose, and has some nice aspects:
However, there are (at least) 2 situations where JSON is a pain:
Further, WebSocket (WAMP default transport) already allows for binary message payload.
It would thus be neat to have a 2nd additional (optional) message payload format for WAMP.
A simple, binary transparent one. Simple. No fancy IDL+compiler stuff!
http://en.wikipedia.org/wiki/Bencode
For the WebSocket transport binding of WAMP, that could be frictionless to do:
If its a text WS message, JSON is assumed/expected.
If its a binary WS message, Bencode is assumed/expected.
There are 2 aspects to think through:
a) WAMP itself
b) the payloads transferred via WAMP
a)
Both JSON and Bencode have:
strings
integers
arrays
The strings used in WAMP (for URIs or Error Desc) MUST BE UTF8. So that translates without problems.
However, WAMPv1 uses "bool" and "null":
i) PUBLISH has = bool
ii) EVENT has always a payload body, which MAY BE null.
iii) CALLRESULT has always a payload body, which MAY BE null.
None of that is essential.
i) use 0/1 integer
ii+iii) just omitting the value would work too.
b)
There might be 3 kinds of clients: text-only, binary-only, can-do-both
So for app payload (i.e. RPC Call arguments, or Publish event payload) we need to map between:
text <=> binary format
There are different possibilities for mapping. I.e. map JSON null to 0, map it to "null", or "". Likewise a Bencode string, could map to UTF8, or HEX.
A sane way would to make the kind of mapping performed a property of the
RPC proc
PubSub topic
A specific RPC proc could say: If you call me with Bencode, I will assume all Bencode strings to be UTF8 and forward those plain to JSON clients. Or it could say: if you call be with Bencode, I assume strings are really binary and convert all to Base64 for JSON clients.
That would then apply to any string inside the payload. So I could NOT say: arg1 = Base64, arg2 = UTF8
The latter would require essentially an IDL. And that is no longer simple.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.