File I/O Service (Using Node.js Module)

About Code Sample

Using this sample, we will extend the capabilities of a web app by taking advantage of the File IO features of Node.js. This service contains methods for creating, writing, reading, and deleting a file.

Creating a Project

From webOS TV 4.0 SDK, we do not provide Moonstone templates of Enyo using Command Line Interface (CLI). 

  • For creating an Enyo-based app, refer to Enyo site.
  • For more information about supporting Enyo and Enact, see Enyo/Enact Guides.

If you use webOS TV 3.x SDK, you can create a new app project using the following CLI command.

ares-generate -t moonstone-[2014,2015,2016,2017] app

To use the moonstone template, specify the -t option. Depending on the webOS TV version, you should specify the appropriate name of the Enyo app. Also, we used "app" for app directory name for which any name can be used. 

Writing an App

We now have a skeleton project on which to build the File IO app and service from. Before you start writing an app, open appinfo.json and specify the app name at "id:" field. In this code sample, I set it to com.mycompany.fileioservice.

First, we will create the app to call the service with. Using your favorite editor, open the src/views/views.js file and replace the code with the code below.

The enyo.LunaService kind is provided by the enyo-webos library (which is included in the bootplate-moonstone template) and is what you use to call webOS services. By default, the enyo-webos library is commented out of the source/package.js. You should modify the package.js file to use the enyo-webos library.

// FileIOService Enyo kind
// An Enyo kind to make calls to our custom service easier
enyo.kind ({
    name: "FileIOService",
    kind: "enyo.LunaService",
    service: "luna://com.mycompany.app.fileioservice.service/"
});

// Our app's main view
enyo.kind({
	name: "myapp.MainView",
	kind: "moon.Panels",
	classes: "moon enyo-fit main-view",
	pattern:"activity",
	components: [
		{kind: "moon.Panel", title: "Read/Write with Node Service", components: [
            {
                name: "FileIOWriteService",
                kind: "FileIOService",
                method: "write",
                onComplete: "writeServiceResponse"
            },
            {
                name: "FileIOReadService",
                kind: "FileIOService",
                method: "read",
                onComplete: "readServiceResponse"
            },
            {
                name: "FileIODeleteService",
                kind: "FileIOService",
                method: "delete",
                onComplete: "deleteServiceResponse"
            },
            {
                name: "FileIOWatchService",
                kind: "FileIOService",
                method: "fileWatch",
                subscribe: true,
                onComplete: "watchServiceResponse"
            },
            {kind: 'moon.Scroller', fit: true, components: [
                {classes: "moon-button-sample-wrapper", components: [
                    {name: "CallWriteServiceButton", kind: "moon.Button", content: "Call 'write' service", ontap: "writeButtonTapped"},
                    {kind: "moon.Input", name:"nameInput",placeholder: "Enter your name"},
                    {kind: "moon.BodyText", name: "writeResult", allowHtml: true, content: "Button not pressed yet."}

                ]},
                {classes: "moon-button-sample-wrapper", components: [
                    {name: "CallReadServiceButton", kind: "moon.Button", content: "Call 'read' service", ontap: "readButtonTapped"},
                    {kind: "moon.BodyText", name: "readResult", allowHtml: true, content: "Button not pressed yet."}

                ]},
                {classes: "moon-button-sample-wrapper", components: [
                    {name: "CallDeleteServiceButton", kind: "moon.Button", content: "Call 'delete' service", ontap: "deleteButtonTapped"},
                    {kind: "moon.BodyText", name: "deleteResult", allowHtml: true, content: "Button not pressed yet."}

                ]},
                {classes: "moon-button-sample-wrapper", components: [
                    {kind: "moon.BodyText", name: "watchResult", allowHtml: true, content: ""}
                ]}
            ]}
        ]}
	],

    create: function() {
        this.inherited(arguments);
        // Start the FileIOWatchService when the app is created
        this.$.FileIOWatchService.send({});
        this.$.watchResult.setContent("Registered fileWatch service.")
    },

    writeButtonTapped: function(inSender, inEvent) {
        this.$.writeResult.setContent("Calling write service with : " + this.$.nameInput.getValue());
        this.$.FileIOWriteService.send({name:this.$.nameInput.getValue()});
    },

    readButtonTapped: function(inSender, inEvent) {
        this.$.readResult.setContent("Calling read service.");
        this.$.FileIOReadService.send({});
    },

    deleteButtonTapped: function(inSender, inEvent) {
        this.$.deleteResult.setContent("Calling delete service.");
        this.$.FileIODeleteService.send({});
    },

    writeServiceResponse: function(inSender, inResponse){
        if (inResponse.returnValue)
            this.$.writeResult.setContent("Service response: " + inResponse.response);
        else
            this.$.writeResult.setContent("Service error :" + inResponse.errorText);
    },

    readServiceResponse: function(inSender, inResponse){
        if (inResponse.returnValue)
            this.$.readResult.setContent("Service response: " + inResponse.response);
        else
            this.$.readResult.setContent("Service error: " + inResponse.errorText);
    },

    watchServiceResponse: function(inSender, inResponse){
        if (inResponse.returnValue) {
            this.count++;
            this.$.watchResult.setContent(this.count + ") fileWatch service response: " + inResponse.response + "
" + this.$.watchResult.getContent());
        }
        else
            this.$.watchResult.setContent("Service error");
    },

    deleteServiceResponse: function(inSender, inResponse){
        if (inResponse.returnValue)
            this.$.deleteResult.setContent("Service response: " + inResponse.response);
        else
            this.$.deleteResult.setContent("Service error: " + inResponse.errorText);
    }
});

Writing a Service

Now create a service to an app at a separate directory. Create a new folder called service. You can use any name for the service folder. A service is made up of three files, which we will add in order. 

First, create a new file called FileIOService.js containing the following code.

// File I/O Service
// A webOS service sample using Node fs library functions

var Service = require('webos-service');
var service = new Service("com.mycompany.app.fileioservice.service");

var fs = require('fs');

// Register the "write" service call which writes a text string to "message.txt"
service.register("write", function(message) {

    fs.writeFile('message.txt', 'Hello ' + message.payload.name, function (err) {
        if (err) {
            message.respond({
                returnValue: false,
                errorCode: 1,
                errorText: err.message
            });
        } else {
            message.respond({
                response: "Hello " + message.payload.name + " written to message.txt.",
                returnValue: true
            });
        }
    });
});

// Register the "read" service call which returns the contents of "message.txt"
service.register("read", function(message) {

    fs.readFile('message.txt', function (err, messageData) {

        if (err) {
            message.respond({
                returnValue: false,
                errorCode: 1,
                errorText: err.message
            });
        }
        else {
            message.respond({
                response: messageData.toString(),
                returnValue: true
            });
        }
    });
});

// Register the "fileWatch" service call which reports changes to "message.txt"
service.register("fileWatch", function(message) {

    fs.watch('message.txt', function (event, filename) {

        message.respond({
            response: event + " " + filename,
            returnValue: true
        });
    });
});

// Register the "delete" service call which deletes the "message.txt" file
service.register("delete", function(message) {

    // fs.unlink() is how Node deletes files
    fs.unlink('message.txt', function (err) {

        if (err) {
            message.respond({
                returnValue: false,
                errorCode: 1,
                errorText: err.message
            });
        } else {
            message.respond({
                response: "File message.txt deleted",
                returnValue: true
            });
        }
    });
});

In the same folder, create another file called services.json and insert the following code. This file defines our service and the methods available to be called on that service.

{
    "id": "com.mycompany.app.fileioservice.service",
    "description": "Sample file I/O service",
    "services": [
        {
            "name": "com.mycompany.app.fileioservice.service",
            "description": "Sample file I/O service",
            "commands": [
                {
                    "name": "write",
                    "description": "Write text with the parameter passed in to message.txt"
                },
                {
                    "name": "read",
                    "description": "Read text from message.txt"
                },
                {
                    "name": "delete",
                    "description": "Delete message.txt"
                },
                {
                    "name": "fileWatch",
                    "description": "Watch for changes to message.txt"
                }
            ]
        }
    ]
}

Finally, create a new file called package.json and insert the following code.

{
    "name": "com.mycompany.app.fileioservice.service",
    "main": "FileIOService.js"
}

Packaging the App

We are now ready to package our app and test it out on the target device. Create the package with SDK command line tools using 

ares-package app service

Installing and Launching the App

Install the package on the target device using

ares-install com.mycompany.app.fileioservice_0.0.1_all.ipk

Finally, run the app using

ares-launch com.mycompany.app.fileioservice

After the app is running, enter any text in the text box, then click CALL 'WRITE' SERVICE button. The app will call the service with the text entered as a parameter and return the response. Also, try CALL 'READ' SERVICE and CALL 'DELETE' SERVICE buttons.

fileio.png

Sample App Source Code

To download the source code for this sample app and service, click webOS-service-FileIO.zip.

Do's and Don'ts

  • DO start service method names with a lower-case letter.

  • DO set "errorText" and "errorCode" properties in the response only if an error occurs.

  • DON'T expect this to work in a browser.

Navigation