Skip to content

Commit

Permalink
Refactor client setup #151 #148
Browse files Browse the repository at this point in the history
  • Loading branch information
fnoop committed Mar 5, 2020
1 parent 912a080 commit c00335c
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 72 deletions.
51 changes: 27 additions & 24 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,7 @@ export default {
// Watch apis state for any change and process
apis: {
handler: function (newValue) {
/*
// If any of the endpoints have changed, destroy and recreate the client
// this.deleteQueries(apiData.key)
delete this.$apollo.provider.clients[apiData.key]
this.createClient(apiData.key+'new', apiData)
*/
for (const api in this.apis) {
this.createQuery('Status', statusQuery, api, null, null, this.processStatusQuery)
this.createSubscription('Status', statusSubscription, api, null, null, this.processStatusSubscription)
}
this.createClients()
},
deep: true
}
Expand All @@ -96,24 +87,37 @@ export default {
mounted () {
this.logBanner('** Welcome to Maverick Web GCS **')
// Try to connect to the default -api client if one doesn't already exist
this.createDefaultClient()
this.createClients()
},
methods: {
checkApis () {
// If an api hasn't been seen for more than 10 seconds, mark it as dead
for (const api in this.apis) {
if (this.appVisible && performance.now() - this.$store.state.core.apiTimestamps[api] > 10000) {
this.logInfo(`deadapi? api: ${api}, timestamp: ${this.$store.state.core.apiTimestamps[api]}`)
this.$store.commit('data/setApiState', { api: api, value: false })
let lastseen = (this.apistate && this.apistate.hasOwnProperty(api)) ? this.apistate[api].lastseen : 0
if (this.appVisible && performance.now() - lastseen > 10000) {
this.logInfo(`deadapi? api: ${api}, timestamp: ${lastseen}`)
this.$store.commit('core/setApiState', { api: api, field: 'state', value: false })
}
}
},
createClients() {
// If there are any defined apis that don't have a corresponding client, create one
for (const api in this.apis) {
if (!this.$apollo.provider.clients.hasOwnProperty(api)) {
this.createClient(api, this.apis[api])
}
this.createQuery('Status', statusQuery, api, null, null, this.processStatusQuery)
this.createSubscription('Status', statusSubscription, api, null, null, this.processStatusSubscription)
}
},
/*
createDefaultClient() {
// Port 6800 is the default Flight Controller -api port in Maverick environment4
// Create a default client if it doesn't already exist
const hostname = window.location.hostname
const protocol = window.location.protocol
const wsprotocol = (protocol.includes("https")) ? 'wss:' : 'ws:'
// Port 6800 is the default Flight Controller -api port in Maverick environment4
const apiport = 6800
this.logDebug(`Creating default client:: hostname: ${hostname}, protocol: ${protocol}, wsprotocol: ${wsprotocol}`)
const clientData = {
Expand All @@ -135,25 +139,23 @@ export default {
this.createClient('default', clientData)
}
},
*/
processStatusQuery (data, key) {
const api = key.split('___')[0]
if (data.data && 'Status' in data.data) {
// Store the message data and set the api state to active, only for the first callback
// if (this.$store.state.core.apis[api].state !== true) this.$store.commit('data/setApiState', { api: api, value: true })
if (this.apis[api].state !== true) this.$store.commit('data/setApiState', { api: api, value: true })
if (this.apistate[api].state !== true) this.$store.commit('core/setApiState', { api: api, field: 'state', value: true })
// If the uuid for the api has not already been set, set it and create a VehicleInfo query (which needs the uuid to be created)
// if (!this.$store.state.core.apis[api].uuid) {
if (!this.apis[api].uuid) {
this.$store.commit('data/setApiUuid', { api: api, value: data.data.Status.id })
if (!this.apistate[api].uuid) {
this.$store.commit('core/setApiUuid', { api: api, value: data.data.Status.id })
}
// If the VehicleInfo query doesn't already exist for this client, create it
if (!(api + '___VehicleInfo___' in this.$apollo.queries)) {
if (this.verifyQuery(vehicleInfoQuery, api)) {
// this.createQuery('VehicleInfo', vehicleInfoQuery, api, null, !this.verifyQuery(vehicleInfoQuery, api), this.processVehicleInfoQuery, null, { uuid: this.$store.state.core.apis[api].uuid })
this.createQuery('VehicleInfo', vehicleInfoQuery, api, null, !this.verifyQuery(vehicleInfoQuery, api), this.processVehicleInfoQuery, null, { uuid: this.apis[api].uuid })
}
}
if (this.$store.state.core.apiTimestamps[api] === null) this.$store.commit('core/setApiSeen', { api: api, value: performance.now() })
if (this.apistate[api].lastseen === null) this.$store.commit('core/setApiState', {api: api, field: 'lastseen', value: performance.now() })
if (!(api in this.$store.state.core.statusData)) {
this.$store.commit('core/setStatusData', { api: api, message: data.data.Status })
}
Expand All @@ -163,7 +165,8 @@ export default {
const api = key.split('___')[0]
// Store the message data and set the api state to active, for subsequent subscription callbacks
// if (data.data && this.$store.state.core.apis[api].state !== true) this.$store.commit('data/setApiState', { api: api, value: true })
this.$store.commit('core/setApiSeen', { api: api, value: performance.now() })
// this.$store.commit('core/setApiSeen', { api: api, value: performance.now() })
this.$store.commit('core/setApiState', {api: api, field: 'lastseen', value: performance.now()})
if (data.data && this.$store.state.core.statusData[api] !== data.data.Status) {
this.$store.commit('core/setStatusData', { api: api, message: data.data.Status })
}
Expand All @@ -172,7 +175,7 @@ export default {
const api = key.split('___')[0]
if (!data.data) {
this.logInfo(`Invalid GraphQL 'VehicleInfo' data returned from api: ${api}`)
this.$store.commit('data/setApiState', { api: api, value: false })
this.$store.commit('core/setApiState', { api: api, field: 'state', value: false })
this.$store.commit('core/setVehicleData', { api: api, message: null })
return false
}
Expand Down
59 changes: 55 additions & 4 deletions src/components/modules/config/ConfigConnections.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ div
v-spacer
v-text-field(v-model="search" clearable flat solo-inverted hide-details prepend-inner-icon="mdi-magnify" label="Search")
v-spacer
v-btn(light @click.stop="dialog = true")
v-icon(left) mdi-plus-box
span Add API Connection

template(v-slot:default="{ items, isExpanded, expand }")
v-row
Expand Down Expand Up @@ -48,7 +51,31 @@ div
v-divider
v-list-item
v-btn(color='green' @click="save(item)") Save
v-btn.ml-2(color='blue') Connect
v-btn.ml-2(color='blue' @click="connect(item)") Connect

v-dialog(v-model="dialog" max-width="600px")
v-card
v-card-title.headline(:class="navColor" primary-title)
v-icon(left) mdi-plus-box
span Add API Connection
v-card-text
v-container
v-row
v-col(cols="12" sm="6" md="6")
v-text-field(v-model="newitem.key" label="API Key (Short)" required)
v-row
v-col(cols="12" sm="12" md="12")
v-text-field(v-model="newitem.name" label="API Name/Description" required)
v-row
v-col(cols="12" sm="12" md="12")
v-text-field(v-model="newitem.hostname" label="Hostname (FQDN) / IP Address" required)
v-row
v-col(cols="12" sm="12" md="12")
v-text-field(v-model="newitem.port" label="Port" required)
v-divider
v-card-actions
v-btn.ma-2(color="green" @click="createConnection()") Create Connection
v-btn.ma-2(color="grey" @click="dialog = false") Cancel
</template>

<script>
Expand All @@ -59,7 +86,9 @@ export default {
data() {
return {
search: '',
filter: {}
filter: {},
dialog: false,
newitem: {}
}
},
computed: {
Expand All @@ -75,9 +104,31 @@ export default {
// delete this.$apollo.provider.clients[apiData.key]
// this.createClient(apiData.key+'new', apiData)
},
connect() {
connect(apiData) {
this.logDebug('connecting')
this.logDebug(this.apis)
if (!(this.$apollo.provider.clients[apiData.key])) {
this.createClient(apiData.key, this.apis[apiData.key])
}
this.logDebug(this.$apollo.provider.clients)
},
createConnection() {
this.dialog = false // Close dialog
this.logDebug('Creating new connection: ' + this.newitem.key)
const protocol = 'http:'
const wsprotocol = (protocol.includes("https")) ? 'wss:' : 'ws:'
let data = {
key: this.newitem.key,
"httpEndpoint": `${protocol}//${this.newitem.hostname}:${this.newitem.port}/graphql`,
"wsEndpoint": `${wsprotocol}//${this.newitem.hostname}:${this.newitem.port}/subscriptions`,
"schemaEndpoint": `${protocol}//${this.newitem.hostname}:${this.newitem.port}/schema`,
"websocketsOnly": false,
"name": this.newitem.name,
"colorLight": "rgba(166,11,11,0.3)",
"colorDark": "rgba(166,11,11,0.9)",
"authToken": null
}
this.$store.commit('data/addApi', {key: data.key, data: data})
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/modules/config/ConfigParamSummary.vue
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export default {
// Store the message data and set the api state to active, only for the first callback
// if (this.$store.state.core.apis[api].state !== true) this.$store.commit('data/setApiState', { api: api, value: true })
if (this.apis[api].state !== true) this.$store.commit('data/setApiState', { api: api, value: true })
if (this.$store.state.core.apiTimestamps[api] === null) this.$store.commit('core/setApiSeen', { api: api, value: performance.now() })
if (this.apistate[api].lasteen === null) this.$store.commit('core/setApiState', { api: api, field: 'lastseen', value: performance.now() })
if (!(api in this.$store.state.statusData)) {
this.$store.commit('core/setStatusData', { api: api, message: data.data.Status })
}
Expand Down
9 changes: 4 additions & 5 deletions src/components/modules/config/ConfigVideo.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template lang='pug'>
div
v-data-iterator(:items="items" hide-default-footer single-expand=true)
v-data-iterator(:items="items" item-key="key" hide-default-footer :single-expand="expand")

template(v-slot:header)
v-toolbar.mb-1(:color="navColor" dark flat)
Expand All @@ -21,7 +21,7 @@ div
v-card-title.headline
span {{ item.name }}
div
v-switch.pl-4(:color="navColor" :input-value="isExpanded(item)" :label="isExpanded(item) ? 'Editing' : 'Edit'" @change="(v) => expand(item, v)")
v-switch.pl-4(:color="navColor" :input-value="isExpanded(item)" label="Edit" @change="(v) => expand(item, v)")
v-list(v-if="isExpanded(item)" dense)
v-list-item
v-divider
Expand Down Expand Up @@ -71,7 +71,8 @@ export default {
search: '',
filter: {},
dialog: false,
newitem: {}
newitem: {},
expand: true
}
},
computed: {
Expand All @@ -90,9 +91,7 @@ export default {
createStream() {
this.dialog = false // Close dialog
this.logDebug('Creating new video stream: ' + this.newitem.key)
this.logDebug(this.newitem)
this.$store.commit('data/addVideoStream', {key: this.newitem.key, data: this.newitem})
this.logDebug(this.$store.state.data.videostreams)
}
}
}
Expand Down
38 changes: 16 additions & 22 deletions src/plugins/core/CoreApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ const plugin = {
apis () {
return this.$store.state.data.apis
},
apistate() {
return this.$store.state.core.apiState
},
activeApi () {
return this.$store.state.core.activeApi
},
Expand Down Expand Up @@ -55,14 +58,6 @@ const plugin = {
if (newValue && this.$apollo) {
this.logInfo('App Visibility changed to Visible, turning on all GraphQL queries')
this.$apollo.skipAll = false
/*
for (const query in this.$apollo.queries) {
if (query != undefined) {
this.logDebug(query)
this.logDebug(this.$apollo.queries[query])
}
}
*/
} else if (this.$apollo) {
this.logInfo('App Visibility changed to Invisible, turning off all GraphQL queries')
this.$apollo.skipAll = true
Expand Down Expand Up @@ -90,6 +85,14 @@ const plugin = {
this.$store.commit('core/clearGraphqlVerified', api)
},

isApiReady (api) {
try {
return this.apistate[api].state === true && this.apistate[api].schemaready === true
} catch {
return false
}
},

verifyQuery (gql, api = this.activeApi, unknownDefault = false) {
let gqlHash = this.hashCode(print(gql))
let alreadyVerified = this.$store.getters['core/graphqlSchemaVerified'](api, gqlHash)
Expand Down Expand Up @@ -154,26 +157,18 @@ const plugin = {
this.logDebug(`Setting auth token: ${clientdata.authToken}`)
onLogin(client, clientdata.authToken, api, this.$store)
}
// Wait for the fetch to resolve before making the api
// accessable to the web app via the vuex store
// Wait for the fetch to resolve before setting the api state
await schemaFetchPromise
// Add a vuex apis entry
this.$store.commit('data/addApi', {
title: api,
value: { ...{ key: api, state: false, auth: false, icon: null, uuid: null }, ...clientdata }
})
this.$store.commit('core/addApiState', api)
this.$store.commit('core/setApiState', {api: api, field: 'schemaready', value: true})
},

createQuery (message, gql, api, container, skip = false, callback = null, errorCallback = null, variables = null) {
// Generate query key
const varvalues = variables && Object.values(variables) ? Object.values(variables).join('~') : ''
const queryKey = [api, message, varvalues].join('___')
// If a query with the calculated key doesn't exist, and the client appears to exist, then create the query
/*
this.logDebug(api)
this.logDebug(message)
this.logDebug(this.$root.$apollo.provider.clients)
*/
if (!this.$apollo.queries[queryKey] && this.$apollo.provider.clients[api]) {
this.logDebug(`Creating GQL Query: api: ${api}, message: ${message}, queryKey: ${queryKey}, container: ${container}`)
// If a callback function has been passed use it as the result processor, otherwise use a default function
Expand All @@ -183,7 +178,7 @@ const plugin = {
// Store the message data and set the api state to active
// Note: Must use this.$set to add object property, to keep new property reactive
this.$set(this[container], cbapi, data.data[message])
this.$store.commit('data/setApiState', { api: cbapi, value: true })
this.$store.commit('core/setApiState', { api: cbapi, field: 'state', value: true })
}
}
let queryFields = {
Expand Down Expand Up @@ -218,9 +213,8 @@ const plugin = {
if (data.data && message in data.data && this[container][cbapi] !== data.data[message]) {
// Store the message data and set the api state to active
this[container][cbapi] = data.data[message]
// if (this.$store && this.$store.state.core.apis[cbapi] && !this.$store.state.core.apis[cbapi].state && message in data.data) {
if (this.$store && this.apis[cbapi] && !this.apis[cbapi].state && message in data.data) {
this.$store.commit('data/setApiState', { api: cbapi, value: true })
this.$store.commit('core/setApiState', { api: cbapi, field: 'state', value: true })
}
}
}
Expand Down
18 changes: 15 additions & 3 deletions src/store/modules/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import axios from 'axios'
// This vuex module contains data that should *not* be persisted

const state = {
apiTimestamps: {},
apiState: {},
statusData: {},
vehicleData: {},
activeApi: null,
Expand Down Expand Up @@ -54,8 +54,20 @@ const mutations = {
setActiveApi (state, api) {
state.activeApi = api
},
setApiSeen (state, data) {
state.apiTimestamps[data.api] = data.value
addApiState (state, api) {
Vue.set(state.apiState, api, {state: false, schemaready: false, auth: false, uuid: null, icon: null, lastseen: null})
},
setApiState (state, data) {
state.apiState[data.api][data.field] = data.value
},
setApiUuid (state, data) {
state.apiState[data.api].uuid = data.value
},
setApiIcon (state, data) {
state.apiState[data.api].icon = data.value
},
setApiAuth (state, data) {
state.apiState[data.api].auth = data.value
},
setStatusData (state, data) {
if (data.api in state.statusData) {
Expand Down
14 changes: 1 addition & 13 deletions src/store/modules/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,11 @@ const state = {

const mutations = {
addApi (state, data) {
Vue.set(state.apis, data.title, data.value)
Vue.set(state.apis, data.key, data.data)
},
setApiData (state, data) {
state.apis[data.api] = data.data
},
setApiState (state, data) {
state.apis[data.api].state = data.value
},
setApiUuid (state, data) {
state.apis[data.api].uuid = data.value
},
setApiIcon (state, data) {
state.apis[data.api].icon = data.value
},
setApiAuth (state, data) {
state.apis[data.api].auth = data.value
},
setDarkUi (state, value) {
state.darkUi = value
},
Expand Down

0 comments on commit c00335c

Please sign in to comment.