Skip to content

Commit

Permalink
Multiserver
Browse files Browse the repository at this point in the history
  • Loading branch information
hmt committed Feb 9, 2021
1 parent e66fdba commit 1ccf946
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 112 deletions.
2 changes: 1 addition & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export default {
}),
commonjs(),
typescript({
sourceMap: !production,
sourceMap: true, //!production,
inlineSources: !production
}),

Expand Down
93 changes: 23 additions & 70 deletions src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,77 +1,30 @@
<script lang="ts">
import "bulma/css/bulma.css";
import parser from "fast-xml-parser";
import sha1 from "jssha/dist/sha1";
import { url, server, secret, interval, status } from "./store";
import Meeting from "./Meeting.svelte";
import type { meeting } from "./types";
import Banner from "./Banner.svelte";
import Settings from "./Settings.svelte";
let meetings: Array<meeting>;
let json: { response: { meetings: { meeting: meeting | Array<meeting> } } };
function getHash(message: string) {
const hash = new sha1("SHA-1", "TEXT");
hash.update(`getMeetings${message}`);
return hash.getHash("HEX");
}
async function get_stats() {
if (!$url) {
json = null;
return;
}
try {
$status = "laden";
const res = await fetch($url);
if (!res.ok) throw "Fehler beim Laden der Seite";
const xml = await res.text();
$status = "ok";
json = parser.parse(xml);
} catch (e) {
console.log("Server nicht erreichbar: ", e);
json = null;
$status = `Fehler: ${e}`;
}
}
console.info(
`%cWillkommen in der Konsole des BBB-Exporters. Hier kannst Du Fehler
nachschauen und die Ergebnisse der Api-Abfrage als JSON auslesen. Man kann
in Firefox das gesamte Objekt kopieren, wenn man mit der rechten Maustaste
auf den "response"-Teil des JSON klickt. Im Texteditor eingefügt, lässt sich
alles besser betrachten.`, 'color: blue'
);
$: $url =
$server && $secret
? `${$server}/bigbluebutton/api/getMeetings?checksum=${getHash($secret)}`
: undefined;
$: console.log("JSON: ", json);
$: $url && get_stats();
$: meetings =
json && [json?.response.meetings?.meeting].flat().filter(Boolean);
setInterval(get_stats, $interval * 1000);
import Server from "./Server.svelte";
import { server_list, selected } from "./store";
</script>

<div class="container">
<Settings />
<section class="section">
{#if meetings}
<Banner {json} {meetings} />
{#each meetings.filter((m) => !m.isBreakout) as meeting}
<Meeting {meeting}>
{#each meetings.filter((b) =>
[meeting.breakoutRooms?.breakout].flat().includes(b.meetingID)
) as breakout}
<Meeting meeting={breakout} />
{/each}
</Meeting>
<div class="tabs">
<ul>
{#each $server_list as s}
<li class:is-active={$selected === s}>
<!-- svelte-ignore a11y-missing-attribute -->
<a on:click={(_) => ($selected = s)}
>{s.name || "Namenloser Server"}</a
>
</li>
{/each}
{:else}
<Banner />
{/if}
</section>
<li>
<!-- svelte-ignore a11y-missing-attribute -->
<a>
<i
class="material-icons is-clickable"
on:click={server_list.add}>add</i
>
</a>
</li>
</ul>
</div>
<Server />
</div>
36 changes: 23 additions & 13 deletions src/Banner.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<script lang="ts">
import Settings from "./Settings.svelte";
import type { meeting } from "./types";
import { settings } from "./store";
export let json: object;
export let meetings: meeting[];
export let json: object = undefined;
export let meetings: meeting[] = undefined;
export let status: string | undefined;
</script>

<nav
Expand Down Expand Up @@ -44,7 +47,10 @@
{:else if json && !meetings.length}
<div class="level-item has-text-centered">
<div>
<p class="heading">Es sind momentan keine Räume offen. Mach doch mal wieder eine BBB-Konferenz!</p>
<p class="heading">
Es sind momentan keine Räume offen. Mach doch mal wieder eine
BBB-Konferenz!
</p>
</div>
</div>
{:else}
Expand All @@ -54,16 +60,20 @@
</div>
</div>
{/if}
<div class="level-item has-text-centered">
<div>
<p class="heading">&nbsp;</p>
<p class="title">
<i
class="material-icons is-clickable"
style="font-size: 3rem"
on:click={(_) => ($settings = true)}>settings</i
>
</p>
<div class="level-right">
<div class="level-item has-text-centered">
<div>
<p class="heading">&nbsp;</p>
<p class="title">
<i
class="material-icons is-clickable"
style="font-size: 3rem"
on:click={(_) => ($settings = !$settings)}>settings</i
>
</p>
</div>
</div>
</div>
</nav>

<Settings {status} />
64 changes: 64 additions & 0 deletions src/Server.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<script lang="ts">
import { selected } from "./store";
import parser from "fast-xml-parser";
import sha1 from "jssha/dist/sha1";
import Meeting from "./Meeting.svelte";
import type { meeting } from "./types";
import Banner from "./Banner.svelte";
let status: string | undefined = undefined;
let meetings: Array<meeting>;
let json: { response: { meetings: { meeting: meeting | Array<meeting> } } };
function getHash(message: string) {
const hash = new sha1("SHA-1", "TEXT");
hash.update(`getMeetings${message}`);
return hash.getHash("HEX");
}
async function get_stats() {
if (!url) {
json = null;
status = undefined;
return;
}
try {
status = "laden";
const res = await fetch(url);
if (!res.ok) throw "Fehler beim Laden der Seite";
const xml = await res.text();
status = "ok";
json = parser.parse(xml);
} catch (e) {
console.log("Server nicht erreichbar: ", e);
json = null;
status = `Fehler: ${e}`;
}
}
$: url =
$selected.host && $selected.secret
? `${$selected.host}/bigbluebutton/api/getMeetings?checksum=${getHash(
$selected.secret
)}`
: undefined;
$: $selected && get_stats();
$: meetings =
json && [json?.response.meetings?.meeting].flat().filter(Boolean);
setInterval(get_stats, $selected.interval * 1000);
</script>

{#if meetings}
<Banner {json} {meetings} {status} />
{#each meetings.filter((m) => !m.isBreakout) as meeting}
<Meeting {meeting}>
{#each meetings.filter((b) =>
[meeting.breakoutRooms?.breakout].flat().includes(b.meetingID)
) as breakout}
<Meeting meeting={breakout} />
{/each}
</Meeting>
{/each}
{:else}
<Banner {status} />
{/if}
52 changes: 31 additions & 21 deletions src/Settings.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
<script lang="ts">
import { server, secret, interval, settings, url, status } from "./store";
$: window.localStorage.setItem(`server`, $server);
$: window.localStorage.setItem(`secret`, $secret);
$: window.localStorage.setItem(`interval`, $interval.toString());
import { selected, settings, server_list } from "./store";
export let status: string | undefined;
</script>

<div class="modal" class:is-active={$settings}>
Expand All @@ -13,6 +10,19 @@
<p class="modal-card-title">BigBlueButton-Monitor</p>
</header>
<section class="modal-card-body">
<div class="field">
<div class="control">
<label class="label"
>Name
<input
class="input"
type="text"
placeholder="Mein BBB-Server"
bind:value={$selected.name}
/>
</label>
</div>
</div>
<div class="field">
<div class="control">
<label class="label"
Expand All @@ -21,7 +31,7 @@
class="input"
type="text"
placeholder="Server z.B. https://bbb.schule.de"
bind:value={$server}
bind:value={$selected.host}
/>
</label>
</div>
Expand All @@ -34,7 +44,7 @@
class="input"
type="password"
placeholder="Secret"
bind:value={$secret}
bind:value={$selected.secret}
/>
</label>
</div>
Expand All @@ -47,37 +57,37 @@
class="input"
type="number"
placeholder="Interval"
bind:value={$interval}
bind:value={$selected.interval}
/>
</label>
</div>
</div>
Es werden keine Daten zum Server übertragen, die Kommunikation findet ausschließlich
zwischen Browser und BBB-Server statt. Aus diesem Grund müssen CORS-Header
vom BBB-Server gesetzt werden (oder eine Browser-Erweiterung, z.B. CORS Everywhere).
Weitere Informationen auf der Projektseite des <a
href="https://github.com/hmt/bbb-static-monitor">BBB-Monitors</a
>
<br>Verbindungsdaten werden im localStorage des Browsers gespeichert.
Es werden keine Daten zum Server übertragen, die Kommunikation findet
ausschließlich zwischen Browser und BBB-Server statt. Aus diesem Grund
müssen CORS-Header vom BBB-Server gesetzt werden (oder eine
Browser-Erweiterung, z.B. CORS Everywhere). Weitere Informationen auf der
Projektseite des <a href="https://github.com/hmt/bbb-static-monitor">BBB-Monitors</a>
<br />Verbindungsdaten werden im localStorage des Browsers gespeichert.
</section>
<footer class="modal-card-foot">
<button
class="is-extended button is-primary"
on:click={(_) => ($settings = false)}>Schließen</button
>
{#if $url}
<span class="ml-4">
{#if status}
<span class="ml-4 mr-4">
Verbindung:
<span
class="tag"
class:is-success={$status === "ok"}
class:is-danger={$status.startsWith("Fehler")}
class:is-warning={$status === "laden"}
class:is-success={status === "ok"}
class:is-danger={status.startsWith("Fehler")}
class:is-warning={status === "laden"}
>
{$status}
{status}
</span>
</span>
{/if}
<button class="is-extended button is-danger" on:click={server_list.remove}>Löschen</button>
</footer>
</div>
</div>
60 changes: 54 additions & 6 deletions src/store.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,56 @@
import { Writable, writable } from "svelte/store";
import type { server, CustomStore } from "./types";

export const url: Writable<string> = writable(undefined);
export const status: Writable<string> = writable(undefined);
export const interval: Writable<number> = writable(parseInt(window.localStorage.getItem("interval")) || 15);
export const server: Writable<string> = writable(window.localStorage.getItem("server") || "");
export const secret: Writable<string> = writable(window.localStorage.getItem("secret") || "");
export const settings: Writable<boolean> = writable(!!(secret && server));
let sel: server, list: server[]

function server_create() {
const { subscribe, update, set }: Writable<server[]> = writable(JSON.parse(window.localStorage.getItem("servers")) || [{ name: "", host: "", secret: "", interval: 15 }]);

return {
subscribe, set, update,
add: () => update(server => {
const new_list = [...server,
{
name: "",
host: "",
secret: "",
interval: 15
}
]
selected.set(new_list[list.length])
settings.set(true)
return new_list
}),
remove: () => update(server => {
if (server.length === 1) {
server = [{ name: "", host: "", secret: "", interval: 15 }];
selected.set(server[0])
return
}
for (let i = 0; i < server.length; i++) {
if (server[i] === sel) {
server.splice(i, 1);
selected.set(server[i] || server[i - 1]);
}
}
settings.set(false)
return server
}),
};
}

export const server_list: CustomStore<server[]> = server_create()

server_list.subscribe(value => {
window.localStorage.setItem(`servers`, JSON.stringify(value));
list = value
})

export const selected: Writable<server> = writable(list[JSON.parse(window.localStorage.getItem("selected")) || 0]);
selected.subscribe(value => {
window.localStorage.setItem(`selected`, JSON.stringify(list.findIndex(s=>s === value)));
sel = value
server_list.set(list)
})

export const settings: Writable<boolean> = writable(undefined)
Loading

0 comments on commit 1ccf946

Please sign in to comment.