Services FAQ
- C/C++ services
- File system access
- Limits on data returned from a service
- NodeJS
- Service exiting after 30 seconds
- Long running services
- Keeping state between commands
- New service version not showing changes
- Ensuring setup is complete
- Making commands available on public bus
- Getting calling app ID
- Getting calling service ID
Can services be coded in C/C++?
No, currently, only JavaScript.
What is the naming convention for services?
Currently, a service must be packaged with an app, but it can be a stub app with no functionality and can be hidden from the Launcher. Dashes are not allowed in service names, they can include only letters, numbers, and dots.
The service ID must start with the app ID.
For example:
App ID: com.palmdts.testacct
Service ID: com.palmdts.testacct.contacts.service
What kind of file system access is available to a service?
Services are run in a jail with limited file system access. Access is allowed to the service directory, /media/internal, and a number of system directories. You can look in/etc/jail_triton.conf to see what is being mounted.
Is there a limit on data that can be returned from a a service?
A definitive limit has not been determined yet, but testing has returned up to 2.5M of data. There is a limit on the length of console.log messages, so depending on how you try to see what is being returned...
What are the node.js modules provided? Can I deliver additional ones in my installer?
Everything listed on the nodejs.org site for v0.2.3 should be available. For additional modules, JavaScript-only modules can be loaded from within the service installation directory. Native code NodeJS extensions are not allowed.
To load node modules, you'll need to initalize require:
// Node.js require load if (typeof require === "undefined") { require = IMPORTS.require; }
Currently, NPM (Node Package Manager) and other 3rd party services are not supported, but that is likely to change in the near future.
Why does my service exit after 30 seconds?
By default, if not actively working on a command, a service exits after 30 seconds. You could extend this using the "activityTimeout" field in the services.json configuration file, however, this is not recommended for long-running services. See the next question for more information.
How do I keep my service from being killed after the scene that calls it is closed?
The "wrong" way to do this is to extend the activityTimeout as this makes it much more likely that errors in the service will keep it running for excessively long times. It is also not recommended that you extend the commandTimeout field, which should only be used to fine-tune the time a command takes to return a response.
One option is to use a subscribeable or watchable command. The initial response from the command indicates that the command was recieved and processed, and the second/subsequent responses can return the data from the remote server. An open subscription will keep the service running until it's canceled.
To do this, you need to configure your command assistant with "subscribe: true" or "watch: true" in your services.json file to mark the command as subscribeable or watchable. If either of these are set, then the command assistant's run function is passed a FutureFactory, which can be used to send multiple responses.
For example (services.json):
{ "name": "subscribable", "assistant": "SomeCommandAssistant", "subscribe": true, "public": true },
Example subscribeable command assistant:
function SomeCommandAssistant() {
}
SomeCommandAssistant.prototype = {
run: function(future, subscription) {
var assistant = this.controller.service.assistant;
var name = this.controller.args.name;
future.result = { reply: assistant.getHello() + name + '!'};
this.interval = setInterval(function ping() {
var f = subscription.get();
f.result = { reply: "ping " + name +"..."};
}, 1000);
},
cancelSubscription: function() {
clearInterval(this.interval);
}
};
Note that this just an example of how to do a subscribed command -- i.e. the setInterval is just an example of a periodic callback, not a required part of implementing a subscription. However, it is important that services not stay running when they do not have to. Services can use the Activity Manager to set up triggered activities and callbacks. This is critical to minimizing power usage.
In addition to implementing a subscribable command, you also need to make the request from the application with Mojo.Service.Request, rather than using the Mojo.Controller.SceneController's request() method, since the controller cancels any requests when the scene closes.
How do I keep state between invocations of commands?
Since your command assistants are only around when processing a request, you can store more-persistent state up in the service assistant object to have it stick around between requests.
From your command assistant code, you can use something like this:
var assistant = this.controller.service.assistant; assistant.saveState(someState);
Note, however, that any data stored in the service assistant is only going to persist until the service exits, typically 30 seconds after the last active command completes. To truly persist data, you should use the db8 database.
How do I make my service pick up changes when I upload a new version?
If you change and re-install a service but it continues to behave as before, make sure the service is not still running during the re-installation. The framework provides every service with a _quit method you can call or you can check if it is still running with ps aux and kill it if it is.
How do I ensure that my setup is complete before a command is executed?
If your assistant's setup() method needs to perform asynchronous operations before any commands can be executed, you can return a future object from setup(), and the framework will ensure that any commands are not dispatched before the future completes.
MyAssistant.prototype.setup = function() { var f = DB.find(...); return };
How do I specify which commands are available on the public bus?
By default, all services listen on the private bus, but not on the public bus. Only HP webOS applications and services can send on the private bus. Third party services can only send on the public bus. To make a command available on the public bus, add "public": true to the command's entry in services.json.
How can my service get the calling application's ID?
In JavaScript, you can get the calling app ID using the following code:
var callingAppID = this.controller.message.applicationID().split(" ")[0];
How can my service get the calling service's ID?
In JavaScript, you can get the calling service ID using the following code:
var serviceID = this.controller.message.senderServiceName();