diff --git a/src/backend/Api.ts b/src/backend/Api.ts index b3c9651..50639c4 100644 --- a/src/backend/Api.ts +++ b/src/backend/Api.ts @@ -19,7 +19,7 @@ let tdConsumer: null | TdConsumer = null; export function retrieveProtocols(td: string): ProtocolEnum[] | null { const protocols = [] as ProtocolEnum[]; - let tdJson; + let tdJson: { properties: any; actions: any; events: any; base: string | string[]; }; try { tdJson = JSON.parse(td); } catch (error) { @@ -122,6 +122,13 @@ export async function consumeAndParseTd( }; } +export async function fetchTD(uri: string) { + if (!tdConsumer) { + tdConsumer = new TdConsumer('', null, ['']); + } + return tdConsumer.fetchTD(uri); +} + export async function resetAll() { // TODO: // delete TdConsumer @@ -255,7 +262,7 @@ export async function invokeInteractions(selectedInteractions) { case PossibleInteractionTypesEnum.ACTION: if (interactionSelectBtn.interaction) { - // Invoke action (possibily with input) + // Invoke action (possibly with input) const resultAction = await selectedInteractions[ interaction ].interactionSelectBtn.interaction(interactionSelectBtn.input); @@ -310,7 +317,7 @@ export function removeVt(VT: VtCall) { VT.stopVt().then( () => { VT = null as any; - res(); + res(true); }, err => { rej(err); diff --git a/src/backend/TdConsumer.ts b/src/backend/TdConsumer.ts index a98b0c3..46abbe3 100644 --- a/src/backend/TdConsumer.ts +++ b/src/backend/TdConsumer.ts @@ -1,12 +1,11 @@ -import { Servient } from '@node-wot/core'; +import { Servient, Helpers } from '@node-wot/core'; import { HttpClientFactory, HttpsClientFactory } from '@node-wot/binding-http'; -import { CoapClientFactory, CoapsClientFactory, CoapServer } from '@node-wot/binding-coap'; +import { CoapClientFactory, CoapsClientFactory } from '@node-wot/binding-coap'; import { MqttClientFactory, MqttBrokerServer } from '@node-wot/binding-mqtt'; // import { WebSocketClientFactory, WebSocketSecureClientFactory } from '@node-wot/binding-websockets'; import { TdStateEnum } from '@/util/enums'; import * as WoT from 'wot-typescript-definitions'; - export default class TdConsumer { // default coap port = 5683; // default mqtt port = 1883; @@ -20,7 +19,8 @@ export default class TdConsumer { private tdState: TdStateEnum | null; private errorMsg: string | null; - private servient: any | null; // TODO: there is no servient type in wot-typescript-definitions + private servient: Servient; + private helper: Helpers; constructor(td: string, config: any, protocols: string[]) { this.td = td; @@ -30,7 +30,15 @@ export default class TdConsumer { this.tdConsumed = null; this.tdState = null; this.errorMsg = null; - this.servient = null; + // instantiate Servient and Helper + this.servient = new Servient(); + this.helper = new Helpers(this.servient); + // Add all ClientFactories + this.servient.addClientFactory(new CoapClientFactory()); + this.servient.addClientFactory(new CoapsClientFactory()); + this.servient.addClientFactory(new HttpClientFactory({})); + this.servient.addClientFactory(new HttpsClientFactory({})); + this.servient.addClientFactory(new MqttClientFactory()); } public setConsumer(td: string, config: any, protocols: string[]) { @@ -78,26 +86,49 @@ export default class TdConsumer { } } + /** A method that fetches a TD using node-wot fetch API. + * The method takes a URI string as input and returns a Promise of a WoT.ThingDescription. + * If no connection is established for 3 seconds, the fetching times out and throws "Fetching Timed Out". + * Otherwise, if any other error occurs, the fetching is initiated upto 3 times. + * If the error is persists, the error is thrown + * @param uri A uri string that represents that represents the TD resource + */ + async fetchTD(uri: string) { + let errorCount = 0 + let helper = this.helper; + let errorMsg: string | Error | null = null; + let td: WoT.ThingDescription; + return new Promise(async (resolve, reject) => { + setTimeout(() => { + reject("Fetching Timed Out"); + },3000); + do { + try { + td = await helper.fetch(uri) + if(td) return resolve(td); else errorCount++; + } catch (err) { + errorMsg = err; + errorCount++; + } + } while(errorCount <= 3) + reject(errorMsg); + }) + } + // Tries to consume given td json object private async consumeThing() { - // console.log('servient:', this.servient); - // if (this.servient) this.servient.shutdown(); - this.servient = new Servient(); - - // Get config of td, possibly altered by user if (this.config && this.config.credentials) this.servient.addCredentials(this.config.credentials); - // Now check which ClientFactories need to be added (based on the given protocols) - + // perform mqtt specific operations if required if (this.protocols.indexOf('mqtt') !== -1) { if (!this.config || !this.config.mqtt) { - // mqtt config was found -> cannot connect to broker + // mqtt config was not found -> cannot connect to broker this.tdState = TdStateEnum.INVALID_CONSUMED_TD; this.errorMsg = 'No mqtt broker credentials were found in config'; return; } - // Set mqtt config from config (possibily entered by user) + // Set mqtt config from config (possibly entered by user) const MQTT_CONFIG: WADE.MqttConfigInterface = { broker: this.config.mqtt.broker || '', username: this.config.mqtt.username || undefined, @@ -113,24 +144,6 @@ export default class TdConsumer { MQTT_CONFIG.clientId ); this.servient.addServer(mqttBrokerServer); - - await this.servient.addClientFactory(new MqttClientFactory()); - } - - if (this.protocols.indexOf('coap') !== -1) { - await this.servient.addClientFactory(new CoapClientFactory()); - } - - if (this.protocols.indexOf('coaps') !== -1) { - await this.servient.addClientFactory(new CoapsClientFactory()); - } - - if (this.protocols.indexOf('http') !== -1) { - await this.servient.addClientFactory(new HttpClientFactory({})); - } - - if (this.protocols.indexOf('https') !== -1) { - await this.servient.addClientFactory(new HttpsClientFactory({})); } // await servient.addClientFactory(new WebSocketClientFactory()); diff --git a/src/components/02_molecules/mUrlBar.vue b/src/components/02_molecules/mUrlBar.vue index d63daaa..6635f57 100644 --- a/src/components/02_molecules/mUrlBar.vue +++ b/src/components/02_molecules/mUrlBar.vue @@ -8,7 +8,7 @@ :btnClass="button.btnClass" :btnLabel="button.btnLabel" :btnOnClick="button.btnOnClick" - :btnActive="urlValid" + :btnActive="true" /> diff --git a/src/components/04_templates/tThingDescription.vue b/src/components/04_templates/tThingDescription.vue index b423337..248e2ad 100644 --- a/src/components/04_templates/tThingDescription.vue +++ b/src/components/04_templates/tThingDescription.vue @@ -71,9 +71,8 @@ import oSelection from '@/components/03_organisms/oSelection.vue'; import oResults from '@/components/03_organisms/oResults.vue'; import oProtocolSelection from '@/components/03_organisms/oProtocolSelection.vue'; import tPerformance from '@/components/04_templates/tPerformance.vue'; -import { Url } from 'url'; import { TdStateEnum, TDTabsEnum } from '../../util/enums'; -import { ftruncate } from 'fs'; +import * as Api from '@/backend/Api'; export default Vue.extend({ name: 'tThingDescription', @@ -109,36 +108,6 @@ export default Vue.extend({ btnClass: 'btn-url-bar', btnOnClick: 'btn-clicked' }, - async fetchFunction(url: string) { - // TODO: Error Handling connection time out - let td: null | string = null; - let errorMsg: null | string = null; - let tdState: null | TdStateEnum = null; - const fetchedTd = await fetch(url) - .then(response => { - return response.json(); - }) - .then(myJson => { - td = JSON.stringify(myJson); - tdState = TdStateEnum.VALID_TD_FETCHED; - return { - td, - tdState, - errorMsg - }; - }) - .catch(err => { - errorMsg = err; - tdState = TdStateEnum.INVALID_TD_FETCHED; - td = null; - return { - td, - tdState, - errorMsg - }; - }); - (this as any).$eventHub.$emit('fetched-td', fetchedTd); - } }; }, computed: { @@ -150,6 +119,7 @@ export default Vue.extend({ }, methods: { ...mapMutations('TdStore', ['setActiveTab']), + ...mapActions('TdStore',['fetchTD']), hideUrlBar() { if (this.showUrlBar) this.showUrlBar = false; }, @@ -168,7 +138,12 @@ export default Vue.extend({ tabbarKey: 'tdTabs', activeTab: this.currentTabId }); - } + }, + async fetchFunction(url: string) { + (this as any).fetchTD({uri: url}).then((fetchedTd) => { + if(fetchedTd) (this as any).$eventHub.$emit('fetched-td', fetchedTd); + }) + } }, watch: { // Check if router id changed and change active sidebar element diff --git a/src/store/modules/td.ts b/src/store/modules/td.ts index 2a7c160..0969d14 100644 --- a/src/store/modules/td.ts +++ b/src/store/modules/td.ts @@ -1,8 +1,6 @@ import * as Api from '@/backend/Api'; import { RESULT_MESSAGES, VtStatus } from '@/util/enums'; import { InteractionStateEnum, TdStateEnum, ProtocolEnum } from '@/util/enums'; -import * as stream from 'stream'; -import VtCall from '@/backend/VtCall'; export default { namespaced: true, @@ -89,6 +87,40 @@ export default { tdEditorPlaceholder: 'Paste your Thing Description here or press the upload button.' }, actions: { + /** An action that fetches an TD and updates the status bar if an error occurs + * + * @param payload an object that includes the property uri, which is a the string of the URI for the TD resource + */ + async fetchTD({ commit, state }, payload: {uri: string}) { + commit('setTdState', TdStateEnum.TD_FETCHING); + commit('setErrorMsg', null); + commit('setInteractionState', null); + commit('setStatusMessage'); + return Api.fetchTD(payload.uri).then(myJson => { + let td = JSON.stringify(myJson); + let tdState = TdStateEnum.VALID_TD_FETCHED; + let errorMsg = null; + let fetchedTd = { + td, + tdState, + errorMsg + }; + console.log(fetchedTd); + commit('setTdState', tdState); + commit('setErrorMsg', null); + commit('setInteractionState', null); + commit('setStatusMessage'); + return fetchedTd; + }) + .catch( (err) => { + let tdState = TdStateEnum.INVALID_TD_FETCHED; + commit('setTdState', tdState); + commit('setErrorMsg', err); + commit('setInteractionState', null); + commit('setStatusMessage'); + } + ) + }, async processChangedTd({ commit, state }, payload: any) { // Do not consume td when its empty or not in correct format if (!payload.td || payload.td.length <= 0) { diff --git a/src/util/enums.ts b/src/util/enums.ts index ceb690d..aaa53ba 100644 --- a/src/util/enums.ts +++ b/src/util/enums.ts @@ -53,7 +53,8 @@ export enum TdStateEnum { INVALID_TD_EMPTY = 'INVALID TD: TD may not be empty object.', INVALID_CONSUMED_TD = 'CONSUME ERROR: TD could not be consumed.', INVALID_TD = 'INVALID TD: TD is invalid.', - VALID_TD = 'VALID TD: TD is valid.' + VALID_TD = 'VALID TD: TD is valid.', + TD_FETCHING = 'FETCHING TD...' } export enum TdConfigEnum { diff --git a/yarn.lock b/yarn.lock index 865a86c..9ee585f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2230,9 +2230,9 @@ babel-plugin-module-resolver@3.2.0: resolve "^1.4.0" babel-plugin-polyfill-corejs2@^0.1.4: - version "0.1.9" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.9.tgz#eb1634b8b17b71567f955787bd05b05f5de856b7" - integrity sha512-+QMb65TxS4ue/mSJmd0M3BofCNcbsq49Pxij3X2mFjVhpwm81gYpmaHEc+GJgRzFrLaWjFbTC+kvVrmeRjwsCA== + version "0.1.10" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.10.tgz#a2c5c245f56c0cac3dbddbf0726a46b24f0f81d1" + integrity sha512-DO95wD4g0A8KRaHKi0D51NdGXzvpqVLnLu5BTvDlpqUEpTmeEtypgC1xqesORaWmiUOQI14UHKlzNd9iZ2G3ZA== dependencies: "@babel/compat-data" "^7.13.0" "@babel/helper-define-polyfill-provider" "^0.1.5" @@ -4677,14 +4677,14 @@ electron-store@^2.0.0: conf "^2.0.0" electron-to-chromium@^1.3.649: - version "1.3.677" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.677.tgz#b5d586b0d1976c97cc7e95262677ac5944199513" - integrity sha512-Tcmk+oKQgpjcM+KYanlkd76ZtpzalkpUULnlJDP6vjHtR7UU564IM9Qv5DxqHZNBQjzXm6mkn7Y8bw2OoE3FmQ== + version "1.3.679" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.679.tgz#69b45bbf1e0bc2320cb1f3e65b9283e86c4d5e2f" + integrity sha512-PNF7JSPAEa/aV2nQLvflRcnIMy31EOuCY87Jbdz0KsUf8O/eFNGpuwgQn2DmyJkKzfQb0zrieanRGWvf/4H+BA== electron@^9.1.0: - version "9.4.3" - resolved "https://registry.yarnpkg.com/electron/-/electron-9.4.3.tgz#9fb6c0a900bdf80cc473def9fbcc8c213a9e7e74" - integrity sha512-FQjVH0jdFj9EIxpHk/CK6nKmPawdayZ01N+o0sVHAGK0qcvTVCkBZT/1qbsJaTBPD1yf3PcN2frpwfTDBCn9GA== + version "9.4.4" + resolved "https://registry.yarnpkg.com/electron/-/electron-9.4.4.tgz#2a74a0655a74bd326216672c5ae6ed3a44451446" + integrity sha512-dcPlTrMWQu5xuSm6sYV42KK/BRIqh3erM8v/WtZqaDmG7pkCeJpvw26Dgbqhdt78XmqqGiN96giEe6A3S9vpAQ== dependencies: "@electron/get" "^1.0.1" "@types/node" "^12.0.12" @@ -8390,9 +8390,9 @@ no-case@^2.2.0: lower-case "^1.1.1" node-abi@^2.7.0: - version "2.19.3" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.19.3.tgz#252f5dcab12dad1b5503b2d27eddd4733930282d" - integrity sha512-9xZrlyfvKhWme2EXFKQhZRp1yNWT/uI1luYPr3sFl+H4keYY4xR+1jO7mvTTijIsHf1M+QDe9uWuKeEpLInIlg== + version "2.20.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.20.0.tgz#0659ee1a4a04dacabd3ac4429fac6297ed58e92e" + integrity sha512-6ldtfVR5l3RS8D0aT+lj/uM2Vv/PGEkeWzt2tl8DFBsGY/IuVnAIHl+dG6C14NlWClVv7Rn2+ZDvox+35Hx2Kg== dependencies: semver "^5.4.1" @@ -12634,9 +12634,9 @@ vue-router@^3.1.3: integrity sha512-RRQNLT8Mzr8z7eL4p7BtKvRaTSGdCbTy2+Mm5HTJvLGYSSeG9gDzNasJPP/yOYKLy+/cLG/ftrqq5fvkFwBJEw== vue-style-loader@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/vue-style-loader/-/vue-style-loader-4.1.2.tgz#dedf349806f25ceb4e64f3ad7c0a44fba735fcf8" - integrity sha512-0ip8ge6Gzz/Bk0iHovU9XAUQaFt/G2B61bnWa2tCcqqdgfHs1lF9xXorFbE55Gmy92okFT+8bfmySuUOu13vxQ== + version "4.1.3" + resolved "https://registry.yarnpkg.com/vue-style-loader/-/vue-style-loader-4.1.3.tgz#6d55863a51fa757ab24e89d9371465072aa7bc35" + integrity sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg== dependencies: hash-sum "^1.0.2" loader-utils "^1.0.2"