Hi!
On 28/05/2013, at 17:31, Gene Lian wrote:
> Hi Mounir and Fernando,
>
> I'd like to ask some questions from the Gecko point of view regarding the API prototyping at [1]. Some of them might be worth clarifying and discussing to improve the API's usability. Could you please return some feedback to me when you're available? Thanks a lot! Btw, I'm just starting with the API implementation at bug 876397.
Probably Mounir is the right person to reply to this questions, but I'll try my best answering with what I understood from this API :)
>
> 1. First of all, all these APIs are going to be managed under |interface mozIDOMApplication|. Right?
That's also my understanding. The Caller API is a "partial interface Application" so I guess this API will be part of mozIDOMApplication [1]
>
> 2. I'm very confused about the following 2 APIs:
>
> // The returned Future will contain true if at least a peer has been
> // selected, false otherwise.
> Future registerConnections(DOMString keyword);
>
> // The returned Future will contain true if at least a peer is allowed
> // to communicate with the application, false otherwise.
> Future connectionsRegistered(DOMString keyword);
>
> My understanding is the .registerConnections(...) means an app is wanting to add itself to the connection pool and the .connectionsRegistered(...) means an app is wanting to ask if other applications have been added into the connection pool. If my understanding is right, what does the return of .registerConnections(...) mean when it returns true? Does it mean there have already been some applications in the pool excluding itself? Isn't it just returning the same thing like .connectionsRegistered(...)?
The way I got it is that a call to .registerConnections("randomKeyword") will internally retrieve the list of apps that has previously registered themselves (via manifest) as able to connect based on the given keyword ("randomKeyword" in this case) and will show this list to the user in some kind of UI (to be defined) so she can choose which app(s) she wants to allow to connect. If the user chooses no application from this list, the result contained in the Future returned by the .registerConnections() call will be *false*. Or it will be *true* if at least one application has been selected and so allowed to connect. At that point (or probably before returning the result through the Future object), the implementation will need to add each of the selected apps to what you called the connection pool.
.connectionsRegistered("randomKeyword") will get *true* within the returned Future object if at least one app has been selected in the previous step.
> 3. If the "connect" system message can be sent to the apps that have registrations in their manifests, what's the main purpose of .registerConnections(...)? May I explain the difference in the following way?
>
> a. System message registration is setting a static condition during the start-up registration.
> b. .registerConnections(...) is setting a dynamic condition during the run-time.
>
> Both (a) and (b) have to be satisfied and then the connection can be successfully established.
I think an example will help you understand it better. So an example flow would be something like:
1 - App A registers itself as able to connect based on the "comms" keyword by adding the following to its manifest:
{
name: "Communications app A",
keywords: ["comms"]
}
2 - App B does exactly the same:
{
name: "Communications app B",
keywords: ["comms"]
}
3 - App C calls .registerConnections("comms"):
let future = app.registerConnections("comms");
future.then() = function(result) {
// See step 5
};
4. Before "future.then()" is called, the UI shows a list of apps that advertise themselves as able to connect based on the "comms" keyword. So the user will see something like (sorry for the crappy UI representation):
"
Do you want to allow a connection between App C and:
1. Communications app A (checkbox)
2. Communications app B (checkbox)
Accept | Cancel (buttons)
"
5. The user selects only App A and clicks "Accept". At that point "future.then()" is triggered:
future.then() = function(result) {
// "result" is true cause the user has allowed *at least* one app to connect.
// At this point we can call .connectionsRegistered("comms") and we'll get true.
// And we can also call .connect("comms");
app.connect("comms").then(function onconnect(ports) {
// Here "ports" is an array with an unique MessagePort that connects App C with App B.
});
};
>
> 4. This might be a stupid question because I didn't join the prototyping process in the first place. The |Future|s of all these APIs practically represent |DOMRequest|s. Right? If yes, the |.then(...)| actually stands for .onsuccess(...)/.onerror(...). Correct?
No. Actually this will be the Futures being implemented at [2] :)
> 5. What's happening if the sender is calling .postMessage(...) but the receiver hasn't called .onmessage(...) or .start() yet? Does the Gecko need to temporally cache the posts and then resend them after the receiver is ready ? Or just discard the posts? Actually, my main concern is: the sender has no way to know whether the receiver is ready to catch the posts. Is |request.accept()| exactly doing the acknowledgement I'm taking about?
That's a really good question!
As far as I can see the proposal doesn't specify if there will be a persistent message queue that can be delivered to an application that was getting messages before setting the message handler.
AFAICT request.accept() is a requirement for properly setting up the communication channel, so no message would be delivered to the receiver until it explicitly accepts the connection, but it is not telling the sender that the channel is properly set. However, |port.start()| seems to be doing that job instead. I agree that might be confusing.
>
> 6. It's not very clear to me what's the main difference between |request.accept()| and |port.start()|. They sound the same thing to me. That is, allowing the establishment of communication between apps. Could you please elaborate more regarding the difference?
Let's get back to the example above. On the receiver application (App B) once App C calls .connect("comms"), we will get a '"connect" system message:
navigator.setMessageHandler("connect", function(request) {
// At this point app B can accept the request or not, most likely based on the request origin.
// As the proposal specifies, not explicitly accepting the request, will reject the connection.
// Let's say we (as App B) want to connect with App C
port = request.accept();
// "port" is an instance of MessagePort.
// We have accepted the connection at this point,
// but that doesn't mean that we are ready to start receiving messages.
// We need to set the message handlers.
port.onmessage = function(evt) {
// Whatever we want to do with the messages.
};
// And now that we have the handlers ready, we can notify App C to start sending messages.
port.start();
});
I hope this helps. Mounir, correct me if I was wrong with any of my assumptions, please.
Cheers,
/ Fernando
[1]
https://mxr.mozilla.org/mozilla-central/source/dom/interfaces/apps/nsIDOMApplicationRegistry.idl#11
[2]
https://bugzilla.mozilla.org/show_bug.cgi?id=856410