diff --git a/API.md b/API.md index 18971ca..ce98031 100755 --- a/API.md +++ b/API.md @@ -114,7 +114,7 @@ Content-Type: application/json; charset=UTF-8 ``` -#### Request Example (set position) +#### Request Example (set position via default relative percentage) ```javascript PUT /v1/pen Content-Type: application/json; charset=UTF-8 @@ -126,6 +126,19 @@ Content-Type: application/json; charset=UTF-8 ``` +#### Request Example (set position via absolute measurement) +```javascript +PUT /v1/pen +Content-Type: application/json; charset=UTF-8 + +{ + "abs": "mm", // Can be 'mm', or 'in' + "x": 20.5, + "y": 230.25 +} + +``` + #### Request Example (reset distance counter) ```javascript PUT /v1/pen @@ -181,6 +194,11 @@ position. In those cases, the response will return a `202 Accepted` instead of a `200 OK`. * `lastDuration` in return data can be used in conjunction with ignoreTimeout to allow the client to manage timings instead of waiting on the server. + * Absolute measurement is only supported by bot configurations that define +`maxAreaMM` width and height. For non-planar bots like the EggBot, absolute +measurements of the X axis could never reliably match to real world constants as +a differing egg size would change this measurement, so sending an `abs` option +will result in a `406` error. * * * @@ -624,7 +642,83 @@ Content-Type: application/json; charset=UTF-8 called. This might have to change though... -## 6. Socket.IO & real-time event data streaming +## 6. Batch +Overhead on individual ReSTful requests isn't so bad, but add that up over 100k+ +instructions/commands, and that's minutes wasted waiting for all the data just +to get where it needs to go. If you don't need to know what's happening after +every request, then _this endpoint is for you!_ + +This final resource is meant as a catch all, allowing for ordered lists of +ReSTful endpoint commands to be batch uploaded as either literal JSON data, or +JSON file & path that the server has access to (either local/or remote HTTP). + +### POST /v1/batch +Post the batch data into the queue. Returns when processing is complete, or +there's an error. + +#### Request: Direct batch data. +```javascript +POST /v1/batch +Content-Type: application/json; charset=UTF-8 + +[ + {"DELETE v1/pen": {}}, // Park. + {"PUT v1/pen": {"x": 50, "y": 50}}, // Move to 50, 50. + {"PUT v1/pen": {"x": 10, "y": 50}}, // Move to 10, 50. + {"DELETE v1/pen": {}} // Park. +] +``` + +#### Request: Batch file (local) +```javascript +POST /v1/batch +Content-Type: application/json; charset=UTF-8 + +{ + // JSON file to read from (make sure the server has permission to read the file!) + "file": "/tmp/data/cncsererver-batch-example.json" +} +``` + +#### Request: Batch file (remote) +```javascript +POST /v1/batch +Content-Type: application/json; charset=UTF-8 + +{ + // Again, make sure the server has HTTP & file access to the file. + "file": "http://example.com/batch-data.json" +} +``` + +### Response +```javascript +HTTP/1.1 201 OK +Content-Type: application/json; charset=UTF-8 + +{ + // Because some batch processing takes longer than the connection would be + // held open for, we simply return a 201 that the command shave been read + // and that these will be pushed into the buffer as quickly as possible. + "status" : "Parsed 4 commands, queuing" +} +``` + +##### Usage Notes + * Command items are parsed and run semi-asynchronously, with each being run as + if an individual ReSTful request had been called, without the overhead. + * Every command is run with `ignoreTimeout` set, so no need to include it in + batch command data. If using the JS wrapper, this is done for you. + * Detailed error catching is mostly non-existent, make sure your data is well + formed and tested without batching before moving to batch submission. + * Return data reporting is exceedingly minimal, so make sure you've + decoupled your client from return data (just tie into stream updates). + * For batches of > 15k commands, data will stream into the buffer internally + for some time, so you have to be careful not to queue any commands in + afterwards or commands will be executed in the wrong order. + + +## 7. Socket.IO & real-time event data streaming The API has served the project incredibly well, but it was lacking in one important aspect: a remote client can receive no updates without asking first, no events or data without polling or some other kludge. That is now all diff --git a/cncserver_api.postman.json b/cncserver_api.postman.json index 5111ed5..7f74074 100755 --- a/cncserver_api.postman.json +++ b/cncserver_api.postman.json @@ -1,365 +1,570 @@ { - "id": "6ed2f056-f044-da06-28aa-6025b812dab8", - "name": "CNC Server API", - "timestamp": 1365738583038, - "order": [ - "cfd1b0a7-6b78-5120-fe2e-fcfba5c3b09a", - "72b33574-693f-cf8d-0aef-d14b4ba06162", - "e85829d1-c897-636a-687f-41c659f12ee8", - "89941fd0-9ccd-1b1a-3b81-13112ae7c917", - "d7d4c368-2f3b-c666-ff86-3d91b4aca87d", - "77c30fc7-8884-e099-f535-d354429b3ad5", - "cb9638bb-94a1-9fd9-c910-8eb97a8f95e9", - "12044a31-0d86-f367-26d2-96d7a0d918d6", - "7065aa8b-188f-cd83-44f6-48da0db125da", - "5c97876c-a835-a9c8-a58d-d2524e7ada6f", - "8bd9b3dd-fb3a-bf4d-0e79-5835ad987b86", - "018053b5-0a68-4027-0c8a-182f7206e0bb", - "1efab236-e56a-1268-ca00-2e8938a2054a", - "199a3586-8ac1-bae8-0c50-2671fd17a34a", - "7c10785d-134d-1a4a-6f94-c1308915a3b2", - "b131cd64-cac4-08ee-7908-599de452765f", - "899a0cc6-8e2c-1952-482e-8947610fb873", - "746528c7-47f2-c0ff-09ff-17d6f9ceec03", - "b8dbd92e-91d4-9a88-3bc0-38b60dcb730a", - "e241fb57-9c0c-baa0-4222-b0eb487bc4ef", - "b6825285-5a48-444a-7f36-408013f86af4", - "4ce5e190-7d00-9be4-703e-e4f5d3201ef6", - "d72fb956-4f95-ae22-7f12-545f746d6fd3" - ], - "requests": [ - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "018053b5-0a68-4027-0c8a-182f7206e0bb", - "name": "Tools: Enumerate", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/tools", - "method": "GET", - "headers": "", - "data": [], - "dataMode": "params", - "timestamp": 0, - "version": 2, - "time": 1375823770402 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "12044a31-0d86-f367-26d2-96d7a0d918d6", - "name": "Pen: Go to 100%,100%", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", - "method": "PUT", - "headers": "Content-Type: application/json; charset=UTF-8\n", - "data": "{\n\"x\": 100,\n\"y\": 100\n}", - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1375824095011 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "199a3586-8ac1-bae8-0c50-2671fd17a34a", - "name": "Motors: Reset offset", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/motors", - "method": "PUT", - "headers": "Content-Type: application/json; charset=UTF-8\n", - "data": "{\n \"reset\": 1\n}", - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1375824541916 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "1efab236-e56a-1268-ca00-2e8938a2054a", - "name": "Motors: Unlock", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/motors", - "method": "DELETE", - "headers": "", - "data": "", - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1375824504090 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "4ce5e190-7d00-9be4-703e-e4f5d3201ef6", - "name": "Buffer: Pause operations", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/buffer", - "method": "PUT", - "headers": "Content-Type: application/json; charset=UTF-8\n", - "data": "{\n \"paused\": true\n}", - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "5c97876c-a835-a9c8-a58d-d2524e7ada6f", - "name": "Pen: Park", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", - "method": "DELETE", - "headers": "", - "data": [], - "dataMode": "params", - "timestamp": 0, - "version": 2, - "time": 1375823758505 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "7065aa8b-188f-cd83-44f6-48da0db125da", - "name": "Pen: Reset distance counter", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", - "method": "PUT", - "headers": "Content-Type: application/json; charset=UTF-8\n", - "data": "{\n \"resetCounter\": 1\n}", - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "72b33574-693f-cf8d-0aef-d14b4ba06162", - "name": "Pen: Pen Down", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", - "method": "PUT", - "headers": "Content-Type: application/json; charset=UTF-8\n", - "data": "{\n \"state\": 1\n}", - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1375824107577 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "746528c7-47f2-c0ff-09ff-17d6f9ceec03", - "name": "Settings: Enable Debug Mode", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/settings/global", - "method": "PUT", - "headers": "Content-Type: application/json; charset=UTF-8\n", - "data": "{\n \"debug\": true\n}", - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1384933117223 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "77c30fc7-8884-e099-f535-d354429b3ad5", - "name": "Pen: Go to 0,0", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", - "method": "PUT", - "headers": "Content-Type: application/json; charset=UTF-8\n", - "data": "{\n\"x\": 0,\n\"y\": 0\n}", - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1375824101642 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "7c10785d-134d-1a4a-6f94-c1308915a3b2", - "name": "Settings: Get All Settings", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/settings", - "method": "GET", - "headers": "", - "data": "", - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1384932946112 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "89941fd0-9ccd-1b1a-3b81-13112ae7c917", - "name": "Pen: Up Halfway", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", - "method": "PUT", - "headers": "Content-Type: application/json; charset=UTF-8\n", - "data": "{\n \"state\": 0.50\n}", - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1380610903028 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "899a0cc6-8e2c-1952-482e-8947610fb873", - "name": "Settings: Change Servo Duration", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/settings/bot", - "method": "PUT", - "headers": "Content-Type: application/json; charset=UTF-8\n", - "data": "{\n \"servo:duration\": 400\n}", - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "8bd9b3dd-fb3a-bf4d-0e79-5835ad987b86", - "name": "Tools: Change", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/tools/water0dip", - "method": "PUT", - "headers": "", - "data": [], - "dataMode": "params", - "timestamp": 0, - "version": 2, - "time": 1375823762939 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "b131cd64-cac4-08ee-7908-599de452765f", - "name": "Settings: Get Global Settings", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/settings/global", - "method": "GET", - "headers": "", - "data": "", - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1384932986222 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "b6825285-5a48-444a-7f36-408013f86af4", - "name": "Buffer: Clear buffer", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/buffer", - "method": "DELETE", - "headers": "", - "data": [], - "dataMode": "params", - "timestamp": 0, - "responses": [], - "version": 2 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "b8dbd92e-91d4-9a88-3bc0-38b60dcb730a", - "name": "Settings: Add height preset", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/settings/bot", - "method": "PUT", - "headers": "Content-Type: application/json; charset=UTF-8\n", - "data": "{\n \"servo:presets:foo\": 42\n}", - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "cb9638bb-94a1-9fd9-c910-8eb97a8f95e9", - "name": "Pen: Go to center (50%, 50%)", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", - "method": "PUT", - "headers": "Content-Type: application/json; charset=UTF-8\n", - "data": "{\n\n\"x\": 50,\n\"y\": 50\n}", - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1375824098563 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "cfd1b0a7-6b78-5120-fe2e-fcfba5c3b09a", - "name": "Pen: Get Data", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", - "method": "GET", - "headers": "", - "data": "{\n \"state\": 0\n}", - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1375823851308 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "d72fb956-4f95-ae22-7f12-545f746d6fd3", - "name": "Buffer: Resume operations", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/buffer", - "method": "PUT", - "headers": "Content-Type: application/json; charset=UTF-8\n", - "data": "{\n \"paused\": false\n}", - "dataMode": "raw", - "timestamp": 0, - "responses": [], - "version": 2 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "d7d4c368-2f3b-c666-ff86-3d91b4aca87d", - "name": "Pen: Down to Wash", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", - "method": "PUT", - "headers": "Content-Type: application/json; charset=UTF-8\n", - "data": "{\n \"state\": \"wash\"\n}", - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1380610973747 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "e241fb57-9c0c-baa0-4222-b0eb487bc4ef", - "name": "Buffer: Get status", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/buffer", - "method": "GET", - "headers": "", - "data": [ - { - "key": "name", - "value": "api-tauntonstore", - "type": "text" - }, - { - "key": "cleartext", - "value": "T@unton1", - "type": "text" - } - ], - "dataMode": "urlencoded", - "timestamp": 0, - "responses": [], - "version": 2 - }, - { - "collectionId": "6ed2f056-f044-da06-28aa-6025b812dab8", - "id": "e85829d1-c897-636a-687f-41c659f12ee8", - "name": "Pen: Pen Up", - "description": "", - "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", - "method": "PUT", - "headers": "Content-Type: application/json; charset=UTF-8\n", - "data": "{\n \"state\": 0\n}", - "dataMode": "raw", - "timestamp": 0, - "version": 2, - "time": 1375824104522 - } - ] + "id": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "name": "CNC Server API", + "description": "", + "order": [], + "folders": [ + { + "id": "0bde2516-84a7-05a8-3b22-4a54a75ae331", + "name": "Batch", + "description": "", + "order": [ + "fef0f1ad-cde7-90cf-3b32-f83579e57b84", + "9f2dbeec-84c6-1c40-5dce-16d1cb9b2ee9", + "30b86d4a-cd8b-8e28-9f0b-9703654e99f2" + ], + "owner": 0 + }, + { + "id": "4a2986e5-9a55-35da-5e41-25c7d580bf39", + "name": "Buffer", + "description": "", + "order": [ + "323d7179-676f-9e79-18ce-718f97c34414", + "d6ec1182-6f1f-0d07-4244-d1972ffafa54", + "9b58295e-595f-05a2-7aac-d2272e7139ba", + "6a418d59-6db5-00d9-3bb1-74566562b281" + ], + "owner": 0 + }, + { + "id": "389b21df-2d74-c667-590c-aec658d7f8eb", + "name": "Motors", + "description": "", + "order": [ + "94cab647-676c-d57b-0617-7c07adfe3f86", + "f15fd6c8-f5e7-bf6c-4551-79a818dd5e4a" + ], + "owner": 0 + }, + { + "id": "a16eb87f-4484-46dc-f1f7-12bc1e2750fc", + "name": "Pen", + "description": "", + "order": [ + "f4e48842-96f1-0a91-1e58-2df842a5c2d7", + "2d30b1ca-c6aa-d178-85bb-3be00d58a7cf", + "738eae88-349d-c347-83a2-a5bbd01b36bc", + "23937438-f6c0-7511-83e8-95fe06ca506f", + "027bbbb4-41eb-dba3-8dc7-dba72a628411", + "a68a8cf8-ca52-56a6-cb22-34a179c99f0b", + "e9e8a40e-31e7-4b33-12cb-9f06ad095cb0", + "8de0efb6-1ff0-8a29-3d51-505dd669fc2e", + "7be84213-f4f7-f355-7d27-d47ada80e86f", + "8de5264d-25d4-759d-a915-79e75e67e2c6" + ], + "owner": 0 + }, + { + "id": "cf6829a8-2d31-c13c-1d17-3e42ac623722", + "name": "Settings", + "description": "", + "order": [ + "c2168d9b-23c1-89ee-7366-8acc5205d2f6", + "d21b1ec9-278e-bb1b-4d1a-b9c9509b7bc8", + "72ce0933-de7a-35e8-1ff5-ed5e0507153f", + "81ff847c-4a98-e954-8b3c-88328c702a70", + "844a8811-f3d0-d45f-8543-5a68adb9cb40" + ], + "owner": 0 + }, + { + "id": "e432b157-b9ed-25d9-107d-25b9486de4d7", + "name": "Tools", + "description": "", + "order": [ + "5ba9aee4-8848-622f-9992-a0456f4c4764", + "571ae8a8-6d39-4b3b-61d4-8083cf106a21" + ], + "owner": 0 + } + ], + "timestamp": 1365738583038, + "owner": 0, + "public": false, + "requests": [ + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "027bbbb4-41eb-dba3-8dc7-dba72a628411", + "name": "Pen: Down to Wash", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", + "method": "PUT", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "version": 2, + "time": 1380610973747, + "preRequestScript": "", + "tests": "", + "folder": "a16eb87f-4484-46dc-f1f7-12bc1e2750fc", + "rawModeData": "{\n \"state\": \"wash\"\n}" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "23937438-f6c0-7511-83e8-95fe06ca506f", + "name": "Pen: Pen Up", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", + "method": "PUT", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "version": 2, + "time": 1375824104522, + "preRequestScript": "", + "tests": "", + "isLastRequest": true, + "folder": "a16eb87f-4484-46dc-f1f7-12bc1e2750fc", + "rawModeData": "{\n \"state\": 0\n}" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "2d30b1ca-c6aa-d178-85bb-3be00d58a7cf", + "name": "Pen: Get Data", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", + "method": "GET", + "headers": "", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "version": 2, + "time": 1375823851308, + "preRequestScript": "", + "tests": "", + "folder": "a16eb87f-4484-46dc-f1f7-12bc1e2750fc", + "rawModeData": "{\n \"state\": 0\n}" + }, + { + "id": "30b86d4a-cd8b-8e28-9f0b-9703654e99f2", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/batch", + "preRequestScript": "", + "pathVariables": {}, + "method": "POST", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1479791132017, + "name": "Batch: Submit remote batch file", + "description": "", + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "responses": [], + "rawModeData": "{\n \"file\": \"http://example.com/batch.json\"\n}" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "323d7179-676f-9e79-18ce-718f97c34414", + "name": "Buffer: Get status", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/buffer", + "method": "GET", + "headers": "", + "data": [ + { + "key": "name", + "value": "api-tauntonstore", + "type": "text" + }, + { + "key": "cleartext", + "value": "T@unton1", + "type": "text" + } + ], + "dataMode": "urlencoded", + "timestamp": 0, + "responses": [], + "version": 2, + "preRequestScript": "", + "tests": "", + "folder": "4a2986e5-9a55-35da-5e41-25c7d580bf39" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "571ae8a8-6d39-4b3b-61d4-8083cf106a21", + "name": "Tools: Enumerate", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/tools", + "method": "GET", + "headers": "", + "data": [], + "dataMode": "params", + "timestamp": 0, + "version": 2, + "time": 1375823770402, + "preRequestScript": "", + "tests": "", + "folder": "e432b157-b9ed-25d9-107d-25b9486de4d7" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "5ba9aee4-8848-622f-9992-a0456f4c4764", + "name": "Tools: Change", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/tools/water0dip", + "method": "PUT", + "headers": "", + "data": [], + "dataMode": "params", + "timestamp": 0, + "version": 2, + "time": 1375823762939, + "preRequestScript": "", + "tests": "", + "folder": "e432b157-b9ed-25d9-107d-25b9486de4d7" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "6a418d59-6db5-00d9-3bb1-74566562b281", + "name": "Buffer: Resume operations", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/buffer", + "method": "PUT", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "responses": [], + "version": 2, + "preRequestScript": "", + "tests": "", + "folder": "4a2986e5-9a55-35da-5e41-25c7d580bf39", + "rawModeData": "{\n \"paused\": false\n}" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "72ce0933-de7a-35e8-1ff5-ed5e0507153f", + "name": "Settings: Change Servo Duration", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/settings/bot", + "method": "PUT", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "responses": [], + "version": 2, + "preRequestScript": "", + "tests": "", + "folder": "cf6829a8-2d31-c13c-1d17-3e42ac623722", + "rawModeData": "{\n \"servo:duration\": 400\n}" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "738eae88-349d-c347-83a2-a5bbd01b36bc", + "name": "Pen: Up Halfway", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", + "method": "PUT", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "version": 2, + "time": 1380610903028, + "preRequestScript": "", + "tests": "", + "folder": "a16eb87f-4484-46dc-f1f7-12bc1e2750fc", + "rawModeData": "{\n \"state\": 0.50\n}" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "7be84213-f4f7-f355-7d27-d47ada80e86f", + "name": "Pen: Reset distance counter", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", + "method": "PUT", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "responses": [], + "version": 2, + "preRequestScript": "", + "tests": "", + "folder": "a16eb87f-4484-46dc-f1f7-12bc1e2750fc", + "rawModeData": "{\n \"resetCounter\": 1\n}" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "81ff847c-4a98-e954-8b3c-88328c702a70", + "name": "Settings: Enable Debug Mode", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/settings/global", + "method": "PUT", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "version": 2, + "time": 1384933117223, + "preRequestScript": "", + "tests": "", + "folder": "cf6829a8-2d31-c13c-1d17-3e42ac623722", + "rawModeData": "{\n \"debug\": true\n}" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "844a8811-f3d0-d45f-8543-5a68adb9cb40", + "name": "Settings: Add height preset", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/settings/bot", + "method": "PUT", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "responses": [], + "version": 2, + "preRequestScript": "", + "tests": "", + "folder": "cf6829a8-2d31-c13c-1d17-3e42ac623722", + "rawModeData": "{\n \"servo:presets:foo\": 42\n}" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "8de0efb6-1ff0-8a29-3d51-505dd669fc2e", + "name": "Pen: Go to 100%,100%", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", + "method": "PUT", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "version": 2, + "time": 1375824095011, + "preRequestScript": "", + "tests": "", + "folder": "a16eb87f-4484-46dc-f1f7-12bc1e2750fc", + "rawModeData": "{\n\"x\": 100,\n\"y\": 100\n}" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "8de5264d-25d4-759d-a915-79e75e67e2c6", + "name": "Pen: Park", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", + "method": "DELETE", + "headers": "", + "data": [], + "dataMode": "params", + "timestamp": 0, + "version": 2, + "time": 1375823758505, + "preRequestScript": "", + "tests": "", + "folder": "a16eb87f-4484-46dc-f1f7-12bc1e2750fc" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "94cab647-676c-d57b-0617-7c07adfe3f86", + "name": "Motors: Reset offset", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/motors", + "method": "PUT", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "version": 2, + "time": 1375824541916, + "preRequestScript": "", + "tests": "", + "folder": "389b21df-2d74-c667-590c-aec658d7f8eb", + "rawModeData": "{\n \"reset\": 1\n}" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "9b58295e-595f-05a2-7aac-d2272e7139ba", + "name": "Buffer: Pause operations", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/buffer", + "method": "PUT", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "responses": [], + "version": 2, + "preRequestScript": "", + "tests": "", + "folder": "4a2986e5-9a55-35da-5e41-25c7d580bf39", + "rawModeData": "{\n \"paused\": true\n}" + }, + { + "id": "9f2dbeec-84c6-1c40-5dce-16d1cb9b2ee9", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/batch", + "preRequestScript": "", + "pathVariables": {}, + "method": "POST", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1479791139664, + "name": "Batch: Submit local batch file", + "description": "", + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "responses": [], + "rawModeData": "{\n \"file\": \"batch.json\"\n}" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "a68a8cf8-ca52-56a6-cb22-34a179c99f0b", + "name": "Pen: Go to 0,0", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", + "method": "PUT", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "version": 2, + "time": 1375824101642, + "preRequestScript": "", + "tests": "", + "folder": "a16eb87f-4484-46dc-f1f7-12bc1e2750fc", + "rawModeData": "{\n\"x\": 0,\n\"y\": 0\n}" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "c2168d9b-23c1-89ee-7366-8acc5205d2f6", + "name": "Settings: Get All Settings", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/settings", + "method": "GET", + "headers": "", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "version": 2, + "time": 1384932946112, + "preRequestScript": "", + "tests": "", + "folder": "cf6829a8-2d31-c13c-1d17-3e42ac623722", + "rawModeData": "" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "d21b1ec9-278e-bb1b-4d1a-b9c9509b7bc8", + "name": "Settings: Get Global Settings", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/settings/global", + "method": "GET", + "headers": "", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "version": 2, + "time": 1384932986222, + "preRequestScript": "", + "tests": "", + "folder": "cf6829a8-2d31-c13c-1d17-3e42ac623722", + "rawModeData": "" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "d6ec1182-6f1f-0d07-4244-d1972ffafa54", + "name": "Buffer: Clear buffer", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/buffer", + "method": "DELETE", + "headers": "", + "data": [], + "dataMode": "params", + "timestamp": 0, + "responses": [], + "version": 2, + "preRequestScript": "", + "tests": "", + "folder": "4a2986e5-9a55-35da-5e41-25c7d580bf39" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "e9e8a40e-31e7-4b33-12cb-9f06ad095cb0", + "name": "Pen: Go to center (50%, 50%)", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", + "method": "PUT", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "version": 2, + "time": 1375824098563, + "preRequestScript": "", + "tests": "", + "folder": "a16eb87f-4484-46dc-f1f7-12bc1e2750fc", + "rawModeData": "{\n\n\"x\": 50,\n\"y\": 50\n}" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "f15fd6c8-f5e7-bf6c-4551-79a818dd5e4a", + "name": "Motors: Unlock", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/motors", + "method": "DELETE", + "headers": "", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "version": 2, + "time": 1375824504090, + "preRequestScript": "", + "tests": "", + "folder": "389b21df-2d74-c667-590c-aec658d7f8eb", + "rawModeData": "" + }, + { + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "id": "f4e48842-96f1-0a91-1e58-2df842a5c2d7", + "name": "Pen: Pen Down", + "description": "", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/pen", + "method": "PUT", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "data": [], + "dataMode": "raw", + "timestamp": 0, + "version": 2, + "time": 1375824107577, + "preRequestScript": "", + "tests": "", + "folder": "a16eb87f-4484-46dc-f1f7-12bc1e2750fc", + "rawModeData": "{\n \"state\": 1\n}" + }, + { + "id": "fef0f1ad-cde7-90cf-3b32-f83579e57b84", + "headers": "Content-Type: application/json; charset=UTF-8\n", + "url": "http://{{cncserver-host}}:{{cncserver-port}}/v1/batch", + "pathVariables": {}, + "preRequestScript": "", + "method": "POST", + "collectionId": "12ad3ed7-7124-c4a7-b839-6b8da3f022b5", + "data": [], + "dataMode": "raw", + "name": "Batch: Submit batch data directly", + "description": "", + "descriptionFormat": "html", + "time": 1479792255823, + "version": 2, + "responses": [], + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "folder": "0bde2516-84a7-05a8-3b22-4a54a75ae331", + "rawModeData": "[\n {\"DELETE v1/pen\": {}},\n {\"PUT v1/tools/water0\": {}},\n {\"PUT v1/tools/water2\": {}},\n {\"PUT v1/tools/color2\": {}},\n {\"PUT v1/pen\": {\"x\": 10, \"y\": 10}},\n {\"PUT v1/pen\": {\"state\": 1}},\n {\"PUT v1/pen\": {\"x\": 50, \"y\": 10}},\n {\"PUT v1/pen\": {\"x\": 50, \"y\": 50}},\n {\"PUT v1/pen\": {\"x\": 10, \"y\": 50}},\n {\"PUT v1/pen\": {\"x\": 10, \"y\": 10}},\n {\"DELETE v1/pen\": {}}\n]" + } + ] } \ No newline at end of file diff --git a/example/cncserver.client.api.js b/example/cncserver.client.api.js index 89b16bf..bc71c6c 100755 --- a/example/cncserver.client.api.js +++ b/example/cncserver.client.api.js @@ -59,25 +59,6 @@ cncserver.api = { if (typeof options !== 'object') options = {}; options.state = value; - // If we're on node and we have a socket, shortcut via WebSockets. - // TODO: FIX this as causes socket.io call stack overflows - if (isNode && cncserver.global.socket && false) { - var data = {state: value, returnData: !!callback}; - cncserver.global.socket.emit('height', data); - if (callback) { - var catchMove = function(d){ - callback(d); - cncserver.global.socket.removeListener('height', catchMove); - }; - - cncserver.global.socket.on('height', catchMove); - } - - // Leave this entire function to avoid doing the regular request. - return; - } - - // Ignore timeout with no callback by default if (typeof options.ignoreTimeout === 'undefined') { options.ignoreTimeout = callback ? '' : '1'; @@ -202,34 +183,12 @@ cncserver.api = { if (!isNode) $(cncserver.api).trigger('movePoint', [point]); // Sanity check inputs - point.x = point.x > 100 ? 100 : point.x; - point.y = point.y > 100 ? 100 : point.y; point.x = point.x < 0 ? 0 : point.x; point.y = point.y < 0 ? 0 : point.y; - // If we're on node and we have a socket, shortcut via WebSockets. - // TODO: FIX this as causes socket.io call stack overflows - if (isNode && cncserver.global.socket && false) { - if (typeof point.returnData === 'undefined') { - point.returnData = !!callback; - } - - cncserver.global.socket.emit('move', point); - if (callback) { - if (!point.returnData){ - callback({}); - } else { - var catchMove = function(d){ - callback(d); - cncserver.global.socket.removeListener('move', catchMove); - }; - - cncserver.global.socket.on('move', catchMove); - } - } - - // Leave this entire function to avoid doing the regular request. - return; + if (!point.abs) { + point.x = point.x > 100 ? 100 : point.x; + point.y = point.y > 100 ? 100 : point.y; } // Ignore timeout with no callback by default @@ -440,7 +399,152 @@ cncserver.api = { } ); } - } + }, + + // Batch API for lowering command send overhead. + batch: { + skipSend: false, + saveFile: '', + firstCommand: true, + data: [], + + /** + * Once enabled, all commands sent through this wrapper will be saved for + * batch sending instead of actually being sent, until end is run. + * + * @return {[type]} [description] + */ + start: function(options) { + options = options || {}; + cncserver.api.batch.endClear(); + cncserver.api.batch.skipSend = true; + + // If node and a file path send, try to save it + // TODO: Add in some file access checks to keep this from dying. + if (isNode && options.saveToFile) { + cncserver.api.batch.fs = require('fs'); + cncserver.api.batch.saveFile = options.saveToFile; + cncserver.api.batch.fs.writeFileSync(options.saveToFile, '['); + } + }, + + /** + * Write final file ending to the JSON file storage. + */ + finishFile: function() { + if (cncserver.api.batch.saveFile) { + cncserver.api.batch.fs.appendFileSync( + cncserver.api.batch.saveFile, + ']' + ); + } + }, + + /** + * Add an entry into the batch data storage. + * + * @param {string} key + * The key holding the method and path + * @param {object} data + * The data arguments being sent to modify the command. + */ + addEntry: function(key, data) { + // Unset ignore timeout as it's just dead weight with batch. + if (data.ignoreTimeout) delete data.ignoreTimeout; + + var entry = {}; + entry[key] = data; + + // Store the data. + if (cncserver.api.batch.saveFile) { + var line = JSON.stringify(entry); + + // Add a comma if the command isn't first. + if (!cncserver.api.batch.firstCommand) { + line = ",\n" + line; + } + cncserver.api.batch.fs.appendFileSync( + cncserver.api.batch.saveFile, + line + ); + } else { + cncserver.api.batch.data.push(entry); + } + cncserver.api.batch.firstCommand = false; + }, + + /** + * End the batch and return the data saved. + * + * @return {object|string} + * Full data array if local, otherwise the file path if saved directly. + */ + endReturn: function() { + var dump = []; + + if (cncserver.api.batch.saveFile) { + cncserver.api.batch.finishFile(); + dump = cncserver.api.batch.saveFile; + } else { + dump = cncserver.api.batch.data; + } + + cncserver.api.batch.endClear(); + return dump; + }, + + /** + * End the batch and send the data immediately. + * + * @param {Function} callback + * Function called when sending is complete. + * @param {object} options + * Keyed options object, currently supports: + * * fileOverride: path/URL that the server should have read access to + * as opposed to the one that the node client has write access to. + */ + endSend: function(callback, options) { + var dump; + options = options || {}; + + // File or raw data? + if (cncserver.api.batch.saveFile) { + cncserver.api.batch.finishFile(); + + // Allow client to specify the end send file path differently. + if (options.fileOverride) { + dump = {file: options.fileOverride}; + } else { + dump = {file: cncserver.api.batch.saveFile}; + } + } else { + // Send the actual data directly. + dump = cncserver.api.batch.data; + } + + cncserver.api.batch.endClear(); + console.time('process-batch'); + _post('batch', { + data: dump, + timeout: 1000 * 60 * 10, // Timeout of 10 mins! + success: function(d){ + console.timeEnd('process-batch'); + console.info(d); + callback(); + }, + }); + }, + + /** + * Reset all batch state to default. + */ + endClear: function() { + cncserver.api.batch.firstCommand = true; + cncserver.api.batch.data = []; + cncserver.api.batch.saveFile = ''; + cncserver.api.batch.skipSend = false; + } + }, }; function _get(path, options) { @@ -484,6 +588,25 @@ function _request(method, path, options) { } var uri = srv.protocol + '://' + srv.domain + ':' + srv.port + srvPath; + + // If we're batching commands.. we don't actually send them, we store them! + // ...unless this command is meant to skipBuffer. + if (cncserver.api.batch.skipSend && !options.data.skipBuffer) { + if (isNode) { + process.nextTick(function() { + cncserver.api.batch.addEntry(method + ' ' + srvPath, options.data); + options.success(); + }); + } else { + setTimeout(function() { + cncserver.api.batch.addEntry(method + ' ' + srvPath, options.data); + options.success(); + }, 0); + } + return; + } + + // Send the request. if (!isNode) { $.ajax({ url: uri, @@ -499,10 +622,10 @@ function _request(method, path, options) { json: true, method: method, body: options.data, - timeout: 1000 + timeout: options.timeout || 1000 }, function(error, response, body){ if (error) { - console.error(error); + console.error('API: Node request error', uri, method, error); if (options.error) options.error(error, response, body); } else { if (options.success) options.success(body, response); diff --git a/example/cncserver.client.commander.js b/example/cncserver.client.commander.js index a6a025b..340cdb5 100755 --- a/example/cncserver.client.commander.js +++ b/example/cncserver.client.commander.js @@ -48,28 +48,28 @@ cncserver.cmd = { next = [next]; } + // These are all run as send and forgets, so ignore the timeout. switch (next[0]) { case "move": + next[1].ignoreTimeout = true; cncserver.api.pen.move(next[1], cncserver.cmd.cb); break; case "tool": + next[1].ignoreTimeout = true; cncserver.api.tools.change(next[1], cncserver.cmd.cb); break; case "up": - cncserver.api.pen.up(cncserver.cmd.cb); + cncserver.api.pen.up(cncserver.cmd.cb, {ignoreTimeout: true}); break; case "down": - cncserver.api.pen.down(cncserver.cmd.cb); + cncserver.api.pen.down(cncserver.cmd.cb, {ignoreTimeout: true}); break; case "status": cncserver.utils.status(next[1], next[2]); cncserver.cmd.cb(true); break; - case "wash": - cncserver.wcb.fullWash(cncserver.cmd.cb); - break; case "park": - cncserver.api.pen.park(cncserver.cmd.cb); + cncserver.api.pen.park(cncserver.cmd.cb, {ignoreTimeout: true}); break; case "custom": cncserver.cmd.cb(); diff --git a/example/index.html b/example/index.html index cb75ce6..1016741 100755 --- a/example/index.html +++ b/example/index.html @@ -473,6 +473,79 @@