mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
sse: properly handle sse opening/closing
This commit is contained in:
parent
0b1030a2fb
commit
2d78749c1d
4 changed files with 39 additions and 41 deletions
|
@ -81,7 +81,6 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import { connectSSE } from '@/api/handlers'
|
|
||||||
import { HistoryConsole, ViewLockOverlay } from '@/views/_partials'
|
import { HistoryConsole, ViewLockOverlay } from '@/views/_partials'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -118,7 +117,7 @@ export default {
|
||||||
// state will be automaticly reseted and user will be prompt with the login view.
|
// state will be automaticly reseted and user will be prompt with the login view.
|
||||||
if (this.connected) {
|
if (this.connected) {
|
||||||
this.$store.dispatch('GET_YUNOHOST_INFOS')
|
this.$store.dispatch('GET_YUNOHOST_INFOS')
|
||||||
connectSSE()
|
this.$store.dispatch('SSE_CONNECT')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
import { openWebSocket, getResponseData, handleError } from './handlers'
|
import { getResponseData, handleError } from './handlers'
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -24,40 +24,6 @@ export async function getResponseData (response) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a WebSocket connection to the server in case it sends messages.
|
|
||||||
* Currently, the connection is closed by the server right after an API call so
|
|
||||||
* we have to open it for every calls.
|
|
||||||
* Messages are dispatch to the store so it can handle them.
|
|
||||||
*
|
|
||||||
* @param {Object} request - Request info data.
|
|
||||||
* @return {Promise<Event>} Promise that resolve on websocket 'open' or 'error' event.
|
|
||||||
*/
|
|
||||||
export function openWebSocket (request) {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const ws = new WebSocket(`wss://${store.getters.host}/yunohost/api/messages`)
|
|
||||||
ws.onmessage = ({ data }) => {
|
|
||||||
store.dispatch('DISPATCH_MESSAGE', { request, messages: JSON.parse(data) })
|
|
||||||
}
|
|
||||||
// ws.onclose = (e) => {}
|
|
||||||
ws.onopen = resolve
|
|
||||||
// Resolve also on error so the actual fetch may be called.
|
|
||||||
ws.onerror = resolve
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function connectSSE () {
|
|
||||||
const host = store.getters.host.split(':')[0]
|
|
||||||
const evtSource = new EventSource(`https://${host}/yunohost/api/sse`)
|
|
||||||
|
|
||||||
evtSource.onmessage = (event) => {
|
|
||||||
store.dispatch('ON_SSE_MESSAGE', JSON.parse(atob(event.data)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME handle 'onerror' hook
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for API errors.
|
* Handler for API errors.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,13 +2,13 @@ import Vue from 'vue'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
import i18n from '@/i18n'
|
import i18n from '@/i18n'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { connectSSE } from '@/api/handlers'
|
|
||||||
import { timeout, isEmptyValue, isObjectLiteral } from '@/helpers/commons'
|
import { timeout, isEmptyValue, isObjectLiteral } from '@/helpers/commons'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
state: {
|
state: {
|
||||||
host: window.location.host, // String
|
host: window.location.host, // String
|
||||||
connected: localStorage.getItem('connected') === 'true', // Boolean
|
connected: localStorage.getItem('connected') === 'true', // Boolean
|
||||||
|
sse: null, // EventSource
|
||||||
yunohost: null, // Object { version, repo }
|
yunohost: null, // Object { version, repo }
|
||||||
waiting: false, // Boolean
|
waiting: false, // Boolean
|
||||||
reconnecting: null, // null|Object { attemps, delay, initialDelay }
|
reconnecting: null, // null|Object { attemps, delay, initialDelay }
|
||||||
|
@ -28,6 +28,17 @@ export default {
|
||||||
state.connected = boolean
|
state.connected = boolean
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'SET_SSE_SOURCE' (state, sse) {
|
||||||
|
state.sse = sse
|
||||||
|
},
|
||||||
|
|
||||||
|
'CLOSE_SSE_SOURCE' (state) {
|
||||||
|
if (state.sse) {
|
||||||
|
state.sse.close()
|
||||||
|
state.sse = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
'SET_YUNOHOST_INFOS' (state, yunohost) {
|
'SET_YUNOHOST_INFOS' (state, yunohost) {
|
||||||
state.yunohost = yunohost
|
state.yunohost = yunohost
|
||||||
},
|
},
|
||||||
|
@ -123,13 +134,30 @@ export default {
|
||||||
|
|
||||||
'CONNECT' ({ commit, dispatch }) {
|
'CONNECT' ({ commit, dispatch }) {
|
||||||
commit('SET_CONNECTED', true)
|
commit('SET_CONNECTED', true)
|
||||||
connectSSE()
|
|
||||||
dispatch('GET_YUNOHOST_INFOS')
|
dispatch('GET_YUNOHOST_INFOS')
|
||||||
|
dispatch('SSE_CONNECT')
|
||||||
|
},
|
||||||
|
|
||||||
|
'SSE_CONNECT' ({ commit, dispatch }) {
|
||||||
|
const sse = new EventSource(`/yunohost/api/sse`, { withCredentials: true })
|
||||||
|
|
||||||
|
sse.onopen = () => {
|
||||||
|
commit('SET_SSE_SOURCE', sse)
|
||||||
|
console.log('connected')
|
||||||
|
};
|
||||||
|
|
||||||
|
sse.onmessage = (event) => {
|
||||||
|
dispatch('ON_SSE_MESSAGE', JSON.parse(atob(event.data)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// sse.onerror = (event) => {
|
||||||
|
// }
|
||||||
},
|
},
|
||||||
|
|
||||||
'RESET_CONNECTED' ({ commit }) {
|
'RESET_CONNECTED' ({ commit }) {
|
||||||
commit('SET_CONNECTED', false)
|
commit('SET_CONNECTED', false)
|
||||||
commit('SET_YUNOHOST_INFOS', null)
|
commit('SET_YUNOHOST_INFOS', null)
|
||||||
|
commit('CLOSE_SSE_SOURCE')
|
||||||
},
|
},
|
||||||
|
|
||||||
'DISCONNECT' ({ dispatch }, route = router.currentRoute) {
|
'DISCONNECT' ({ dispatch }, route = router.currentRoute) {
|
||||||
|
@ -249,7 +277,13 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
async 'ON_SSE_MESSAGE' ({ state, commit, dispatch }, data) {
|
async 'ON_SSE_MESSAGE' ({ state, commit, dispatch }, data) {
|
||||||
let action = state.history.findLast((action) => action.operationId === data.operation_id)
|
let action
|
||||||
|
if (data.type === 'start') {
|
||||||
|
action = state.requests.findLast((request) => request.status === 'pending')
|
||||||
|
} else {
|
||||||
|
action = state.history.findLast((action) => action.operationId === data.operation_id)
|
||||||
|
}
|
||||||
|
|
||||||
if (!action) {
|
if (!action) {
|
||||||
action = await dispatch('START_EXTERNAL_ACTION', { operationId: data.operation_id, timestamp: data.timestamp })
|
action = await dispatch('START_EXTERNAL_ACTION', { operationId: data.operation_id, timestamp: data.timestamp })
|
||||||
}
|
}
|
||||||
|
@ -288,7 +322,6 @@ export default {
|
||||||
}
|
}
|
||||||
commit('ADD_TEMP_MESSAGE', { request: action, message, type })
|
commit('ADD_TEMP_MESSAGE', { request: action, message, type })
|
||||||
}
|
}
|
||||||
action.messages.push(message)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue