├── .gitignore ├── LICENSE.txt ├── README.md ├── dist └── bundle.js ├── example └── 01-simple-requests.html ├── package.json ├── src ├── agent.js ├── index.js ├── requests │ ├── assets-request.js │ ├── current-request.js │ ├── probe-request.js │ ├── protocol-request.js │ └── sample-request.js └── responses │ ├── assets-response.js │ ├── create-protocol-response.js │ ├── devices-response.js │ ├── error-response.js │ ├── headers │ ├── assets-header.js │ ├── devices-header.js │ ├── error-header.js │ ├── protocol-header.js │ └── streams-header.js │ ├── protocol-response.js │ └── streams-response.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | node_modules/* -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Phil Coltrane 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MTConnect-JS 2 | 3 | ## Overview 4 | 5 | MTConnect-JS is a library for accessing data from an MTConnect agent via Javascript in the browser. 6 | If the library is not served from the same origin as the agent, the agent must allow CORS requests, or the browser will block requests. 7 | 8 | (The library is being rewritten in modern Javascript, and to remove the JQuery dependencies. Some functionality may have changed or be unavailable during this process.) 9 | 10 | ## Installation 11 | 12 | > git clone https://github.com/pmcoltrane/MTConnect-JS.git 13 | 14 | ## Build 15 | 16 | > npm run build 17 | 18 | NPM will run webpack, and create a `dist/bundle.js` that can be included in an HTML <script> tag. 19 | 20 | ## Usage 21 | 22 | For usage, see the examples under the `example` folder. 23 | 24 | ## Further Information 25 | 26 | Information about MTConnect, including standards documents, may be found at the [MTConnect Institute website](http://mtconnect.org). 27 | -------------------------------------------------------------------------------- /dist/bundle.js: -------------------------------------------------------------------------------- 1 | var MTConnect = 2 | /******/ (function(modules) { // webpackBootstrap 3 | /******/ // The module cache 4 | /******/ var installedModules = {}; 5 | /******/ 6 | /******/ // The require function 7 | /******/ function __webpack_require__(moduleId) { 8 | /******/ 9 | /******/ // Check if module is in cache 10 | /******/ if(installedModules[moduleId]) { 11 | /******/ return installedModules[moduleId].exports; 12 | /******/ } 13 | /******/ // Create a new module (and put it into the cache) 14 | /******/ var module = installedModules[moduleId] = { 15 | /******/ i: moduleId, 16 | /******/ l: false, 17 | /******/ exports: {} 18 | /******/ }; 19 | /******/ 20 | /******/ // Execute the module function 21 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 22 | /******/ 23 | /******/ // Flag the module as loaded 24 | /******/ module.l = true; 25 | /******/ 26 | /******/ // Return the exports of the module 27 | /******/ return module.exports; 28 | /******/ } 29 | /******/ 30 | /******/ 31 | /******/ // expose the modules object (__webpack_modules__) 32 | /******/ __webpack_require__.m = modules; 33 | /******/ 34 | /******/ // expose the module cache 35 | /******/ __webpack_require__.c = installedModules; 36 | /******/ 37 | /******/ // define getter function for harmony exports 38 | /******/ __webpack_require__.d = function(exports, name, getter) { 39 | /******/ if(!__webpack_require__.o(exports, name)) { 40 | /******/ Object.defineProperty(exports, name, { 41 | /******/ configurable: false, 42 | /******/ enumerable: true, 43 | /******/ get: getter 44 | /******/ }); 45 | /******/ } 46 | /******/ }; 47 | /******/ 48 | /******/ // getDefaultExport function for compatibility with non-harmony modules 49 | /******/ __webpack_require__.n = function(module) { 50 | /******/ var getter = module && module.__esModule ? 51 | /******/ function getDefault() { return module['default']; } : 52 | /******/ function getModuleExports() { return module; }; 53 | /******/ __webpack_require__.d(getter, 'a', getter); 54 | /******/ return getter; 55 | /******/ }; 56 | /******/ 57 | /******/ // Object.prototype.hasOwnProperty.call 58 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 59 | /******/ 60 | /******/ // __webpack_public_path__ 61 | /******/ __webpack_require__.p = ""; 62 | /******/ 63 | /******/ // Load entry module and return exports 64 | /******/ return __webpack_require__(__webpack_require__.s = 3); 65 | /******/ }) 66 | /************************************************************************/ 67 | /******/ ([ 68 | /* 0 */ 69 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 70 | 71 | "use strict"; 72 | class ProtocolRequest { 73 | 74 | constructor(baseUrl) { 75 | this.baseUrl = baseUrl; 76 | } 77 | 78 | buildUrl(components, query) { 79 | let url = this.baseUrl; 80 | if (!url.endsWith('/')) url += '/'; 81 | 82 | // Join array of URL components into the path 83 | let pathString = components.filter(i => i).map(encodeURIComponent).join('/'); 84 | 85 | // Create the querystring 86 | let queryComponents = []; 87 | if (query) for (let i in query) { 88 | if (!i || !query[i]) continue; 89 | 90 | let key = encodeURIComponent(i); 91 | let value = encodeURIComponent(query[i]); 92 | queryComponents.push(key + '=' + value); 93 | } 94 | let queryString = queryComponents.join("&"); 95 | if (queryString) queryString = '?' + queryString; 96 | 97 | return url + pathString + queryString; 98 | } 99 | 100 | async send(url) { 101 | console.log('Send', url); 102 | 103 | return new Promise((resolve, reject) => { 104 | let xhr = new XMLHttpRequest(); 105 | xhr.open('GET', url); 106 | xhr.onload = e => { 107 | if (xhr.readyState === 4) { 108 | if (xhr.status === 200) { 109 | //console.log(xhr.responseText) 110 | resolve(xhr.responseXML); 111 | } else { 112 | //console.error(xhr.statusText) 113 | reject(xhr.statusText); 114 | } 115 | } 116 | }; 117 | 118 | xhr.onerror = e => { 119 | //console.error(xhr.statusText) 120 | reject(xhr.statusText); 121 | }; 122 | 123 | xhr.send(null); 124 | }); 125 | } 126 | 127 | } 128 | /* harmony export (immutable) */ __webpack_exports__["a"] = ProtocolRequest; 129 | 130 | 131 | /***/ }), 132 | /* 1 */ 133 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 134 | 135 | "use strict"; 136 | class ProtocolHeader { 137 | constructor(xmlElem) { 138 | this.xmlElement = xmlElem; 139 | 140 | if (!xmlElem || !xmlElem.getAttribute) throw new Error('Header element not valid.'); 141 | 142 | // Extract common attributes 143 | this.creationTime = Date.parse(xmlElem.getAttribute('creationTime')); 144 | this.sender = xmlElem.getAttribute('sender'); 145 | this.instanceId = Number(xmlElem.getAttribute('instanceId')); 146 | this.version = xmlElem.getAttribute('version'); 147 | } 148 | } 149 | /* harmony export (immutable) */ __webpack_exports__["a"] = ProtocolHeader; 150 | 151 | 152 | /***/ }), 153 | /* 2 */ 154 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 155 | 156 | "use strict"; 157 | class ProtocolResponse { 158 | constructor(xmlDoc) { 159 | this.xmlDocument = xmlDoc; 160 | this.documentType = xmlDoc.documentElement.tagName; 161 | this.isError = false; 162 | } 163 | 164 | } 165 | /* harmony export (immutable) */ __webpack_exports__["a"] = ProtocolResponse; 166 | 167 | 168 | /***/ }), 169 | /* 3 */ 170 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 171 | 172 | "use strict"; 173 | Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); 174 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__requests_assets_request__ = __webpack_require__(4); 175 | /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "AssetsRequest", function() { return __WEBPACK_IMPORTED_MODULE_0__requests_assets_request__["a"]; }); 176 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__requests_current_request__ = __webpack_require__(5); 177 | /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "CurrentRequest", function() { return __WEBPACK_IMPORTED_MODULE_1__requests_current_request__["a"]; }); 178 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__requests_probe_request__ = __webpack_require__(6); 179 | /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "ProbeRequest", function() { return __WEBPACK_IMPORTED_MODULE_2__requests_probe_request__["a"]; }); 180 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__requests_sample_request__ = __webpack_require__(7); 181 | /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "SampleRequest", function() { return __WEBPACK_IMPORTED_MODULE_3__requests_sample_request__["a"]; }); 182 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__responses_create_protocol_response__ = __webpack_require__(8); 183 | /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "ProcessResponse", function() { return __WEBPACK_IMPORTED_MODULE_4__responses_create_protocol_response__["a"]; }); 184 | 185 | 186 | 187 | 188 | 189 | 190 | console.log('MTConnect'); 191 | 192 | /***/ }), 193 | /* 4 */ 194 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 195 | 196 | "use strict"; 197 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_request__ = __webpack_require__(0); 198 | 199 | 200 | class AssetsRequest extends __WEBPACK_IMPORTED_MODULE_0__protocol_request__["a" /* default */] { 201 | 202 | constructor(baseUrl, options) { 203 | super(baseUrl); 204 | this._options = options; 205 | } 206 | 207 | async execute() { 208 | let url = this.buildUrl(['asset'], this._options); 209 | return this.send(url); 210 | } 211 | 212 | } 213 | /* harmony export (immutable) */ __webpack_exports__["a"] = AssetsRequest; 214 | 215 | 216 | /***/ }), 217 | /* 5 */ 218 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 219 | 220 | "use strict"; 221 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_request_js__ = __webpack_require__(0); 222 | 223 | 224 | class CurrentRequest extends __WEBPACK_IMPORTED_MODULE_0__protocol_request_js__["a" /* default */] { 225 | 226 | constructor(baseUrl, options) { 227 | super(baseUrl); 228 | this._options = options || {}; 229 | } 230 | 231 | get at() { 232 | return this._options.at; 233 | } 234 | set at(value) { 235 | this._options.at = value; 236 | } 237 | 238 | get path() { 239 | return this._options.path; 240 | } 241 | set path(value) { 242 | this._options.path = value; 243 | } 244 | 245 | async execute() { 246 | let url = this.buildUrl(['current'], this._options); 247 | return this.send(url); 248 | } 249 | 250 | } 251 | /* harmony export (immutable) */ __webpack_exports__["a"] = CurrentRequest; 252 | 253 | 254 | /***/ }), 255 | /* 6 */ 256 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 257 | 258 | "use strict"; 259 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_request_js__ = __webpack_require__(0); 260 | 261 | 262 | class ProbeRequest extends __WEBPACK_IMPORTED_MODULE_0__protocol_request_js__["a" /* default */] { 263 | 264 | constructor(baseUrl, deviceName) { 265 | super(baseUrl); 266 | this._deviceName = deviceName; 267 | } 268 | 269 | get deviceName() { 270 | return this._deviceName; 271 | } 272 | set deviceName(value) { 273 | this._deviceName = value; 274 | } 275 | 276 | async execute() { 277 | let url = this.buildUrl([this.deviceName]); 278 | return this.send(url); 279 | } 280 | 281 | } 282 | /* harmony export (immutable) */ __webpack_exports__["a"] = ProbeRequest; 283 | 284 | 285 | /***/ }), 286 | /* 7 */ 287 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 288 | 289 | "use strict"; 290 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_request_js__ = __webpack_require__(0); 291 | 292 | 293 | class SampleRequest extends __WEBPACK_IMPORTED_MODULE_0__protocol_request_js__["a" /* default */] { 294 | 295 | constructor(baseUrl, options) { 296 | super(baseUrl); 297 | this._options = options || {}; 298 | } 299 | 300 | get from() { 301 | return this._options.from; 302 | } 303 | set from(value) { 304 | this._options.from = value; 305 | } 306 | 307 | get count() { 308 | return this._options.count; 309 | } 310 | set count(value) { 311 | this._options.count = value; 312 | } 313 | 314 | get path() { 315 | return this._options.path; 316 | } 317 | set path(value) { 318 | this._options.path = value; 319 | } 320 | 321 | async execute() { 322 | let url = this.buildUrl(['sample'], this._options); 323 | return this.send(url); 324 | } 325 | 326 | } 327 | /* harmony export (immutable) */ __webpack_exports__["a"] = SampleRequest; 328 | 329 | 330 | /***/ }), 331 | /* 8 */ 332 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 333 | 334 | "use strict"; 335 | /* harmony export (immutable) */ __webpack_exports__["a"] = CreateProtocolResponse; 336 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__assets_response__ = __webpack_require__(9); 337 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__devices_response__ = __webpack_require__(11); 338 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__error_response__ = __webpack_require__(13); 339 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__streams_response__ = __webpack_require__(15); 340 | 341 | 342 | 343 | 344 | 345 | function CreateProtocolResponse(xmlDoc) { 346 | if (!xmlDoc || !xmlDoc.documentElement || !xmlDoc.documentElement.tagName) { 347 | throw new Error('Document is not a valid document.'); 348 | } 349 | 350 | let documentTag = xmlDoc.documentElement.tagName; 351 | 352 | if (documentTag === 'MTConnectDevices') { 353 | return new __WEBPACK_IMPORTED_MODULE_1__devices_response__["a" /* default */](xmlDoc); 354 | } else if (documentTag === 'MTConnectStreams') { 355 | return new __WEBPACK_IMPORTED_MODULE_3__streams_response__["a" /* default */](xmlDoc); 356 | } else if (documentTag === 'MTConnectAssets') { 357 | return new __WEBPACK_IMPORTED_MODULE_0__assets_response__["a" /* default */](xmlDoc); 358 | } else if (documentTag === 'MTConnectError') { 359 | return new __WEBPACK_IMPORTED_MODULE_2__error_response__["a" /* default */](xmlDoc); 360 | } else { 361 | throw new Error('Document is not a recognized MTConnect document.'); 362 | } 363 | } 364 | 365 | /***/ }), 366 | /* 9 */ 367 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 368 | 369 | "use strict"; 370 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__headers_assets_header__ = __webpack_require__(10); 371 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__protocol_response__ = __webpack_require__(2); 372 | 373 | 374 | 375 | class AssetsResponse extends __WEBPACK_IMPORTED_MODULE_1__protocol_response__["a" /* default */] { 376 | constructor(xmlDoc) { 377 | super(xmlDoc); 378 | 379 | let headerElem = xmlDoc.getElementsByTagName('Header')[0]; 380 | this.header = new __WEBPACK_IMPORTED_MODULE_0__headers_assets_header__["a" /* default */](headerElem); 381 | } 382 | } 383 | /* harmony export (immutable) */ __webpack_exports__["a"] = AssetsResponse; 384 | 385 | 386 | /***/ }), 387 | /* 10 */ 388 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 389 | 390 | "use strict"; 391 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_header__ = __webpack_require__(1); 392 | 393 | 394 | class AssetsHeader extends __WEBPACK_IMPORTED_MODULE_0__protocol_header__["a" /* default */] { 395 | constructor(xmlElem) { 396 | super(xmlElem); 397 | 398 | // Extract Assets attributes 399 | this.assetBufferSize = Number(xmlElem.getAttribute('assetBufferSize')); 400 | this.assetCount = Number(xmlElem.getAttribute('assetCount')); 401 | } 402 | } 403 | /* harmony export (immutable) */ __webpack_exports__["a"] = AssetsHeader; 404 | 405 | 406 | /***/ }), 407 | /* 11 */ 408 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 409 | 410 | "use strict"; 411 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__headers_devices_header__ = __webpack_require__(12); 412 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__protocol_response__ = __webpack_require__(2); 413 | 414 | 415 | 416 | class DevicesResponse extends __WEBPACK_IMPORTED_MODULE_1__protocol_response__["a" /* default */] { 417 | constructor(xmlDoc) { 418 | super(xmlDoc); 419 | 420 | let headerElem = xmlDoc.getElementsByTagName('Header')[0]; 421 | this.header = new __WEBPACK_IMPORTED_MODULE_0__headers_devices_header__["a" /* default */](headerElem); 422 | } 423 | } 424 | /* harmony export (immutable) */ __webpack_exports__["a"] = DevicesResponse; 425 | 426 | 427 | /***/ }), 428 | /* 12 */ 429 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 430 | 431 | "use strict"; 432 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_header__ = __webpack_require__(1); 433 | 434 | 435 | class DevicesHeader extends __WEBPACK_IMPORTED_MODULE_0__protocol_header__["a" /* default */] { 436 | constructor(xmlElem) { 437 | super(xmlElem); 438 | 439 | // Extract Devices attributes 440 | this.assetBufferSize = Number(xmlElem.getAttribute('assetBufferSize')); 441 | this.assetCount = Number(xmlElem.getAttribute('assetCount')); 442 | this.bufferSize = Number(xmlElem.getAttribute('bufferSize')); 443 | } 444 | } 445 | /* harmony export (immutable) */ __webpack_exports__["a"] = DevicesHeader; 446 | 447 | 448 | /***/ }), 449 | /* 13 */ 450 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 451 | 452 | "use strict"; 453 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__headers_error_header__ = __webpack_require__(14); 454 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__protocol_response__ = __webpack_require__(2); 455 | 456 | 457 | 458 | class ErrorResponse extends __WEBPACK_IMPORTED_MODULE_1__protocol_response__["a" /* default */] { 459 | constructor(xmlDoc) { 460 | super(xmlDoc); 461 | 462 | let headerElem = xmlDoc.getElementsByTagName('Header')[0]; 463 | this.header = new __WEBPACK_IMPORTED_MODULE_0__headers_error_header__["a" /* default */](headerElem); 464 | this.isError = true; 465 | } 466 | } 467 | /* harmony export (immutable) */ __webpack_exports__["a"] = ErrorResponse; 468 | 469 | 470 | /***/ }), 471 | /* 14 */ 472 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 473 | 474 | "use strict"; 475 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_header__ = __webpack_require__(1); 476 | 477 | 478 | class ErrorHeader extends __WEBPACK_IMPORTED_MODULE_0__protocol_header__["a" /* default */] { 479 | constructor(xmlElem) { 480 | super(xmlElem); 481 | 482 | // Extract Error attributes 483 | this.bufferSize = Number(xmlElem.getAttribute('bufferSize')); 484 | } 485 | } 486 | /* harmony export (immutable) */ __webpack_exports__["a"] = ErrorHeader; 487 | 488 | 489 | /***/ }), 490 | /* 15 */ 491 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 492 | 493 | "use strict"; 494 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__headers_streams_header__ = __webpack_require__(16); 495 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__protocol_response__ = __webpack_require__(2); 496 | 497 | 498 | 499 | class StreamsResponse extends __WEBPACK_IMPORTED_MODULE_1__protocol_response__["a" /* default */] { 500 | constructor(xmlDoc) { 501 | super(xmlDoc); 502 | 503 | let headerElem = xmlDoc.getElementsByTagName('Header')[0]; 504 | this.header = new __WEBPACK_IMPORTED_MODULE_0__headers_streams_header__["a" /* default */](headerElem); 505 | } 506 | } 507 | /* harmony export (immutable) */ __webpack_exports__["a"] = StreamsResponse; 508 | 509 | 510 | /***/ }), 511 | /* 16 */ 512 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 513 | 514 | "use strict"; 515 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_header__ = __webpack_require__(1); 516 | 517 | 518 | class StreamsHeader extends __WEBPACK_IMPORTED_MODULE_0__protocol_header__["a" /* default */] { 519 | constructor(xmlElem) { 520 | super(xmlElem); 521 | 522 | // Extract Streams attributes 523 | this.bufferSize = Number(xmlElem.getAttribute('bufferSize')); 524 | this.nextSequence = Number(xmlElem.getAttribute('nextSequence')); 525 | this.firstSequence = Number(xmlElem.getAttribute('firstSequence')); 526 | this.lastSequence = Number(xmlElem.getAttribute('lastSequence')); 527 | } 528 | } 529 | /* harmony export (immutable) */ __webpack_exports__["a"] = StreamsHeader; 530 | 531 | 532 | /***/ }) 533 | /******/ ]); -------------------------------------------------------------------------------- /example/01-simple-requests.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 74 | 75 | 76 | 77 |
78 | 79 | 80 | 81 | 82 |
83 | 84 |
85 |
86 | Document type:
87 | Error:
88 | First sequence:
89 | Last sequence:
90 | Next sequence:
91 |
92 | 93 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mtconnect-js", 3 | "version": "1.0.0", 4 | "description": "mtconnect tools for javascript", 5 | "main": "dist/bundle.js", 6 | "directories": { 7 | "example": "example" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "build": "npx webpack" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/pmcoltrane/MTConnect-JS.git" 16 | }, 17 | "keywords": [ 18 | "mtconnect" 19 | ], 20 | "author": "pmcoltrane", 21 | "license": "Apache-2.0", 22 | "bugs": { 23 | "url": "https://github.com/pmcoltrane/MTConnect-JS/issues" 24 | }, 25 | "homepage": "https://github.com/pmcoltrane/MTConnect-JS#readme", 26 | "devDependencies": { 27 | "babel-core": "^6.26.0", 28 | "babel-loader": "^7.1.2", 29 | "babel-polyfill": "^6.26.0", 30 | "babel-preset-env": "^1.6.1", 31 | "babel-preset-es2015": "^6.24.1", 32 | "babel-preset-stage-0": "^6.24.1", 33 | "webpack": "^3.10.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/agent.js: -------------------------------------------------------------------------------- 1 | import ProbeRequest from './probe-request' 2 | import CurrentRequest from './current-request' 3 | import SampleRequest from './sample-request' 4 | import AssetRequest from './asset-request' 5 | 6 | export default class Agent{ 7 | 8 | constructor(baseUrl){ 9 | this.baseUrl = baseUrl 10 | this.interval = 10000 11 | } 12 | 13 | async getProbe(deviceName){ 14 | let request = new ProbeRequest(this.baseUrl, this.deviceName) 15 | return await request.execute() 16 | } 17 | 18 | async getCurrent(at, path){ 19 | let request = new CurrentRequest(this.baseUrl, {at, path}) 20 | return await request.execute() 21 | } 22 | 23 | async getSample(from, count, path){ 24 | let request = new SampleRequest(this.baseUrl, {from, count, path}) 25 | return await request.execute() 26 | } 27 | 28 | async getAsset(){ 29 | let request = new AssetRequest(this.baseUrl) 30 | return await request.execute() 31 | } 32 | 33 | start(){ 34 | // current 35 | // use this to queue up a loop of samples, based on net sequence 36 | } 37 | 38 | stop(){ 39 | throw new Error('not implemented') 40 | } 41 | 42 | // TODO: emit events: 43 | // DevicesReceived 44 | // StreamsReceived 45 | // ErrorReceived 46 | 47 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export {default as AssetsRequest} from './requests/assets-request' 2 | export {default as CurrentRequest} from './requests/current-request' 3 | export {default as ProbeRequest} from './requests/probe-request' 4 | export {default as SampleRequest} from './requests/sample-request' 5 | export {default as ProcessResponse} from './responses/create-protocol-response' 6 | 7 | console.log('MTConnect') -------------------------------------------------------------------------------- /src/requests/assets-request.js: -------------------------------------------------------------------------------- 1 | import ProtocolRequest from './protocol-request' 2 | 3 | export default class AssetsRequest extends ProtocolRequest{ 4 | 5 | constructor(baseUrl, options){ 6 | super(baseUrl) 7 | this._options = options 8 | } 9 | 10 | async execute(){ 11 | let url = this.buildUrl( 12 | ['asset'], 13 | this._options 14 | ) 15 | return this.send(url) 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /src/requests/current-request.js: -------------------------------------------------------------------------------- 1 | import ProtocolRequest from './protocol-request.js' 2 | 3 | export default class CurrentRequest extends ProtocolRequest { 4 | 5 | constructor(baseUrl, options) { 6 | super(baseUrl) 7 | this._options = options || {} 8 | } 9 | 10 | get at() { return this._options.at } 11 | set at(value) { this._options.at = value } 12 | 13 | get path() { return this._options.path } 14 | set path(value) { this._options.path = value } 15 | 16 | async execute() { 17 | let url = this.buildUrl( 18 | ['current'], 19 | this._options 20 | ) 21 | return this.send(url) 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /src/requests/probe-request.js: -------------------------------------------------------------------------------- 1 | import ProtocolRequest from './protocol-request.js' 2 | 3 | export default class ProbeRequest extends ProtocolRequest { 4 | 5 | constructor(baseUrl, deviceName) { 6 | super(baseUrl) 7 | this._deviceName = deviceName 8 | } 9 | 10 | get deviceName() { return this._deviceName } 11 | set deviceName(value) { this._deviceName = value } 12 | 13 | async execute() { 14 | let url = this.buildUrl([this.deviceName]) 15 | return this.send(url) 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /src/requests/protocol-request.js: -------------------------------------------------------------------------------- 1 | export default class ProtocolRequest { 2 | 3 | constructor(baseUrl) { 4 | this.baseUrl = baseUrl 5 | } 6 | 7 | buildUrl(components, query) { 8 | let url = this.baseUrl 9 | if (!url.endsWith('/')) url += '/' 10 | 11 | // Join array of URL components into the path 12 | let pathString = components 13 | .filter(i => i) 14 | .map(encodeURIComponent) 15 | .join('/') 16 | 17 | // Create the querystring 18 | let queryComponents = [] 19 | if (query) for (let i in query) { 20 | if (!i || !query[i]) continue 21 | 22 | let key = encodeURIComponent(i) 23 | let value = encodeURIComponent(query[i]) 24 | queryComponents.push(key + '=' + value) 25 | } 26 | let queryString = queryComponents.join("&") 27 | if (queryString) queryString = '?' + queryString 28 | 29 | return (url + pathString + queryString) 30 | } 31 | 32 | async send(url) { 33 | console.log('Send', url) 34 | 35 | return new Promise((resolve, reject) => { 36 | let xhr = new XMLHttpRequest() 37 | xhr.open('GET', url) 38 | xhr.onload = e => { 39 | if (xhr.readyState === 4) { 40 | if (xhr.status === 200) { 41 | //console.log(xhr.responseText) 42 | resolve(xhr.responseXML) 43 | } 44 | else { 45 | //console.error(xhr.statusText) 46 | reject(xhr.statusText) 47 | } 48 | } 49 | } 50 | 51 | xhr.onerror = e => { 52 | //console.error(xhr.statusText) 53 | reject(xhr.statusText) 54 | } 55 | 56 | xhr.send(null) 57 | }) 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /src/requests/sample-request.js: -------------------------------------------------------------------------------- 1 | import ProtocolRequest from './protocol-request.js' 2 | 3 | export default class SampleRequest extends ProtocolRequest { 4 | 5 | constructor(baseUrl, options) { 6 | super(baseUrl) 7 | this._options = options || {} 8 | } 9 | 10 | get from() { return this._options.from } 11 | set from(value) { this._options.from = value } 12 | 13 | get count() { return this._options.count } 14 | set count(value) { this._options.count = value } 15 | 16 | get path() { return this._options.path } 17 | set path(value) { this._options.path = value } 18 | 19 | async execute() { 20 | let url = this.buildUrl( 21 | ['sample'], 22 | this._options 23 | ) 24 | return this.send(url) 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /src/responses/assets-response.js: -------------------------------------------------------------------------------- 1 | import {default as AssetsHeader} from './headers/assets-header' 2 | import {default as ProtocolResponse} from './protocol-response' 3 | 4 | export default class AssetsResponse extends ProtocolResponse{ 5 | constructor(xmlDoc){ 6 | super(xmlDoc) 7 | 8 | let headerElem = xmlDoc.getElementsByTagName('Header')[0] 9 | this.header = new AssetsHeader(headerElem) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/responses/create-protocol-response.js: -------------------------------------------------------------------------------- 1 | import {default as AssetsResponse} from './assets-response' 2 | import {default as DevicesResponse} from './devices-response' 3 | import {default as ErrorResponse} from './error-response' 4 | import {default as StreamsResponse} from './streams-response' 5 | 6 | export default function CreateProtocolResponse(xmlDoc){ 7 | if(!xmlDoc || !xmlDoc.documentElement || !xmlDoc.documentElement.tagName){ 8 | throw new Error('Document is not a valid document.') 9 | } 10 | 11 | let documentTag = xmlDoc.documentElement.tagName 12 | 13 | if (documentTag === 'MTConnectDevices'){ 14 | return new DevicesResponse(xmlDoc) 15 | } 16 | else if(documentTag === 'MTConnectStreams'){ 17 | return new StreamsResponse(xmlDoc) 18 | } 19 | else if(documentTag === 'MTConnectAssets'){ 20 | return new AssetsResponse(xmlDoc) 21 | } 22 | else if(documentTag === 'MTConnectError'){ 23 | return new ErrorResponse(xmlDoc) 24 | } 25 | else{ 26 | throw new Error('Document is not a recognized MTConnect document.') 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/responses/devices-response.js: -------------------------------------------------------------------------------- 1 | import {default as DevicesHeader} from './headers/devices-header' 2 | import {default as ProtocolResponse} from './protocol-response' 3 | 4 | export default class DevicesResponse extends ProtocolResponse{ 5 | constructor(xmlDoc){ 6 | super(xmlDoc) 7 | 8 | let headerElem = xmlDoc.getElementsByTagName('Header')[0] 9 | this.header = new DevicesHeader(headerElem) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/responses/error-response.js: -------------------------------------------------------------------------------- 1 | import {default as ErrorHeader} from './headers/error-header' 2 | import {default as ProtocolResponse} from './protocol-response' 3 | 4 | export default class ErrorResponse extends ProtocolResponse{ 5 | constructor(xmlDoc){ 6 | super(xmlDoc) 7 | 8 | let headerElem = xmlDoc.getElementsByTagName('Header')[0] 9 | this.header = new ErrorHeader(headerElem) 10 | this.isError = true 11 | } 12 | } -------------------------------------------------------------------------------- /src/responses/headers/assets-header.js: -------------------------------------------------------------------------------- 1 | import {default as ProtocolHeader} from './protocol-header' 2 | 3 | export default class AssetsHeader extends ProtocolHeader{ 4 | constructor(xmlElem){ 5 | super(xmlElem) 6 | 7 | // Extract Assets attributes 8 | this.assetBufferSize = Number(xmlElem.getAttribute('assetBufferSize')) 9 | this.assetCount = Number(xmlElem.getAttribute('assetCount')) 10 | } 11 | } -------------------------------------------------------------------------------- /src/responses/headers/devices-header.js: -------------------------------------------------------------------------------- 1 | import {default as ProtocolHeader} from './protocol-header' 2 | 3 | export default class DevicesHeader extends ProtocolHeader{ 4 | constructor(xmlElem){ 5 | super(xmlElem) 6 | 7 | // Extract Devices attributes 8 | this.assetBufferSize = Number(xmlElem.getAttribute('assetBufferSize')) 9 | this.assetCount = Number(xmlElem.getAttribute('assetCount')) 10 | this.bufferSize = Number(xmlElem.getAttribute('bufferSize')) 11 | 12 | } 13 | } -------------------------------------------------------------------------------- /src/responses/headers/error-header.js: -------------------------------------------------------------------------------- 1 | import {default as ProtocolHeader} from './protocol-header' 2 | 3 | export default class ErrorHeader extends ProtocolHeader{ 4 | constructor(xmlElem){ 5 | super(xmlElem) 6 | 7 | // Extract Error attributes 8 | this.bufferSize = Number(xmlElem.getAttribute('bufferSize')) 9 | } 10 | } -------------------------------------------------------------------------------- /src/responses/headers/protocol-header.js: -------------------------------------------------------------------------------- 1 | export default class ProtocolHeader{ 2 | constructor(xmlElem){ 3 | this.xmlElement = xmlElem 4 | 5 | if(!xmlElem || ! xmlElem.getAttribute) throw new Error('Header element not valid.') 6 | 7 | // Extract common attributes 8 | this.creationTime = Date.parse(xmlElem.getAttribute('creationTime')) 9 | this.sender = xmlElem.getAttribute('sender') 10 | this.instanceId = Number(xmlElem.getAttribute('instanceId')) 11 | this.version = xmlElem.getAttribute('version') 12 | } 13 | } -------------------------------------------------------------------------------- /src/responses/headers/streams-header.js: -------------------------------------------------------------------------------- 1 | import {default as ProtocolHeader} from './protocol-header' 2 | 3 | export default class StreamsHeader extends ProtocolHeader{ 4 | constructor(xmlElem){ 5 | super(xmlElem) 6 | 7 | // Extract Streams attributes 8 | this.bufferSize = Number(xmlElem.getAttribute('bufferSize')) 9 | this.nextSequence = Number(xmlElem.getAttribute('nextSequence')) 10 | this.firstSequence = Number(xmlElem.getAttribute('firstSequence')) 11 | this.lastSequence = Number(xmlElem.getAttribute('lastSequence')) 12 | 13 | } 14 | } -------------------------------------------------------------------------------- /src/responses/protocol-response.js: -------------------------------------------------------------------------------- 1 | export default class ProtocolResponse{ 2 | constructor(xmlDoc){ 3 | this.xmlDocument = xmlDoc 4 | this.documentType = xmlDoc.documentElement.tagName 5 | this.isError = false 6 | } 7 | 8 | } 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/responses/streams-response.js: -------------------------------------------------------------------------------- 1 | import {default as StreamsHeader} from './headers/streams-header' 2 | import {default as ProtocolResponse} from './protocol-response' 3 | 4 | export default class StreamsResponse extends ProtocolResponse{ 5 | constructor(xmlDoc){ 6 | super(xmlDoc) 7 | 8 | let headerElem = xmlDoc.getElementsByTagName('Header')[0] 9 | this.header = new StreamsHeader(headerElem) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = { 4 | entry: './src/index.js', 5 | output: { 6 | path: path.join(__dirname, 'dist'), 7 | filename: 'bundle.js', 8 | library: 'MTConnect' 9 | }, 10 | module: { 11 | rules: [ 12 | { 13 | test: /.js$/, 14 | exclude: /(node_modules)/, 15 | loader: 'babel-loader' 16 | } 17 | ] 18 | } 19 | }; --------------------------------------------------------------------------------