-
Notifications
You must be signed in to change notification settings - Fork 70
style: add comments #588
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
style: add comments #588
Changes from 6 commits
09bdfd1
2d2e0b0
895ab9e
b251279
c4627d4
6114097
23fd2dd
38085ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,7 +49,7 @@ FullSignalK.prototype.retrieve = function() { | |
|
|
||
| FullSignalK.prototype.addDelta = function(delta) { | ||
| this.emit('delta', delta); | ||
| var context = findContext(this.root, delta.context); | ||
| var context = findContextAndUpdateIdentity(this.root, delta.context); | ||
| this.addUpdates(context, delta.context, delta.updates); | ||
| this.updateLastModified(delta.context); | ||
| }; | ||
|
|
@@ -76,66 +76,114 @@ FullSignalK.prototype.deleteContext = function(contextKey) { | |
| } | ||
| } | ||
|
|
||
| function findContext(root, contextPath) { | ||
| var context = _.get(root, contextPath); | ||
| /** | ||
| * Both returns the context for a contextPath and update the context with the | ||
| * appropriate key. | ||
| * | ||
| * contextPath is something like vessels.urn:mrn:imo:mmsi:276810000 or | ||
| * vessels.foo. Signalk tracks multiple vessels, each with their own context. | ||
| * This method returns the context for the vessel. It additionally adds either | ||
| * the mmsi or url to the context to allow for easier access. | ||
| * | ||
| * For example: | ||
| * contextPath=vessels.urn:mrn:imo:mmsi:276810000 | ||
| * before context={} | ||
| * after context={"mmsi":"276810000"} | ||
| * | ||
| * @param {Object} root the signalk store | ||
| * @param {string} contextPath the path to the desired vessel | ||
| * @return {Object} the context for the desired vessel from the signalk store | ||
| */ | ||
| function findContextAndUpdateIdentity(root, contextPath) { | ||
| // get the context and create an empty context if it doesn't exist | ||
| let context = _.get(root, contextPath); | ||
| if(!context) { | ||
| context = {}; | ||
| _.set(root, contextPath, context); | ||
| } | ||
| var identity = contextPath.split('.')[1]; | ||
|
|
||
| // contextPath is something like "vessels.foo" or "vessels.urn:mrn:..." | ||
| // if we have a full context path, add its contents to the context, so that | ||
| // we can more easily access the mmsi or url | ||
| const identity = contextPath.split('.')[1]; | ||
| if(!identity) { | ||
| return undefined; | ||
| } | ||
| signalkSchema.fillIdentityField(context, identity); | ||
|
|
||
| return context; | ||
| } | ||
|
|
||
| FullSignalK.prototype.addUpdates = function(context, contextPath, updates) { | ||
| var len = updates.length; | ||
| for (var i = 0; i < len; ++i) { | ||
| this.addUpdate(context, contextPath, updates[i]); | ||
| } | ||
| let that = this; | ||
| updates.forEach(function(update) { | ||
| that.addUpdate(context, contextPath, update); | ||
| }); | ||
| } | ||
|
|
||
| FullSignalK.prototype.addUpdate = function(context, contextPath, update) { | ||
| // first, update the sources in the full context | ||
| if (typeof update.source != 'undefined') { | ||
| this.updateSource(context, update.source, update.timestamp); | ||
| } else if(typeof update['$source'] != 'undefined') { | ||
| this.updateDollarSource(context, update['$source'], update.timestamp); | ||
| } else { | ||
| console.error("No source in delta update:" + JSON.stringify(update)); | ||
| } | ||
|
|
||
| // second, update the values | ||
| addValues(context, contextPath, update.source || update['$source'], update.timestamp, update.values); | ||
| } | ||
|
|
||
| /** | ||
| * Update the $source in the context. | ||
| * | ||
| * $source is a pointer to the sources field in the context. See doc/data_model.html | ||
| * | ||
| * @param {Object} context | ||
| * @param {string} dollarSource a path directive pointing the real source | ||
| * @param {string} timestamp | ||
| */ | ||
| FullSignalK.prototype.updateDollarSource = function(context, dollarSource, timestamp) { | ||
| const parts = dollarSource.split('.') | ||
| // descend into the sources element of the context, creating elements as needed | ||
| parts.reduce((cursor, part) => { | ||
| if(typeof cursor[part] === 'undefined') { | ||
| return cursor[part] = {} | ||
| } | ||
| return cursor[part] | ||
| }, this.sources) | ||
|
|
||
| // Uh, shouldn't something be done with the result of the reduce? What if | ||
| // the pointed to value isn't found? | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You already documented what this does: creating elements as needed, using reduce cursor as a temp variable.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm still confused. All this does is create elements, it doesn't actually update anything. Notice that context and timestamp aren't referenced in the body of the method. (Which means my comment is wrong, it's descending into this.sources, not context.)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, so
|
||
| } | ||
|
|
||
| /** | ||
| * Update the source in the context. | ||
| * | ||
| * This is the top level source element in the context, not a source embedded in the tree | ||
| * | ||
| * @param {Object} context | ||
| * @param {string} dollarSource a path directive pointing the real source | ||
| * @param {string} timestamp | ||
| */ | ||
| FullSignalK.prototype.updateSource = function(context, source, timestamp) { | ||
| // create the source, if this is the first time we've seen it | ||
| if(!this.sources[source.label]) { | ||
| this.sources[source.label] = {}; | ||
| this.sources[source.label].label = source.label; | ||
| this.sources[source.label].type = source.type; | ||
| } | ||
|
|
||
| // handle various different source types | ||
| if(source.type === 'NMEA2000' || source.src) { | ||
| handleNmea2000Source(this.sources[source.label], source, timestamp); | ||
| return | ||
| } | ||
|
|
||
| if(source.type === 'NMEA0183' || source.sentence) { | ||
| } else if(source.type === 'NMEA0183' || source.sentence) { | ||
| handleNmea0183Source(this.sources[source.label], source, timestamp); | ||
| return | ||
| } else { | ||
| handleOtherSource(this.sources[source.label], source, timestamp); | ||
| } | ||
|
|
||
| handleOtherSource(this.sources[source.label], source, timestamp); | ||
| } | ||
|
|
||
| function handleNmea2000Source(labelSource, source, timestamp) { | ||
|
|
@@ -177,72 +225,100 @@ function handleOtherSource(sourceLeaf, source, timestamp) { | |
| } | ||
|
|
||
| function addValues(context, contextPath, source, timestamp, pathValues) { | ||
| var len = pathValues.length; | ||
| for (var i = 0; i < len; ++i) { | ||
| addValue(context, contextPath, source, timestamp, pathValues[i]); | ||
| } | ||
| pathValues.forEach(function(pathValue) { | ||
c33howard marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| addValue(context, contextPath, source, timestamp, pathValue); | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Adds a value to the context. | ||
| * | ||
| * @param {Object} context | ||
| * @param {string} contextPath ex: vessels.urn:mrn:imo:mmsi:200000000 | ||
| * @param {Object} source description of where the data came from ex: {"label":"aLabel","type":"NMEA2000","pgn":130312,"src":"41","instance":"5"} | ||
| * @param {string} timestamp time of the data point (in ISO format) | ||
| * @param {Object} pathValue the path and value ex: {"path":"environment.inside.engineRoom.temperature","value":70} | ||
| */ | ||
| function addValue(context, contextPath, source, timestamp, pathValue) { | ||
| // guardian for no path or value | ||
| if (_.isUndefined(pathValue.path) || _.isUndefined(pathValue.value)) { | ||
| console.error("Illegal value in delta:" + JSON.stringify(pathValue)); | ||
| return; | ||
| } | ||
| var valueLeaf; | ||
| if(pathValue.path.length === 0) { | ||
| // if the added path is the root, just do a merge with the context and we're done | ||
| if (pathValue.path.length === 0) { | ||
| _.merge(context, pathValue.value) | ||
| return | ||
| } else { | ||
| const splitPath = pathValue.path.split('.'); | ||
| valueLeaf = splitPath.reduce(function(previous, pathPart, i) { | ||
| if (!previous[pathPart]) { | ||
| previous[pathPart] = {}; | ||
| } | ||
| if ( i === splitPath.length-1 && typeof previous[pathPart].value === 'undefined' ) { | ||
| let meta = signalkSchema.getMetadata(contextPath + '.' + pathValue.path) | ||
| if (meta ) { | ||
| //ignore properties from keyswithmetadata.json | ||
| meta = JSON.parse(JSON.stringify(meta)) | ||
| delete meta.properties | ||
|
|
||
| _.assign(meta, previous[pathPart].meta) | ||
| previous[pathPart].meta = meta | ||
| } | ||
| } | ||
| return previous[pathPart]; | ||
| }, context); | ||
| } | ||
|
|
||
| if(valueLeaf.values) { //multiple values already | ||
| var sourceId = getId(source); | ||
| if(!valueLeaf.values[sourceId]) { | ||
| const splitPath = pathValue.path.split('.'); | ||
| // traverse down the context to find the object that this path references, | ||
| // possibly creating elements as we go | ||
| let valueLeaf = splitPath.reduce(function(previous, pathPart, i) { | ||
| // if required, create a new nested object for this path component | ||
| if (!previous[pathPart]) { | ||
| previous[pathPart] = {}; | ||
| } | ||
|
|
||
| // if we're at the last path component and we don't have a value yet, then | ||
| // determine if we need to add the meta key to describe the data type for | ||
| // this path | ||
| if (i === splitPath.length-1 && typeof previous[pathPart].value === 'undefined') { | ||
| let meta = signalkSchema.getMetadata(contextPath + '.' + pathValue.path) | ||
| if (meta) { | ||
| //ignore properties from keyswithmetadata.json | ||
| meta = JSON.parse(JSON.stringify(meta)) | ||
| delete meta.properties | ||
|
|
||
| _.assign(meta, previous[pathPart].meta) | ||
| previous[pathPart].meta = meta | ||
| } | ||
| } | ||
|
|
||
| // return the object as we traverse downwards | ||
| return previous[pathPart]; | ||
| }, context); | ||
|
|
||
| // if there are already multiple values, then add the new value as a nested | ||
| // element indexed by the source (see doc/data_model_multiple_values.html) | ||
| if (valueLeaf.values) { | ||
| const sourceId = getId(source); | ||
|
|
||
| // add the new child node, if this is the first time we've observed this | ||
| // value from this source | ||
| if (!valueLeaf.values[sourceId]) { | ||
| valueLeaf.values[sourceId] = {}; | ||
| } | ||
|
|
||
| // do the assignment | ||
| assignValueToLeaf(pathValue.value, valueLeaf.values[sourceId]); | ||
| valueLeaf.values[sourceId].timestamp = timestamp; | ||
| setMessage(valueLeaf.values[sourceId], source); | ||
| } else if(typeof valueLeaf.value != "undefined" && valueLeaf['$source'] != getId(source)) { | ||
| // first multiple value | ||
|
|
||
| var sourceId = valueLeaf['$source']; | ||
| var tmp = {}; | ||
| } | ||
| // special case for when we've got an existing source and this is the first | ||
| // time we've seen this path from a new source | ||
| else if(typeof valueLeaf.value != "undefined" && valueLeaf['$source'] != getId(source)) { | ||
| // first move the existing value to a nested element inside values | ||
| let sourceId = valueLeaf['$source']; | ||
| let tmp = {}; | ||
| copyLeafValueToLeaf(valueLeaf, tmp); | ||
| valueLeaf.values = {}; | ||
| valueLeaf.values[sourceId] = tmp; | ||
| valueLeaf.values[sourceId].timestamp = valueLeaf.timestamp; | ||
|
|
||
| // second, add the new value | ||
| sourceId = getId(source); | ||
| valueLeaf.values[sourceId] = {}; | ||
| assignValueToLeaf(pathValue.value, valueLeaf.values[sourceId]); | ||
| valueLeaf.values[sourceId].timestamp = timestamp; | ||
| setMessage(valueLeaf.values[sourceId], source); | ||
| } | ||
|
|
||
| // do the final assignment into the context | ||
| assignValueToLeaf(pathValue.value, valueLeaf); | ||
| if(pathValue.path.length != 0) { | ||
| valueLeaf['$source'] = getId(source); | ||
| valueLeaf.timestamp = timestamp; | ||
| setMessage(valueLeaf, source); | ||
| } | ||
| valueLeaf['$source'] = getId(source); | ||
| valueLeaf.timestamp = timestamp; | ||
| setMessage(valueLeaf, source); | ||
| } | ||
|
|
||
| function copyLeafValueToLeaf(fromLeaf, toLeaf) { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.