Security News
New Python Packaging Proposal Aims to Solve Phantom Dependency Problem with SBOMs
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
The City of Things client library will help you to connect to the City of Things backend. It uses the Web Linking RFC 5988 and interprets the Link header for you. This way you can let the library follow the next/prev/last pages for you.
npm install cot-lib --save
This library is written in Typescript before being transpiled to Javascript, hence the type information is embedded. (Credentials are optional)
import { CotClient, LocationsClient, SourcesClient, Util } from 'cot-lib';
let credentials = {username: "user", password: "pass"};
let client = new CotClient('http://my-cot-backend.eu', credentials);
let hash = Util.encodeAsGeohash(31.123456,15.321654);
This library can also be used as a regular javascript library. (Credentials are optional)
var CotClient = require('cot-lib').CotClient;
var Util = require('cot-lib').Util;
var credentials = {username: "user", password: "pass"};
var client = new CotClient('http://my-cot-backend.eu', credentials);
var hash = Util.encodeAsGeohash(31.123456,15.321654);
or
var cot = require('cot-lib');
var credentials = {username: "user", password: "pass"};
var client = new cot.CotClient('http://my-cot-backend.eu', credentials);
var hash = cot.Util.encodeAsGeohash(31.123456,15.321654);
You start by creating a CotClient object. A CotClient object allows you to request the basic API functions. It needs a reference to the base url of the API.
Basic Auth credentials can be given as an extra optional argument.
import { CotClient } from 'cot-lib';
let credentials = {username: "user", password: "pass"};
let cotClient = new CotClient('http://my-cot-backend.eu', credentials);
A SourcesClient object allows you to pre-define all the sourceIds you want to request data from simultaneously. The best way to create one, is from an existing CotClient.
import { CotClient, SourcesClient } from 'cot-lib';
let cotClient = new CotClient('http://my-cot-backend.eu', {username: "user", password:"pass"});
let sourcesClient = cotClient.createSourcesClient('sourceId1', 'sourceId2', 'sourceId3');
A LocationsClient object allows you to pre-define all the geohashes you want to request data from simultaneously. Because of the sheer amount of data, you are required to already filter on the Type you are interested in. The best way to create one, is from an existing CotClient.
import { CotClient, LocationsClient } from 'cot-lib';
let cotClient = new CotClient('http://my-cot-backend.eu', {username: "user", password:"pass"});
let locationsClient = cotClient.createLocationsClient('u15kk', 'u15kh', 'u15ke');
This API makes heavy use of ReactiveX Observables. They are a very modern way to do asynchronous communication. When calling subscribe(...)
on an Observable, the Observable is activated and starts its work. It will asynchronously notify its different handlers. The first handler - typically called next - can be notified multiple times, everytime there is new data available, the second one handles errors and the last one is called when the Observable stream has completed its work.
The simplest way to use them is as follows. Given a method getMyData()
that returns an Observable<MyData>
type. This is how you handle it:
Typescript
client.getMyData().subscribe(
nextData => {
// handle nextData as its coming in, this handler will be called on every update with new data
},
error => {
// do something when an error occurs
},
() => {
// this handler will be called when the data streaming is complete and there is no more incoming data
}
);
Javascript
client.getMyData().subscribe(
function(nextData) {
// handle nextData as its coming in, this handler will be called on every update with new data
},
function(error) {
// do something when an error occurs
},
function() {
// this handler will be called when the data streaming is complete and there is no more incoming data
}
);
There are many more things you can do with Observables, for a more comprehensive guide we refer to the ReactiveX introduction website and the RxJs github page with its excellent Readme.
An Observable allows you to call the toPromise()
method on it, after which it can be handled as a normal Promise with a then(...)
method. Be aware though that to first argument callback of the then(...)
method will only be called with the very last next update of the observable. So this will not always behave as you would expect.
However we remediated this with two Util methods collectOne(...)
and collectMultiple(...)
that are further explained in the API section. They allow for usage that is more in line with the Promises workflow.
The API uses a couple of Types that it returns.
A Type object describes sources of the same type. It has an id to uniquely identify it. It has a finalizationDelay that determines the delay until the data is considered unchanged and indefinitely cacheable, it has a preferredGranularity that determines the default size of returned TemperalPage brackets for Sources of this Type. At last is has a schema that defines the structure and meaning of the fields in the Source data.
{
"id": "bpost.car",
"finalizationDelay": 0,
"preferredGranularity": "HOURLY",
"schema": {
"co2": "IntNumber (The co2 level.)"
}
}
A Source represents a sensor, actuator or data producer of some sort. It has an id to uniquely identify it. It has a name which is a human readable label for this Source. At last it has a typeRefs field which contains a set of typeId strings that define the Types this Source belongs to.
{
"id": "Car1",
"name": "Bpost Mockup Car 1",
"typeRefs": [
"bpost.car"
]
}
A TemporalPage object is a bucket (like a page in a pageing mechanism, but spread by time instead of amount). This object contains the parsed Link header values, so they can easily be accessed.
{
"data": {TemporalPageData},
"link": {TemporalPageLink}
}
A TemporalPageData object is just the data part of a TemporalPage. It is used when the TemporalPageLink field is no longer relevant in the returned data of a TemporalPage object. (e.g. when requesting data of an interval of multiple pages). (note that next, prev and last fields are optional and not always present).
{
"name": "Car1" or ["Car1", "Car2"],
"columns": ["timestamp","co2","temperature"],
"values": [
[1483201200, 430, 297.15],
[1483201202, 432, 297.13],
[1483201212, 433, 300.01],
[1483201301, 427, 301.14],
[1483201302, 419, 298.06],
[1483201331, 418, 299.48],
[1483201340, 424, 299.82],
]
}
A TemporalPageLink object contains the parsed Link header values relevant for the City of Things client to request follow up requests. It parses the Link header according to the RFC 5988 specification.
{
"self": "/sources/Car1/events/20161231/16?from=1483201200",
"next": "/sources/Car1/events/20161231/17",
"prev": "/sources/Car1/events/20161231/16?to=1483201200",
"last": "/sources/Car1/events/20161231/20?to=1483215300",
}
Constructor, call as new CotClient('http://my-cot.backend.eu', {username: "user", password: "pass"})
. This will construct a new CotClient object to work with.
Returns an Observable containing an array with all available Type objects.
Returns an Observable containing Type information of the Type with the given typeId.
Returns an Observable containing an array of Source objects belonging to the Type with the given typeId.
Returns an Observable containing an array of all Source objects currently available.
Returns an Observable containing the Source object with the given sourceId.
Continuously poll for data from a Source defined by a given sourcId. The period field is the time in milliseconds in between polling for new values. The optional from argument is the UNIX UTC timestamp from which to start polling. If not present the last data will be polled.
Returns an Observable containing a TemporalPageData object with data from a Source defined by a given sourceId. The TemporalPageData contains the aggregated interval. This method automatically calls the necessary subsequent requests. On every response, the Observable calls its next handler with the newly received data. It is up to the developer to listen for this incoming data and update the already received data.
If you want to wait and only call a handler when all data has come in, use the Util.collectOne(...)
method on this Observable. More information on this method can be found at the end of this API section.
The arguments from and to are UNIX (UTC) timestamps.
Continuously poll for data in a location, defined by the geohash and belonging to a given typeId. The period field is the time in milliseconds in between polling for new values. The optional from argument is the UNIX UTC timestamp from which to start polling. If not present the last data will be polled.
Returns an Observable containing a TemporalPageData object with data from Sources belonging to a given typeId, within the given geohash. The TemporalPageData contains the aggregated interval. This method automatically calls the necessary subsequent requests. On every response, the Observable calls its next handler with the newly received data.
It is up to the developer to listen for this incoming data and update the already received data!
If you want to wait and only call a handler when all data has come in, use the Util.collectOne(...)
method on this Observable. More information on this method can be found at the end of this API section.
The arguments from and to are UNIX (UTC) timestamps.
A convenience method to create a new SourcesClient object, by reusing the host and credential settings from the CotClient.
A convenience method to create a new LocationsClient object, by reusing the host and credential settings from the CotClient.
Recommended: use cotClient.createSourcesClient(...sourceIds)
Constructor, call as new SourcesClient('http://my-cot.backend.eu', null, 'sourceId1','sourceId2', 'sourceId3')
. This will construct a new sourcesClient to work with. (The axiosInstance is an instance of the internally used axios library to perform requests, if null the default is used).
Poll for data of each Source defined in the client. The period field is the time in milliseconds in between polling for new values. Every update will immediatly be sent through, hence it is mandatory to check the incoming data for the key. The optional from argument is the UNIX UTC timestamp from which to start polling. If not present the last data will be polled.
Returns an Observable containing a TemporalPageData object with data from all Source defined by the registered sourceIds of this sourcesClient. The TemporalPageData contains the aggregated interval. This method automatically calls the necessary subsequent requests. On every response, the Observable calls its next handler with the newly received data.
It is up to the developer to listen for this incoming data and update the already received data!
If you want to wait and only call a handler when all data has come in, use the Util.collectMany(...)
method on this Observable. More information on this method can be found at the end of this API section.
The arguments from and to are UNIX (UTC) timestamps.
Recommended: use cotClient.createLocationsClient(...geohashes)
Constructor, call as new LocationsClient('http://my-cot.backend.eu', null, 'geohash1','geohash2', 'geohash3')
. This will construct a new LocationsClient to work with. (The axiosInstance is an instance of the internally used axios library to perform requests, if null the default is used).
Poll for data from each location, defined in the client by geohashes, filtered by the Type given by the typeId arugment. The period field is the time in milliseconds in between polling for new values. Every update will immediatly be sent through, hence it is mandatory to check the incoming data for the key. The optional from argument is the UNIX UTC timestamp from which to start polling. If not present the last data will be polled.
Returns an Observable containing a TemporalPageData object with data from all locations defined by the registered geohashes of this locationsClient. Because of the sheer amount of data, a typeId must be given to limit the results to Sources from this Type. The TemporalPageData contains the aggregated interval. This method automatically calls the necessary subsequent requests. On every response, the Observable calls its next handler with the newly received data.
It is up to the developer to listen for this incoming data and update the already received data!
If you want to wait and only call a handler when all data has come in, use the Util.collectMany(...)
method on this Observable. More information on this method can be found at the end of this API section.
The arguments from and to are UNIX (UTC) timestamps.
The Util class contains some static methods that can be helpful when working with the City of Things cilent library.
Returns the unix (UTC) timestamp for the given date parameters. The arguments are considered to be in UTC time.
Argument | Optional | Description |
---|---|---|
year | no | Four digit number |
month | no | The month in the year (1-12) |
day | yes | The day of the month (1-31) |
hours | yes | The hour of the day (0-23) |
minutes | yes | The minute of the day (0-59) |
seconds | yes | The seconds of the day (0-59) |
milliseconds | yes | The milliseconds of the day (0-999) |
Encodes a latitude-longitude point as a geohash with the given precision.
Argument | Description |
---|---|
lat | Latitude of point |
lng | Longitude of point |
precision | Character length of geohash (defaults to 9) |
Decode a given geohash as a latitude-longitude point.
This utility method will subscribe to an Observable<TemporalPageData> and collect the results that are sent through on each update of the next handler. Once it is complete, the callback handler will be called with the complete collected data as an argument. An optional error handler is called with the Error object, if one occurs.
Note: Use this in conjunction with CotClient getDataInterval
methods.
import { CotClient, Util } from 'cot-lib';
testMethod() {
let client = new CotClient('http://my-cot-endpoint.eu');
let from = Util.timestampOf(2017, 3, 1, 0, 0, 0, 0);
let to = Util.timestampOf(2017, 4, 1, 0, 0, 0, 0);
let observable = client.getDataIntervalIn('u15kk', 'bpost.cars', from, to);
Util.collectOne(observable, temporalPageData => {
console.log(temporalPageData);
});
}
This utility method will subscribe to an Observable<TemporalPageData> and collect the results that are sent through on each update of the next handler for each endpoint. It will send these updates as an array of TemporalPageData objects. Once it is complete, the callback handler will be called with the complete collected data as an argument, this is again an array of TemporalPageData objects, as many as there are registered sourceIds for a SourcesClient or geohashes for a LocationsClient. An optional error handler is called with the Error object, if one occurs.
Note: Use this in conjunction with SourcesClient and LocationsClient getDataInterval
methods.
import { SourcesClient, Util } from 'cot-lib';
testMethod() {
let sclient = new SourcesClient('http://my-cot-endpoint.eu', 'Car1', 'Car2', 'Car3', 'Car4');
let from = Util.timestampOf(2017, 3, 1, 0, 0, 0, 0);
let to = Util.timestampOf(2017, 4, 1, 0, 0, 0, 0);
let observable = sclient.getDataInterval(from, to);
Util.collectMany(observable, collectedDataArray => {
collectedDataArray.forEach(temporalPageData => {
console.log(temporalPageData);
});
});
}
FAQs
Easily consume the City of Things platform data
The npm package cot-lib receives a total of 2 weekly downloads. As such, cot-lib popularity was classified as not popular.
We found that cot-lib demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
Security News
Socket CEO Feross Aboukhadijeh discusses open source security challenges, including zero-day attacks and supply chain risks, on the Cyber Security Council podcast.
Security News
Research
Socket researchers uncover how threat actors weaponize Out-of-Band Application Security Testing (OAST) techniques across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data.