Skip to content
This repository has been archived by the owner on Jun 13, 2019. It is now read-only.

Commit

Permalink
JS API: Convert rep payload to/from JS object
Browse files Browse the repository at this point in the history
Fixes gh-28
  • Loading branch information
Gabriel Schulhof committed Nov 5, 2015
1 parent ee48cca commit a1b7bea
Show file tree
Hide file tree
Showing 5 changed files with 281 additions and 40 deletions.
52 changes: 26 additions & 26 deletions lib/OicClient.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var iotivity = require( "bindings" )( "iotivity" ),
_ = require( "lodash" ),
sidToString = require( "./utils" ).sidToString,
utils = require( "./utils" ),

// "acked" maps to OC_HIGH_QOS and anything else maps to OC_LOW_QOS
qosMap = {
Expand Down Expand Up @@ -163,7 +163,7 @@ _.extend( OicClient.prototype, {
doDiscovery( this, "findDevices", fulfill, reject,
iotivity.OC_RSRVD_DEVICE_URI, null,
_.bind( function findDevicesHandler( response ) {
var deviceId = sidToString( response.payload.sid );
var deviceId = utils.sidToString( response.payload.sid );

this._devices[ deviceId ] = {
address: response.devAddr,
Expand All @@ -189,7 +189,7 @@ _.extend( OicClient.prototype, {
var resourceCount = resources.length;

if ( resourceCount > 0 ) {
var deviceId = sidToString( resources[ 0 ].sid );
var deviceId = utils.sidToString( resources[ 0 ].sid );

if ( !this._devices[ deviceId ] ) {
this._devices[ deviceId ] = { address: devAddr };
Expand Down Expand Up @@ -262,37 +262,36 @@ _.extend( OicClient.prototype, {
},

createResource: function( resource ) {
return oneShotRequest( this, "createResource", resource, "OC_REST_POST", {
type: iotivity.OCPayloadType.PAYLOAD_TYPE_REPRESENTATION,
types: resource.resourceTypes || [],
interfaces: resource.interfaces || [],
values: resource.properties,
uri: resource.url
}, _.bind( function createResourceFromResponse() {
return this._maybeAddResource( resource );
}, this ) );
return oneShotRequest( this, "createResource", resource, "OC_REST_POST",
_.extend( utils.objectToPayload( resource.properties ), {
types: resource.resourceTypes || [],
interfaces: resource.interfaces || [],
uri: resource.url
} ),
_.bind( function createResourceFromResponse() {
return this._maybeAddResource( resource );
}, this ) );
},

retrieveResource: function( id ) {
var resource = this._resources[ id ];

return oneShotRequest( this, "retrieveResource", resource, "OC_REST_GET", null,
function retrieveResourceFromResponse( response ) {
_.extend( resource.properties, response.payload.values );
_.extend( resource.properties, utils.payloadToObject( response.payload.values ) );
return resource;
} );
},

updateResource: function( id, resource ) {
return oneShotRequest( this, "updateResource", this._resources[ id ], "OC_REST_PUT", {
type: iotivity.OCPayloadType.PAYLOAD_TYPE_REPRESENTATION,
values: resource.properties
}, function updateResourceFromResponse() {

// We know that when the update proves successful the remote resource will have the
// properties we sent to it
_.extend( this._resources[ id ].properties, resource.properties );
} );
return oneShotRequest( this, "updateResource", this._resources[ id ], "OC_REST_PUT",
utils.objectToPayload( resource.properties ),
function updateResourceFromResponse() {

// We know that when the update proves successful the remote resource will have the
// properties we sent to it
_.extend( this._resources[ id ].properties, resource.properties );
} );
},

deleteResource: function( id ) {
Expand Down Expand Up @@ -320,15 +319,16 @@ _.extend( OicClient.prototype, {
_.bind( function( handle, response ) {
if ( response.payload ) {
var oneProperty,
updatedResource = utils.payloadToObject( response.payload.values ),
event = new OicResourceChangedEvent();

event.resource = resource;
if ( response.payload.values ) {
for ( oneProperty in response.payload.values ) {
if ( response.payload.values[ oneProperty ] !==
if ( updatedResource ) {
for ( oneProperty in updatedResource ) {
if ( updatedResource[ oneProperty ] !==
event.resource.properties[ oneProperty ] ) {
event.resource.properties[ oneProperty ] =
response.payload.values[ oneProperty ];
updatedResource[ oneProperty ];
event.updatedPropertyNames.push( oneProperty );
}
}
Expand Down
18 changes: 7 additions & 11 deletions lib/OicServer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var iotivity = require( "bindings" )( "iotivity" ),
OicResource = require( "./OicResource" ),
utils = require( "./utils" ),
_ = require( "lodash" ),
OicServer = function( device ) {
if ( !this._isOicServer ) {
Expand All @@ -23,10 +24,7 @@ _.extend( OicRequestEvent.prototype, {
oicResponse = {
requestHandle: this.requestId,
resourceHandle: this.target,
payload: ( resource ? {
type: iotivity.OCPayloadType.PAYLOAD_TYPE_REPRESENTATION,
values: resource.properties
} : null ),
payload: ( resource ? utils.objectToPayload( resource.properties ) : null ),
sendVendorSpecificHeaderOptions: headerOptions,

resourceUri: ( iotivity.OCGetResourceUri( this.target ) || "" ),
Expand Down Expand Up @@ -128,14 +126,14 @@ _.extend( OicServer.prototype, {
} else if ( request.method === iotivity.OCMethod.OC_REST_POST ) {
oicReq.type = "create";

oicReq.res = _.extend( {}, request.payload.values );
oicReq.res = utils.payloadToObject( request.payload.values );

} else if ( request.method === iotivity.OCMethod.OC_REST_PUT ) {
if ( resource ) {
oicReq.type = "update";

//FIXME: Check if this is the right way of doing it.
oicReq.res = _.extend( {}, request.payload.values );
oicReq.res = utils.payloadToObject( request.payload.values );
oicReq.updatedPropertyNames = _.difference( resource, request.payload );
}
} else if ( request.method === iotivity.OCMethod.OC_REST_DELETE ) {
Expand Down Expand Up @@ -286,11 +284,9 @@ _.extend( OicServer.prototype, {

result = iotivity.OCNotifyListOfObservers( resource._handle,
this._interestedObservers,
{
type: iotivity.OCPayloadType.PAYLOAD_TYPE_REPRESENTATION,
uri: resource.url,
values: resource.properties
},
_.extend( utils.objectToPayload( resource.properties ), {
uri: resource.url
} ),
iotivity.OCQualityOfService[
( this._device.settings.connectionMode === "acked" ?
"OC_HIGH_QOS" : "OC_LOW_QOS" )
Expand Down
51 changes: 48 additions & 3 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,54 @@
var iotivity = require( "bindings" )( "iotivity" );
var iotivity = require( "bindings" )( "iotivity" ),
util = require( "util" );

function objectToPayload( theObject, visitedObjects ) {
var index, theValue,
payload = { type: iotivity.OCPayloadType.PAYLOAD_TYPE_REPRESENTATION, values: {} };

if ( visitedObjects === undefined ) {
visitedObjects = {};
}

for ( index in theObject ) {
theValue = theObject[ index ];
if ( typeof theValue === "object" ) {
if ( visitedObjects[ theValue ] ) {
throw new Error( "objectToPayload: Cannot handle circular object references" );
}
visitedObjects[ theValue ] = true;
if ( !util.isArray( theValue ) ) {
payload.values[ index ] = objectToPayload( theValue, visitedObjects );
continue;
}
}
payload.values[ index ] = theValue;
}

return payload;
}

function payloadToObject( values ) {
var index, theValue,
result = {};

for ( index in values ) {
theValue = values[ index ];
if ( typeof theValue === "object" && !util.isArray( theValue ) ) {
result[ index ] = payloadToObject( theValue.values );
} else {
result[ index ] = theValue;
}
}

return result;
}

module.exports = {
sidToString: function( sid ) {
var result,
idReceptacle = {};

// If we get an sid convert it to a string
// If we get a sid convert it to a string
if ( sid ) {
result = iotivity.OCConvertUuidToString( sid, idReceptacle );
if ( result === iotivity.OCRandomUuidResult.RAND_UUID_OK ) {
Expand All @@ -20,5 +63,7 @@ module.exports = {
}

throw new Error( "OicResource: Failed to generate UUID" );
}
},
objectToPayload: objectToPayload,
payloadToObject: payloadToObject
};
69 changes: 69 additions & 0 deletions tests/tests/API Complex Payload/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
var resource,
_ = require( "lodash" ),
async = require( "async" ),
uuid = process.argv[ 2 ],
device = require( "../../../index" )(),
testUtils = require( "../../assert-to-console" );

console.log( JSON.stringify( { assertionCount: 1 } ) );

async.series( [

function initStack( callback ) {
device.configure( {
role: "client",
connectionMode: "acked"
} ).then( callback, callback );
},

function discoverResource( callback ) {
Promise.all( [
new Promise( function( fulfill ) {
var resourceFound = function( event ) {
if ( event.resource.url === "/a/" + uuid ) {
resource = event.resource;
fulfill();
device.client.removeEventListener( "resourcefound", resourceFound );
}
};
device.client.addEventListener( "resourcefound", resourceFound );
} ),
device.client.findResources()
] ).then(
function() {
callback();
}, callback );
},

function performRetrieve( callback ) {
device.client.retrieveResource( resource.id ).then(
function( resource ) {
testUtils.assert( "deepEqual", resource.properties, {
primitiveValue: 42,
objectValue: {
childValue: 91
},
arrayValue: [ 19, 23, 7 ]
}, "Client: Retrieved properties are correct" );
callback();
},
callback );
},

function performUpdate( callback ) {
device.client.updateResource( resource.id, _.extend( resource, {
properties: {
putValue: "A string",
anotherPutValue: 23.7,
childValues: {
putChildValue: false,
putChildArray: [ [ 2, 3, 5 ], [ 9, 11, 17 ] ]
}
}
} ) ).then( callback, callback );
}
], function( error ) {
if ( error ) {
testUtils.die( "Client: " + error.message + ", result: " + error.result );
}
} );
Loading

0 comments on commit a1b7bea

Please sign in to comment.