This software is part of a larger suite of microservices designed to remotely manage digital fabrication equipment in a loosely coupled and distributed environment. More specifically, the software in this repo implements the Cloud Hub; namely the central node of the NEWTON Fab Labs spoke-hub architecture. The Cloud Hub is in charge to keep and update a registry of all the connected Fab Labs and to route the incoming fabrication requests from the connected clients to that Fab Lab that is geographically closer to the Fab Lab that is geographically closer to the issuer of the request.
This software has been developed by Gianluca Cornetta and Javier Mateos within NEWTON project. NEWTON is a large scale Integrated Action, started in March 2016 and scheduled to end in summer 2019, funded by the European Commission under the Horizon 2020 Researh and Innovation Programme with grant agreement n. 688503.
- Preliminary steps
- Software architecture
- Documentation and developer support
- Websites
- Contribution guidelines
- License
Before installing the software you have to make sure that you comply with the hardware and software requirements specified in the next two sections.
We recommend installing this software on an AWS m4.large EC2 instance or equivalent with at least 80GB Hard disk.
The Machine wrapper software requires that you previously install on your system the following software packages:
- Node.js >= v8.x
- npm >= v6.x
- Mongo DB v3.x
We have not tested the software with Mongo DB latest version; however it should work without any problem if you update mongoose to the last version in the `package.json` file with the project dependencies.
To install the Machine Wrapper module go through the following steps:
- download or clone this repo,
- run
npm install
in the installation folder, - run
npm run start
to start the server.
We have not tested the software with Mongo DB latest version; however it should work without any problem if you update mongoose to the last version in the `package.json` file with the project dependencies
To install the Machine Wrapper module go through the following steps:
- download or clone this repo,
- run
npm install
in the installation folder, - run
npm run start
to start the server.
The server will listen to port 3000.
The Cloud Hub business software implements the application logic end exposes the main services through a set of REST APIs. Fig. 1 depicts the architecture of the Cloud Hub software. The application business logic is implemented on top of middleware functions that implement: 1. The API server logic. 2. The database wrapping logic. 3. The microservice interface (to manage communications with the Service Registry and the Service Monitor modules). The persitence layer is built on top of MongoDB NoSQL data base.
Fig. 1 - Cloud Hub Software Architecture.The Cloud Hub APIs expose the underlying Fab Lab network as software service over the internet and represent the interface between the Fab Lab cloud and third-party applications and platforms allowing the possibility to seamlessly implement complex multi-cloud architecture that communicates and synchronize through APIs.
The Cloud Hub APIs provide software methods that can be exploited to remotely control the whole Fab Lab network using custom interfaces. In our specific case, we expose a single object that represents a snapshot of the Fab Lab status and of the available fabrication resources. Table 1 displays the resource URI and the implemented HTTP verbs for some of the APIs.
Resource | GET | POST | PUT | DELETE |
---|---|---|---|---|
/fablab/1234 | Shows the Fab Lab with the specified id if it exists | Error 400 (Bad Request) |
Error 400 (Bad Request) |
Error 400 (Bad Request) |
/fablabs | Show all the Fab Labs | Error 400 (Bad Request) |
Error 400 (Bad Request) |
Error 400 (Bad Request) |
/fablabs/jobs?machine=laser%20cutter&process=cut&lat=xx&long=yy | Error 400 (Bad Request) |
Submit a job to the Fab Lab closest to the specified coordinates | Error 400 (Bad Request) |
Error 400 (Bad Request) |
/fablabs/1234?job=1235 | Shows the status of the specified job if it exists; otherwise displays an error (Not found) | Error 400 (Bad Request) |
Error 400 (Bad Request) |
Delete a job if it exists; otherwise displays an error (Not found |
The POST method supports multipart/form-data to upload the design file to the Cloud Hub server.
A Fab lab is modelled by a JSON object that includes the following information:
- The Fab Lab contact information, geographic position and service URL.
- The machines information (including type, vendor, status and queued jobs).
- The materials information (including type and quantity).
The Fab Lab JSON object is the following:
"fablab": {
"id": "The Fab Lab unique identifier",
"name": "The Fab Lab name",
"web": "The Fab Lab web page url",
"api": "The API endpoint of the Fab Lab gateway",
"capacity": "% of the total Fab Lab fabrication capacity",
"address": {
"street": "The Fab Lab address",
"postCode": "The postcode",
"state": "The state or province",
"country": "The country",
"countryCode": "State or country code"
},
"coordinates": {
"latitude": "The Fab Lab latitude",
"longitude": "The Fab Lab longitude"
},
"contact": {
"name": "Name of the contact person",
"charge": "Charge of the contact person",
"email": "Email of the contact person"
},
"openingDays": [
{
"day": "Day of the week",
"from": "Opening hour",
"to": "Closing hour"
}
],
"equipment": [
{
"id": "The machine connection identifier",
"type": "Machine type",
"vendor": "Machine vendor",
"name": "Machine name",
"status": "Machine status",
"jobsQueued": "The number of queued jobs"
}
],
"materials": [
{
"type": "Material type",
"quantity": "% of available stock"
}
]
},
"jobs": {
"running": "Number of total running jobs",
"queued": "Number of total queued jobs",
"details": [
{
"machineId": "The machine connection id",
"type": "Machine type",
"vendor": "Vendor",
"jobs": [
{
"id": "Job id",
"status": "Job status",
"process": "Type of fabrication process",
"queue": "Local or global queue",
"queuePosition": "Position in queue"
}
]
}
]
}
}
The object is self-explanatory. Observe that the machine status may assume the following values: undefined, off, idle, busy. Conversely, the job status may assume the following values: running, completed, pending, approved, cancelled (either by the user or the Fab Lab administrator). The supported materials are: vinyl, wood, mylar, copper, cardboard. The supported machine types are: vinyl cutter, laser cutter, 3D printer, milling machine. The supported fabrication processes are: cut, halftone, wax. The process field is set to null for jobs sent to 3D printers. Finally, the supported vendors are: epilog, prusa, gcc, roland.
API versioning is not mandatory for Cloud Hub APIs.
APIs only support JSON format; however, they are designed to implement content negotiation and to support more formats in the future. Content negotiation is implemented using a query parameter in the resource URI rather than using the accept field in the incoming HTML request, namely:
/fablabs/1234/?format=json
?format=json
is the default value, so if no format is specified in the query parameter of the resource URI, server response will be in JSON.
Partial response allows to give the developers just the information they need from the API. For example:
/fablabs/1234?fields=id,name,api
displays just the id, the name and the api fields of the Fab Lab JSON object.
Pagination allows to return just part of the database content using the limit and the offset parameters. For example:
/fablabs?limit=20&offset=30
gets 20 database records from 30 to 50. The server response should also include metadata to specify the total number of records available. If no limit and offset parameters are specified the default query values are limit=10&offset=0
.
Both simple and scoped searches are supported using the verb q. Global searches across resources are not supported since our implementation has a single resource (i.e. the Fab Lab object). A simple search can be performed as follows:
/fablabs?q=laser%20cutter+epilog
The previous query returns all the fab labs that have an epilog laser cutter. To perform a scoped search, one can use the following query:
/fablabs/12345/jobs?q=laser%20cutter+queue
The previous query returns all the queued jobs on all the laser cutters of the fab lab whose id is 12345. The search results can be explicitly formatted using a parameter in the query string. If this parameter is omitted, the server will return a response in the default format (i.e. JSON). Observe that this feature is implemented only for future improvements since the only format supported by the API server is JSON. To specify the output format, use the following URI:
/fablabs?format=json&q=laser%20cutter+epilog
Finally, observe that the ‘+’ character in the resource URI is automatically converted into a blank space (code %20
) when the URI is parsed by the server middleware. In order to override this behaviour and to allow the expected operation of the business logic on the server side, the ‘+’ character is encoded (code %2B
); thus, for example, the previous resource URI is encoded as:
/fablabs?format=json&q=laser%20cutter%2Bepilog
The API error codes will match HTTP codes. The following cases are managed:
- Everything worked (success): 200–OK.
- The application did something wrong (client error): 400–Bad Request.
- The API did something wrong (server error): 500–Internal Server Error.
In the case of client error, the server will return in the response a JSON object with error details and hints to correct it. The message has the following format:
{“message”: “verbose error explanation”, “errorCode”: 12345, “infoLink”: “link to the developer suppor page”}
The object must redirect to a web page with hints to developers on how to solve the issue.
The error management system must also handle the case in which the client intercepts HTTP error versions (this is the case of some versions of Adobe Flash). In order to allow the developer to intercept error codes, the resource URI must have an optional flag (by default set to false
) to suppress response error codes. When this flag is true the HTTP response will be always 200 –OK
and the response will contain a JSON object with the error details. To enable error code suppression, you can use a query in the resource URI as follows:
/fablabs/1234?suppress_response_codes=true&job=1235
We use Twitter API style; thus, the URI is deliberately verbose to highlight the effect on the response codes. The server response contains a JSON object with the error details, for example:
{“error”: “Unable to delete. The job you specified does not exist.”}
GET /fablabs/1234
Response:
200 OK
{
“fablab”: {
“id”: 1234
....
},
“jobs”: {
....
}
}
GET /fablabs
Response:
200 OK
{
“fablabs”: [
{
“fablab”: {
“id”: 1234
....
},
“jobs”:
{
....
}
},
{
“fablab”: {
“id”: 1235
....
},
“jobs”: {
....
}
}
],
“_metadata”: [
{“totalCount”: 500, “limit”: 10, “offset”: 0}
]}
Observe that the response also includes a _metadata object with the following fields:
totalCount
: the total number of records in the databaselimit
: the number of records displayed in the responseoffset
: the offset with respect the first element of the database (an offset of 0 means that the records are displayed starting from the first element of the database)
POST /fablabs/jobs?machine=laser%20cutter&process=cut&material =wood&lat=xx&long=yy
Response:
200 OK
{
“fablab”: {
“id”: 1234
“name”: “Fab Lab Name”
“address” : {....},
“coordinates”: {....},
“contact”: {....},
“openingDays”: {....}
},
“job”: {
“id”: 1235,
“status”: “pending”,
“process”: “cut”,
“queue”: “global”,
“queuePosition”: 1,
“machine”: {
“machineId”: 12345,
“type”: “laser cutter”,
“vendor”: “Epilog”
}
}
}
Recall, that with this method a design file in PNG (i.e. a graphic format) or GCODE (i.e. a text format) format is uploaded on the server. In the case of PNG format, our API specifications correspond to the HTTP request depicted below.
POST /fablabs/
Host: api.cloudhub.uspcloud.eu/uploads
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryqzByvokjOTfF9UwD
Content-Length: 204
------WebKitFormBoundaryqzByvokjOTfF9UwD
Content-Disposition: form-data; name="design"; filename="design.png"
Content-Type: image/png
File contents go here.
------WebKitFormBoundaryqzByvokjOTfF9UwD--
GET /fablabs/1234?job=1235
Response:
200 OK
{
“job”: {
“id”: 1235,
“status”: “pending”,
“machine”: {....}
}
DELETE /fablabs/1234?job=1235
Response:
200 OK