@@ -4,108 +4,31 @@ import {gql} from '@apollo/client/core';
4
4
import { BBBGraphQl } from './BBBGraphQl' ;
5
5
import type { DisplayManager } from './displayManager' ;
6
6
import type { Layout } from '../../common/config' ;
7
- /*
8
- export async function createBBBMeeting(control: string, screens: Array<string>, displayManager: DisplayManager, leftCallback: () => void) {
7
+ import { v7 as uuid } from 'uuid' ;
9
8
10
- const bbbGraphQl = new BBBGraphql(control);
11
- const connected = await bbbGraphQl.connect();
12
- if(!connected)
13
- return false;
14
-
15
- console.log('connected to graphql');
16
-
17
- const joinUrl1 = await bbbGraphQl.getJoinURL({
18
- 'sessionName': 'left',
19
- 'enforceLayout': 'CAMERAS_ONLY',
20
- 'userdata-bbb_hide_actions_bar': false,
21
- 'userdata-bbb_display_notifications': false,
22
- 'userdata-bbb_auto_share_webcam': true,
23
- 'userdata-bbb_listen_only_mode': false,
24
- 'userdata-bbb_skip_check_audio': true,
25
- 'userdata-bbb_skip_video_preview': true,
26
- 'userdata-bbb_preferred_camera_profile': 'high',
27
- 'userdata-bbb_hide_nav_bar': true,
28
- 'userdata-bbb_auto_join_audio': true,
29
- 'userdata-bbb_show_session_details_on_join': false,
30
- });
31
-
32
- console.log('joinUrl1', joinUrl1.status);
33
- console.log('joinUrl1', joinUrl1.statusText);
34
- console.log('joinUrl1', JSON.stringify(joinUrl1.data));
35
- console.log('joinUrl1', JSON.stringify(joinUrl1.headers));
36
- console.log('joinUrl1', JSON.stringify(joinUrl1.config));
37
-
38
- const joinUrl2 = await bbbGraphQl.getJoinURL({
39
- 'sessionName': 'right',
40
- 'enforceLayout': 'PRESENTATION_ONLY',
41
- 'userdata-bbb_hide_actions_bar': false,
42
- 'userdata-bbb_display_notifications': false,
43
- 'userdata-bbb_auto_share_webcam': true,
44
- 'userdata-bbb_listen_only_mode': false,
45
- 'userdata-bbb_skip_check_audio': true,
46
- 'userdata-bbb_skip_video_preview': true,
47
- 'userdata-bbb_preferred_camera_profile': 'high',
48
- 'userdata-bbb_hide_nav_bar': true,
49
- 'userdata-bbb_auto_join_audio': true,
50
- 'userdata-bbb_show_session_details_on_join': false,
51
- });
52
-
53
- console.log('joinUrl2', joinUrl2.status);
54
- console.log('joinUrl2', joinUrl2.statusText);
55
- console.log('joinUrl2', JSON.stringify(joinUrl2.data));
56
- console.log('joinUrl2', JSON.stringify(joinUrl2.headers));
57
- console.log('joinUrl2', JSON.stringify(joinUrl2.config));
58
-
59
- return new BBBMeeting(screens, displayManager, leftCallback, bbbGraphQl);
60
- }
61
- */
62
- export async function createBBBMeeting ( control : string , layout : Layout , displayManager : DisplayManager , leftCallback : ( ) => void ) {
9
+ export async function createBBBMeeting ( control : string , displayManager : DisplayManager , leftCallback : ( ) => void ) {
63
10
64
11
const bbbGraphQl = new BBBGraphQl ( control ) ;
65
12
const connected = await bbbGraphQl . connect ( leftCallback ) ;
66
- if ( ! connected )
67
- return false ;
13
+ if ( ! connected ) return false ;
68
14
69
15
console . log ( 'connected to graphql' ) ;
70
16
71
- console . log ( 'layout' , layout . label ) ;
72
-
73
- const screens : { [ key : string ] : string } = { } ;
74
- for ( const [ key , value ] of Object . entries ( layout . screens ) ) {
75
- console . log ( key , value ) ;
76
-
77
- const joinUrl = await bbbGraphQl . getJoinURL ( {
78
- sessionName : key ,
79
- duplicateSession : false ,
80
- ...value . bbb_join_parameters ,
81
- } ) ;
82
-
83
- console . log ( 'status' , joinUrl . status ) ;
84
- console . log ( 'statusText' , joinUrl . statusText ) ;
85
- console . log ( 'data' , JSON . stringify ( joinUrl . data ) ) ;
86
- console . log ( 'headers' , JSON . stringify ( joinUrl . headers ) ) ;
87
- console . log ( 'config' , JSON . stringify ( joinUrl . config ) ) ;
88
-
89
- screens [ key ] = joinUrl . data . response . url ;
90
- }
91
-
92
- return new BBBMeeting ( screens , displayManager , leftCallback , bbbGraphQl ) ;
17
+ return new BBBMeeting ( displayManager , leftCallback , bbbGraphQl ) ;
93
18
}
94
19
95
-
96
20
class BBBMeeting {
97
- private readonly screens : { [ key : string ] : string } ;
21
+ private screens ! : { [ key : string ] : string } ;
98
22
private displayManager : DisplayManager ;
99
23
100
- private windows : BrowserWindow [ ] ;
101
- private apolloClient : ApolloClient < NormalizedCacheObject > ;
24
+ private windows : { [ key : string ] : BrowserWindow } ;
25
+ private apolloClient : ApolloClient < NormalizedCacheObject > | undefined ;
102
26
private bbbGraphQl : BBBGraphQl ;
103
- private mediaScreen : { url : string , window : BrowserWindow } ;
27
+ private mediaScreen : { url : string ; window : BrowserWindow } | undefined ;
104
28
105
- constructor ( screens : { [ key : string ] : string } , displayManager : DisplayManager , leftCallback : ( ) => void , bbbGraphQl : BBBGraphQl ) {
106
- this . screens = screens ;
29
+ constructor ( displayManager : DisplayManager , leftCallback : ( ) => void , bbbGraphQl : BBBGraphQl ) {
107
30
this . displayManager = displayManager ;
108
- this . windows = [ ] ;
31
+ this . windows = { } ;
109
32
this . bbbGraphQl = bbbGraphQl ;
110
33
111
34
this . apolloClient = this . bbbGraphQl . getApolloClient ( ) ;
@@ -118,7 +41,6 @@ class BBBMeeting {
118
41
}
119
42
120
43
private onUsersLeft ( callback : ( ) => void ) {
121
-
122
44
const getMeetingEndData = gql `
123
45
subscription getUserCurrent {
124
46
user_current {
@@ -133,7 +55,12 @@ class BBBMeeting {
133
55
}
134
56
}
135
57
}
136
- ` ;
58
+ ` ;
59
+
60
+ if ( this . apolloClient == undefined ) {
61
+ console . error ( 'Error: apolloClient is undefined' ) ;
62
+ return ;
63
+ }
137
64
138
65
this . apolloClient
139
66
. subscribe ( {
@@ -142,7 +69,7 @@ class BBBMeeting {
142
69
. subscribe ( {
143
70
next ( data ) {
144
71
console . log ( 'getMeetingEndData' , JSON . stringify ( data ) ) ;
145
- if ( data . data . user_current [ 0 ] . meeting . ended === true ) {
72
+ if ( data . data . user_current [ 0 ] . meeting . ended === true ) {
146
73
console . log ( 'Meeting ended' ) ;
147
74
callback ( ) ;
148
75
}
@@ -152,7 +79,6 @@ class BBBMeeting {
152
79
} ,
153
80
} ) ;
154
81
155
-
156
82
const USER_SESSIONS = gql `
157
83
subscription {
158
84
user_session(where: {connectionsAlive: {_gt: "0"}}) {
@@ -187,7 +113,35 @@ class BBBMeeting {
187
113
} ) ;
188
114
}
189
115
190
- public openScreens ( ) {
116
+ public async openScreens ( layout : Layout ) {
117
+
118
+ console . log ( 'Switching Layout to: ' , layout . label ) ;
119
+
120
+ // if (this.windows.length > 0) {
121
+ // console.log('Windows already exist. Amount of Current windows: ' + this.windows.length);
122
+ // for (var window of this.windows) {
123
+ // console.log('Closing window: ' + window.id);
124
+ // window.close();
125
+ // window.destroy();
126
+ // }
127
+ // }
128
+
129
+ this . mediaScreen = undefined ;
130
+ this . screens = { } ;
131
+
132
+ for ( const [ key , value ] of Object . entries ( layout . screens ) ) {
133
+ console . log ( "\nProcessing screen: " + key ) ;
134
+ console . log ( "With value: " + value + "\n" ) ;
135
+ const joinUrl = await this . bbbGraphQl . getJoinURL ( {
136
+ sessionName : key ,
137
+ duplicateSession : false ,
138
+ ...value . bbb_join_parameters ,
139
+ } ) ;
140
+ this . screens [ key ] = joinUrl . data . response . url ;
141
+ }
142
+
143
+ let newWindows : { [ key : string ] : BrowserWindow } = { } ;
144
+
191
145
for ( const [ screen , url ] of Object . entries ( this . screens ) ) {
192
146
const screenDisplay = this . displayManager . getDisplay ( screen ) ;
193
147
@@ -196,40 +150,74 @@ class BBBMeeting {
196
150
continue ;
197
151
}
198
152
199
- console . log ( 'screenDisplay' , screenDisplay ) ;
200
-
201
- const partition = 'persist:windows-' + this . windows . length ;
153
+ console . log ( 'Processing screen ' + screen ) ;
154
+
155
+ const partition = 'persist:windows-' + uuid ( ) ;
156
+
157
+ // Get old window if exists
158
+ let screenWindow = this . windows [ screenDisplay . label ] ;
159
+ delete this . windows [ screenDisplay . label ] ;
160
+
161
+ if ( screenWindow == undefined ) {
162
+ console . log ( 'Creating new window' ) ;
163
+ screenWindow = new BrowserWindow ( {
164
+ show : true ,
165
+ width : screenDisplay . size . width ,
166
+ height : screenDisplay . size . height ,
167
+ x : screenDisplay . bounds . x ,
168
+ y : screenDisplay . bounds . y ,
169
+ fullscreen : true ,
170
+ webPreferences : {
171
+ partition : partition ,
172
+ contextIsolation : true ,
173
+ } ,
174
+ autoHideMenuBar : true ,
175
+ } ) ;
176
+ } else {
177
+ console . log ( 'Using existing window' ) ;
178
+ }
202
179
203
- const screenWindow = new BrowserWindow ( {
204
- show : true ,
205
- width : screenDisplay . size . width ,
206
- height : screenDisplay . size . height ,
207
- x : screenDisplay . bounds . x ,
208
- y : screenDisplay . bounds . y ,
209
- fullscreen : true ,
210
- webPreferences : {
211
- partition : partition ,
212
- contextIsolation : true ,
213
- } ,
180
+ // When leaving the BBB meeting (by visiting another website), BBB will show a confirmation dialog (are you sure blabla)
181
+ // This dialog will prevent the loading of a new URL, so we handle this problem here in this event listener
182
+ screenWindow . webContents . on ( 'will-prevent-unload' , ( event ) => {
183
+ console . log ( "Prevented unload detected, forcing unload..." ) ;
184
+ event . preventDefault ( ) ; // This stops the confirmation dialog
185
+ if ( screenWindow ) {
186
+ console . log ( screenDisplay . label + ": Loading URL again: " + url ) ;
187
+ screenWindow . loadURL ( url ) ;
188
+ }
214
189
} ) ;
215
- //screenWindow.webContents.openDevTools();
190
+ console . log ( '\n' + screenDisplay . label + ': Loading URL: ' + url ) ;
191
+ await screenWindow . loadURL ( url ) ;
192
+ console . log ( screenDisplay . label + ': Loading of URL finished.\n' ) ;
216
193
217
- this . windows . push ( screenWindow ) ;
194
+ newWindows [ screenDisplay . label ] = screenWindow ;
218
195
219
- screenWindow . loadURL ( url ) ;
220
-
221
- if ( url . includes ( 'userdata-bbb_auto_join_audio=true' ) ) {
196
+ if ( url . includes ( 'userdata-bbb_auto_join_audio=true' ) ) {
222
197
this . mediaScreen = { url : url , window : screenWindow } ;
223
198
}
224
199
}
200
+
201
+ // Close all unused windows
202
+ Object . values ( this . windows ) . forEach ( window => {
203
+ console . log ( 'closing window ' + window . id ) ;
204
+ window . close ( ) ;
205
+ window . destroy ( ) ;
206
+ } ) ;
207
+
208
+ this . windows = newWindows ;
225
209
}
226
210
227
211
public mute ( ) {
228
- this . executeJavaScriptInMediaScreen ( 'document.querySelectorAll(\'button[data-test="muteMicButton"]\')[0].click()' ) . then ( r => console . log ( r ) ) ;
212
+ this . executeJavaScriptInMediaScreen (
213
+ 'document.querySelectorAll(\'button[data-test="muteMicButton"]\')[0].click()' ,
214
+ ) . then ( r => console . log ( r ) ) ;
229
215
}
230
216
231
217
public unmute ( ) {
232
- this . executeJavaScriptInMediaScreen ( 'document.querySelectorAll(\'button[data-test="unmuteMicButton"]\')[0].click()' ) . then ( r => console . log ( r ) ) ;
218
+ this . executeJavaScriptInMediaScreen (
219
+ 'document.querySelectorAll(\'button[data-test="unmuteMicButton"]\')[0].click()' ,
220
+ ) . then ( r => console . log ( r ) ) ;
233
221
}
234
222
235
223
public async getMediaDevices ( ) {
@@ -253,13 +241,13 @@ class BBBMeeting {
253
241
}
254
242
255
243
private async executeJavaScriptInMediaScreen ( command : string ) {
256
- if ( this . mediaScreen . window ) {
244
+ if ( this . mediaScreen ) {
257
245
return await this . mediaScreen . window . webContents . executeJavaScript ( command ) ;
258
246
}
259
247
}
260
248
261
249
private closeScreens ( ) {
262
- this . windows . forEach ( window => {
250
+ Object . values ( this . windows ) . forEach ( window => {
263
251
window . close ( ) ;
264
252
window . destroy ( ) ;
265
253
} ) ;
0 commit comments