Skip to content

Commit 9b38a8c

Browse files
committed
Improve session connection monitoring and reconnection
1 parent 8a8fe8d commit 9b38a8c

File tree

5 files changed

+87
-69
lines changed

5 files changed

+87
-69
lines changed

presenter-app/src/common/ApiService.js

+33-14
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const {
1515

1616
let evtSource = null;
1717
let sseReconnectFrequencySeconds = 1;
18+
let shouldCloseEvtSource = false;
1819

1920
const axiosInstance = axios.create({
2021
baseURL: `${apiEndpoint}/${apiVersion}`,
@@ -39,15 +40,18 @@ const ApiService = {
3940

4041
if (process.type === "main") {
4142
ipcMain.on("CONNECT_EVENT_STREAM", (evt, args) => this.onConnectEventStream());
42-
ipcMain.on("CLOSE_EVENT_STREAM", (evt, args) => {
43-
if (evtSource) evtSource.close();
44-
});
43+
ipcMain.on("CLOSE_EVENT_STREAM", (evt, args) => this.onCloseEventStream());
4544
}
4645

47-
if(store.getters.activeSession.id !== "")
48-
this.connectEventStream();
46+
if (store.getters.activeSession.id !== "") this.connectEventStream();
4947
},
5048

49+
/**
50+
* Create a new session on the server
51+
*
52+
* @param {{id}[]} votingOptions for the sessions
53+
* @returns {{sessionId:String, accessToken:{}}} session data
54+
*/
5155
async joinSession(votingOptions) {
5256
const { data } = await axiosInstance.post("sessions", {
5357
votingOptions: votingOptions.map(x => x.id),
@@ -56,6 +60,11 @@ const ApiService = {
5660
return data;
5761
},
5862

63+
/**
64+
* Abandon a session on the server
65+
*
66+
* @param {String} sessionId
67+
*/
5968
async leaveSession(sessionId) {
6069
await axiosInstance.delete(`sessions/${sessionId}`, {
6170
headers: { Authorization: `Bearer ${store.getters.accessToken}` },
@@ -78,22 +87,32 @@ const ApiService = {
7887
return;
7988
}
8089

90+
this.onCloseEventStream();
91+
},
92+
93+
onCloseEventStream() {
94+
shouldCloseEvtSource = true;
8195
if (evtSource) evtSource.close();
96+
store.dispatch("updateSessionStreamState", null);
97+
console.log("stream closed");
8298
},
8399

84100
onConnectEventStream() {
85101
console.log("Connecting eventstream");
102+
shouldCloseEvtSource = false;
86103
const waitFunc = () => sseReconnectFrequencySeconds * 1000;
87104
const tryToSetupFunc = () => {
88-
setupEventSource();
89-
sseReconnectFrequencySeconds *= 2;
90-
if (sseReconnectFrequencySeconds >= 64) {
91-
sseReconnectFrequencySeconds = 64;
105+
if (!shouldCloseEvtSource) {
106+
setupEventSource();
107+
sseReconnectFrequencySeconds *= 2;
108+
if (sseReconnectFrequencySeconds >= 64) {
109+
sseReconnectFrequencySeconds = 64;
110+
}
92111
}
93112
};
94113

95114
const setupEventSource = () => {
96-
if(evtSource) evtSource.close();
115+
if (evtSource) evtSource.close();
97116

98117
evtSource = new EventSource(`${streamEndpoint}?access_token=${store.getters.accessToken}`, {
99118
withCredentials: true,
@@ -113,12 +132,12 @@ const ApiService = {
113132
this.closeEventStream();
114133
});
115134

116-
evtSource.onopen = (e) => {
135+
evtSource.onopen = e => {
117136
sseReconnectFrequencySeconds = 1;
118-
console.log("Eventstream opened", {e});
137+
console.log("Eventstream opened", { e });
119138
};
120-
evtSource.onerror = (e) => {
121-
console.log("Eventstream error", {e});
139+
evtSource.onerror = e => {
140+
console.log("Eventstream error", { e });
122141
evtSource.close();
123142
store.dispatch("updateSessionStreamState", false);
124143
setTimeout(tryToSetupFunc, waitFunc());

presenter-app/src/components/SessionHealth.vue

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
<template>
22
<div>
3-
<div class="tags has-addons">
3+
<div v-if="sessionStream.connected" class="tags has-addons">
44
<span
55
:class="sessionStream.connected ? 'tag is-success' : 'tag is-danger'"
66
>{{ sessionStream.connected ? 'Connected' : 'Connecting...' }}</span>
7-
<span class="tag connectBtn" @click="connectEventStream()" title="Reconnect">
7+
<span
8+
class="tag has-background-grey-lighter has-text-primary connectBtn"
9+
@click="connectEventStream()"
10+
title="Reconnect"
11+
>
812
<b-icon icon="undo" size="is-small" />
913
</span>
1014
</div>
15+
<div v-else class="tags has-addons">
16+
<span
17+
class="tag is-success"
18+
>Ready</span>
19+
</div>
1120
</div>
1221
</template>
1322

presenter-app/src/main.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ import {
2323
faAsterisk,
2424
faInfoCircle,
2525
faSpinner,
26+
faExternalLinkAlt,
2627

2728
} from "@fortawesome/free-solid-svg-icons";
2829

2930
import {
30-
31+
faHeart,
3132
} from "@fortawesome/free-regular-svg-icons";
3233

3334
library.add(
@@ -44,6 +45,8 @@ library.add(
4445
faAsterisk,
4546
faInfoCircle,
4647
faSpinner,
48+
faExternalLinkAlt,
49+
faHeart
4750
);
4851

4952
import "@/assets/scss/plodo.scss";

presenter-app/src/store/index.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ export default new Vuex.Store({
7070
actions: {
7171
async createSession({ commit, dispatch, getters }, { votingOptions }) {
7272
try {
73-
const data = await ApiService.joinSession(votingOptions);
73+
const {sessionId, accessToken} = await ApiService.joinSession(votingOptions);
7474

75-
commit("setToken", { token: data.accessToken.token });
76-
commit("setSession", { sessionId: data.sessionId, votingOptions: votingOptions });
75+
commit("setToken", { token: accessToken.token });
76+
commit("setSession", { sessionId: sessionId, votingOptions: votingOptions });
7777

7878
ApiService.connectEventStream();
7979
} catch (e) {

presenter-app/src/views/PlayingSession.vue

+36-49
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,9 @@
33
<div class="level is-mobile">
44
<div class="level-left">
55
<div class="level-item">
6-
<b-icon
7-
class="has-text-secondary"
8-
icon="asterisk"
9-
size="is-small"
10-
/>
11-
</div>
12-
<div class="level-item has-text-secondary has-text-weight-bold">
13-
Session ID
6+
<b-icon class="has-text-secondary" icon="asterisk" size="is-small" />
147
</div>
8+
<div class="level-item has-text-secondary has-text-weight-bold">Session ID</div>
159
</div>
1610
<div class="level-right">
1711
<div class="level-item">
@@ -20,74 +14,59 @@
2014
class="button is-family-monospace has-text-secondary has-text-weight-bold"
2115
title="Copy to clipboard"
2216
@click="copySessionId()"
23-
>
24-
{{ activeSession.id }}
25-
</button>
17+
>{{ activeSession.id }}</button>
2618
<button
2719
class="button has-text-secondary"
2820
title="Copy to clipboard"
2921
@click="copySessionId()"
3022
>
31-
<b-icon
32-
icon="copy"
33-
size="is-small"
34-
/>
23+
<b-icon icon="copy" size="is-small" />
24+
</button>
25+
<button
26+
class="button has-text-grey"
27+
title="Open in browser"
28+
@click="openSessionInBrowser()"
29+
>
30+
<b-icon icon="external-link-alt" size="is-small" />
3531
</button>
3632
</div>
3733
</div>
3834
</div>
3935
</div>
40-
<hr>
36+
<hr />
4137
<div class="level is-mobile">
4238
<div class="level-left">
4339
<div class="level-item">
44-
<b-icon
45-
icon="info-circle"
46-
size="is-small"
47-
/>
48-
</div>
49-
<div class="level-item">
50-
Status
40+
<b-icon class icon="tv" size="is-small" />
5141
</div>
42+
<div class="level-item">Screen</div>
5243
</div>
5344
<div class="level-right">
5445
<div class="level-item">
55-
<session-health />
46+
<screen-selection-dropdown />
5647
</div>
5748
</div>
5849
</div>
5950
<div class="level is-mobile">
6051
<div class="level-left">
6152
<div class="level-item">
62-
<b-icon
63-
icon="tv"
64-
size="is-small"
65-
/>
66-
</div>
67-
<div class="level-item">
68-
Celebration
53+
<b-icon icon="heart" pack="far" size="is-small" />
6954
</div>
55+
<div class="level-item">Show celebration</div>
7056
</div>
7157
<div class="level-right">
7258
<div class="level-item">
7359
<b-switch
74-
v-model="celebrate"
60+
v-model="shouldCelebrate"
7561
size="is-small"
7662
title="Toggle celebration on screen"
77-
@input="toggleCelebration"
7863
/>
7964
</div>
8065
</div>
8166
</div>
8267
<div class="buttons is-centered">
83-
<button
84-
class="button is-secondary is-rounded"
85-
@click="quitSession"
86-
>
87-
<b-icon
88-
icon="sign-out-alt"
89-
size="is-small"
90-
/>
68+
<button class="button is-secondary is-rounded" @click="quitSession">
69+
<b-icon icon="sign-out-alt" size="is-small" />
9170
<span>End session</span>
9271
</button>
9372
</div>
@@ -103,17 +82,20 @@
10382
<script>
10483
import { mapGetters } from "vuex";
10584
import SmileyCounter from "@/components/SmileyCounter.vue";
106-
import SessionHealth from "@/components/SessionHealth.vue";
107-
import { clipboard, ipcRenderer } from "electron";
85+
import ScreenSelectionDropdown from "../components/ScreenSelectionDropdown";
86+
import { clipboard, ipcRenderer, remote } from "electron";
10887
export default {
109-
components: { SmileyCounter, SessionHealth },
110-
data() {
111-
return {
112-
shouldCelebrate: this.celebrate,
113-
};
114-
},
88+
components: { SmileyCounter, ScreenSelectionDropdown },
11589
computed: {
11690
...mapGetters(["activeSession", "celebrate"]),
91+
shouldCelebrate: {
92+
get() {
93+
return this.celebrate;
94+
},
95+
set(val) {
96+
this.$store.dispatch("toggleCelebration", val);
97+
},
98+
},
11799
},
118100
methods: {
119101
async quitSession() {
@@ -126,6 +108,11 @@ export default {
126108
toggleCelebration(val) {
127109
this.$store.dispatch("toggleCelebration", val);
128110
},
111+
openSessionInBrowser() {
112+
remote.shell.openExternal(
113+
`https://www.plodo.io/#/start/${this.activeSession.id}`
114+
);
115+
},
129116
},
130117
};
131118
</script>

0 commit comments

Comments
 (0)