Open y-lohse opened 6 years ago
Now a few subjective points.
There's probably a new use case, which is "Silent Computing". A client wants another app to perform some computation on some data (probably data the client has not access to) and get a result back, but the service shouldn't be visible. This can be hacked by hiding the service iframe, but maybe it should become a legit thing. It also needs very special consideration, because while intents in general are there to work around permissions, it's usually with the user's consent. In this case... maybe not ☠️ . I think @Ljinod and @Gara64 are interested in this, and @ptbrowne may have actually done it. I may also have a use case for this, but not sure yet.
Regarding A), I think all use cases are good ones and I have no problem keeping them, but maybe we could clean up the API a bit? Especially the callbacks and flags used to load / unload the iframe could probably be replaced by introducing lifecycle hooks or something like that? @gregorylegarec is probably the wisest 🐒 on this topic.
Thanks for opening this issue @y-lohse. The more we use intents the more we are facing the limits you described.
Concerning your point B.1, we actually already faced this situation in Collect, when we need to link to a given folder into cozy-drive. At first we have been thinking using an intent, but we quickly realized that we were over-complicating the feature. We concluded that the best way to achieve our link was to use a redirection
from the cozy stack. A redirection is a simple link, having the form /redirect/io.cozy.files/121238468868448/
. This link is managed by the stack, which looks which app is able to handle the given doctype. We assume that Cozy-Drive should declare into its manifest something like:
"redirections": [{
"doctype": "io.cozy.files",
"template": ":id"
"target:" "/#/files/{id}"
We discussed this point with @poupotte and I think that is something backlogged for the back team (@nono ?), but not yet implemeted yet. Perhaps if you need it too it could be done sooner as expected.
Totally agree, we should pass a list of callbacks at intent's creation. We just have to keep backward compatibility for a time.
Like you, we need to have what you call Silent Computing (love that name). At this time, using intents to handle this kind of feature is a practical solution, but I am not sure that it was intent's initial purpose. In my opinion, intents are expecting an action from the user. We still don't know what the best thing to do or implement. Maybe some kind of simplified intent ?
As we dig deeper into Claudy's logic (espacially @CPatchane), we are needing some more complex communication between service and client. For example, sometimes the client expect some information from the service without having the service terminated. This could imply that we may improve the intent mechanism to be able to send several messages from the service, and not only final one as it is working now.
EDIT: s/slack/stack
Uh ok, I missed that info. At first sight, it seems like a better solution than using intents, especially if it's already planned. I'll just wait for confirmation of that and if it is indeed planned, I'll scrap it from this list :)
I feel like it's ok if we make that part of intents. Intents are there for cross-app communication, and the mechanics will probably be super-similar.
Again, we may use the disposition
here, eg. a disposition of none
or hidden
would mean that the iframe should be kept hidden. But I haven't thought too much about it. I'll add it to the list, as it seems it will be needed.
Sounds good! Do you have a concrete example of information that the client needs while the service is running?
Conceptually, I think it's perfectly fine if the client and service exchange data more than once. A few thoughts about the API:
data received
callback from the intent terminated
callback. The second one wouldn't receive any data, it's only there to perform clean-up operations if needed.I haven't heard of this proposition until this issue. As far as I can tell, it is not in our backlog.
In fact, I'm not sure if it is really better than intents. Intents have some nice properties. For example, it's possible to pass structured informations as JSON (it's harder in an URL). What advantages do you see to use a new redirections system instead of the intents?
I could add more ideas about what you describe @y-lohse, thanks for opening this issue.
Completely agree about that and that could be better implemented in the API. We could use a kind of lifecycle of the intent to be better handled by the client and inspire us from components lifecycle in (P)React.
createService(...) // initial data sent to service
.mount(...) // current start()
.intentDidMount(...) // current onReadyCallback usage
.intentWillUnmount(...) // ~ current terminate with exposeRemoval
.intentDidUnmount(finalDataFromService...) // current then()
.intentWillResize(newSize...) // better handling resizing from the client
That's a pure example and could be not correct in some points but it's to show the main idea. Also, sending data from the Client already started during the process could be a good idea but that must come in a second time since we doesn't know if we really need it IMHO.
I think this part is just a use case of a more general thing that I could name Smart Redirection. This is different from the intent currently implemented since:
In this case, the client cannot know which app will open its request and what will be the result from the redirection.
I like to use the search use case as example for here:
Smart redirection declarations from the service application:
"redirections": [{
"service": "TERM_SEARCH",
"targetURL": "/#/search/web/:term"
}, {
"service": "IMAGES_SEARCH",
"targetURL": "/#/search/images/:term"
}, {
"service": "SEARCH",
"targetURL": "/#/search/:type/:term"
}]
So, on the client side:
const urlToRedirect = await cozy.redirect("SEARCH", { type: "web", term: "Recherche depuis Cozy" })
And for files of folder that could be :
cozy.redirect("FILE_ID", { id: "zekdze892jdeh221d" })
cozy.redirect("FOLDER_ID", { id: "zekdze892jdeh221d" })
cozy.redirect("FOLDER_NAME", { name: "/Administration/SFR" })
Ideally, calling this function, if a service matches, the client will receive an obfuscated URL from the stack to use (as for the OAuth connexion) null
if no service was found.
I would say, in a first place, that the response need to be an information that doesn't need permissions for the client. For me, if we use a service to silently compute an information that the initial application doesn't have the permission, it would be a way to hack the stack permissions system and access informations without permissions. Or maybe we could use like an intent to start the computing and when the result is coming back, it will be displayed to the user as the information that will be received by the current application which asked for it. It's just some thinkings but we have to more discuss about the real needs and the implementation for this latter.
My 2 cents.
@CPatchane I also think this API design is probably what makes the most sense. Regarding complex coms in itself, do you have a concrete example of information that the client needs while the service is running?
I've added a note about this topic in the first post. Not much else to add at this point imo.
Hot topic 🔥 So just to be clear since there were some talks outside of Github as well, there is no redirection API that is planned at the moment. So I think it's up for discussion wether it's better to introduce such a separate API, or use the intent system. Here are some pros and cons that have come up, feel free to add more:
Using Intents | Using a redirection API | |
---|---|---|
Specification work | small-ish update to an existing spec (introducing dispositions) | creating a small new spec |
👎 Requires non-trivial front end work | ✅ | ❌ |
👎 Requires non-trivial back end work | ❌ | ✅ |
👎 Introduces a new manifest field | ❌ | ✅ |
👍 Privacy (redirecting app doesn't know what happens next) | ❌ | ✅ |
👍 Redirect based on structured data | ✅ | ☑️ |
My opinion on this: If the stack can handle the redirection, apps don't have to implement it which is very neat. Having to add a new section to the manifest for this is a compromise I'm ok with.
I also understand if the stack doesn't want to take care of this, since it's probably a fair amount of work (more manifest inspecting, URL pattern matching, etc) — especially since intents in their current incarnation can kind of already do redirections. It's also logical enough — the window
disposition is meant for this.
For privacy, it's a tie. Using a redirection API doesn't protect against a rogue application.
About the disposition, I thought it could be also used for hidden computing. If if it the case, I really think it would be more logical to use intents and disposition for links.
After discussing with @nono two days ago : intents are already designed to return an URL for a given ACTION
on a given doctype
. We could "hack" this feature to get an URL for a REDIRECT
action.
For example an app's manifest should be able to declare:
"intents": [{
"action": "REDIRECT",
"type": ["io.cozy.files"],
"href": "/#/files/:_id"
}]
And we would just have to implement a method cozy.client.intents.redirect(document)
. Passing the document should give us all the information we need : doctype
, _id
, or whatever we need to replace in the url. The method should handle the redirection/opening too.
The only limit I see is the case with redirection url with unknown segments, for example /#/page/:_id/:unavailable_property
. But I am not sure this case could happen if applications and routes are well designed.
So essentially here instead of injecting the service iframe, you'd do some pattern matching on the href
and then change the url to that?
I think that would be a smart way to do it. I can't think of use cases where the client doesn't know enough to give some params. If we can somehow declare optional params in the href
in the manifest, that would probably cover what we need.
That's it.
Cool, I guess we solved links! Onto the 2 other topics.
After thinking about this a bit, looking at code and writing some, here's what I think:
action
and type
.That being said, I think it would be too much overhead to introduce a separate API. I think we should make these intent hacks official by extending the intent spec to support messaging between client and service, and reshaping the API to provide more hooks (see @CPatchane 's draft for a general idea). I don't think the stack will need updates at all.
What do you think?
On a décidé en "Front Transverse" que l'on déplacera les intentes dans un package séparé dans le repo de cozy-client. Mais que ce n'était pas forcément une priorité du moment
Lately, we have discovered new use cases for intents, and in the past we've had to add things to the Intent API that weren't part of the initial plan. We should start thinking about the next version of the intent specs.
Before we start, two strongly recomended reads:
A) Things that are not in the spec but are in the API
1) A hook for the client to know when the iframe is loaded — See #189, used to wait until the service is loaded to display it. 1) A hook for the client to remove the iframe manually — See #189, used to animate the iframe closing. 1) The service tells the client to change the size of the service's frame — See #175 and #194, used when a service wants to be displayed at a specific size and the client couldn't predict it. Can happen after the service is initialized or when the user interacts with the service (eg. expanding Claudy).
B) Things that we need but are not in the spec
1. Linking to a specific part of an app
The most common example for this is wanting to link to a certain document inside cozy-drive. Except cozy-drive, no one has any clue what the exact URL is — in fact, even the URL for the drive app is mostly unknown for apps.
The solution here is to use intents. The client will express that it wants a redirection (maybe through a dedicated method like
cozy.intents.redirect()
, or maybe by adding a disposition parameter).The service can indicate in it's manifest that it handles redirections, as well as what parameters the new URL accepts (see this comment).
2. Complex communication
The current model specifies that the client sends some data at the start of the intent, and the service replies with some data at the end, and nothing in between. It would be good to have the ability for the service to send intermediate messages as well.
3. Silent Communication
Kinda vague at this point, but a client might need access to some data from another app, but without showing the service's UI. This could be because the client itself will show that data, aggregated with dat from other sources. Or it could be because there's just no need for a UI.
This has some implications in terms of security that need to be considered.
???
You tell me. I'll try to keep this post updated.