Working on better thing
This commit is contained in:
15
Client/src/.routify/config.js
Normal file
15
Client/src/.routify/config.js
Normal file
@ -0,0 +1,15 @@
|
||||
module.exports = {
|
||||
"pages": "src/pages",
|
||||
"sourceDir": "public",
|
||||
"routifyDir": "src/.routify",
|
||||
"ignore": "",
|
||||
"dynamicImports": true,
|
||||
"singleBuild": false,
|
||||
"noHashScroll": false,
|
||||
"distDir": "dist",
|
||||
"hashScroll": true,
|
||||
"extensions": [
|
||||
"svelte"
|
||||
],
|
||||
"started": "2022-02-17T23:53:42.346Z"
|
||||
}
|
140
Client/src/.routify/routes.js
Normal file
140
Client/src/.routify/routes.js
Normal file
@ -0,0 +1,140 @@
|
||||
|
||||
/**
|
||||
* @roxi/routify 2.18.4
|
||||
* File generated Thu Feb 17 2022 23:53:42 GMT+0000 (Coordinated Universal Time)
|
||||
*/
|
||||
|
||||
export const __version = "2.18.4"
|
||||
export const __timestamp = "2022-02-17T23:53:42.361Z"
|
||||
|
||||
//buildRoutes
|
||||
import { buildClientTree } from "@roxi/routify/runtime/buildRoutes"
|
||||
|
||||
//imports
|
||||
|
||||
|
||||
//options
|
||||
export const options = {}
|
||||
|
||||
//tree
|
||||
export const _tree = {
|
||||
"name": "root",
|
||||
"filepath": "/",
|
||||
"root": true,
|
||||
"ownMeta": {},
|
||||
"absolutePath": "src/pages",
|
||||
"children": [
|
||||
{
|
||||
"isFile": true,
|
||||
"isDir": false,
|
||||
"file": "index.svelte",
|
||||
"filepath": "/index.svelte",
|
||||
"name": "index",
|
||||
"ext": "svelte",
|
||||
"badExt": false,
|
||||
"absolutePath": "/root/Projects/ScreenSharingThing/Client/src/pages/index.svelte",
|
||||
"importPath": "../pages/index.svelte",
|
||||
"isLayout": false,
|
||||
"isReset": false,
|
||||
"isIndex": true,
|
||||
"isFallback": false,
|
||||
"isPage": true,
|
||||
"ownMeta": {},
|
||||
"meta": {
|
||||
"recursive": true,
|
||||
"preload": false,
|
||||
"prerender": true
|
||||
},
|
||||
"path": "/index",
|
||||
"id": "_index",
|
||||
"component": () => import('../pages/index.svelte').then(m => m.default)
|
||||
},
|
||||
{
|
||||
"isFile": false,
|
||||
"isDir": true,
|
||||
"file": "session",
|
||||
"filepath": "/session",
|
||||
"name": "session",
|
||||
"ext": "",
|
||||
"badExt": false,
|
||||
"absolutePath": "/root/Projects/ScreenSharingThing/Client/src/pages/session",
|
||||
"children": [
|
||||
{
|
||||
"isFile": false,
|
||||
"isDir": true,
|
||||
"file": "[sessionid]",
|
||||
"filepath": "/session/[sessionid]",
|
||||
"name": "[sessionid]",
|
||||
"ext": "",
|
||||
"badExt": false,
|
||||
"absolutePath": "/root/Projects/ScreenSharingThing/Client/src/pages/session/[sessionid]",
|
||||
"children": [
|
||||
{
|
||||
"isFile": true,
|
||||
"isDir": false,
|
||||
"file": "index.svelte",
|
||||
"filepath": "/session/[sessionid]/index.svelte",
|
||||
"name": "index",
|
||||
"ext": "svelte",
|
||||
"badExt": false,
|
||||
"absolutePath": "/root/Projects/ScreenSharingThing/Client/src/pages/session/[sessionid]/index.svelte",
|
||||
"importPath": "../pages/session/[sessionid]/index.svelte",
|
||||
"isLayout": false,
|
||||
"isReset": false,
|
||||
"isIndex": true,
|
||||
"isFallback": false,
|
||||
"isPage": true,
|
||||
"ownMeta": {},
|
||||
"meta": {
|
||||
"recursive": true,
|
||||
"preload": false,
|
||||
"prerender": true
|
||||
},
|
||||
"path": "/session/:sessionid/index",
|
||||
"id": "_session__sessionid_index",
|
||||
"component": () => import('../pages/session/[sessionid]/index.svelte').then(m => m.default)
|
||||
}
|
||||
],
|
||||
"isLayout": false,
|
||||
"isReset": false,
|
||||
"isIndex": false,
|
||||
"isFallback": false,
|
||||
"isPage": false,
|
||||
"ownMeta": {},
|
||||
"meta": {
|
||||
"recursive": true,
|
||||
"preload": false,
|
||||
"prerender": true
|
||||
},
|
||||
"path": "/session/:sessionid"
|
||||
}
|
||||
],
|
||||
"isLayout": false,
|
||||
"isReset": false,
|
||||
"isIndex": false,
|
||||
"isFallback": false,
|
||||
"isPage": false,
|
||||
"ownMeta": {},
|
||||
"meta": {
|
||||
"recursive": true,
|
||||
"preload": false,
|
||||
"prerender": true
|
||||
},
|
||||
"path": "/session"
|
||||
}
|
||||
],
|
||||
"isLayout": false,
|
||||
"isReset": false,
|
||||
"isIndex": false,
|
||||
"isFallback": false,
|
||||
"meta": {
|
||||
"recursive": true,
|
||||
"preload": false,
|
||||
"prerender": true
|
||||
},
|
||||
"path": "/"
|
||||
}
|
||||
|
||||
|
||||
export const {tree, routes} = buildClientTree(_tree)
|
||||
|
3
Client/src/.routify/urlIndex.json
Normal file
3
Client/src/.routify/urlIndex.json
Normal file
@ -0,0 +1,3 @@
|
||||
[
|
||||
"/index"
|
||||
]
|
6
Client/src/App.svelte
Normal file
6
Client/src/App.svelte
Normal file
@ -0,0 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { Router } from "@roxi/routify";
|
||||
import { routes } from "./.routify/routes";
|
||||
</script>
|
||||
|
||||
<Router {routes} />
|
105
Client/src/api.ts
Normal file
105
Client/src/api.ts
Normal file
@ -0,0 +1,105 @@
|
||||
import {
|
||||
type ICollectionRef,
|
||||
type IDocumentRef,
|
||||
UpdateTypes,
|
||||
} from "@rtdb2/sdk";
|
||||
import { nanoid } from "nanoid";
|
||||
import { Peer } from "peerjs/lib/peer";
|
||||
import {
|
||||
collectionToStore,
|
||||
Sessions,
|
||||
type IMember,
|
||||
type IMessage,
|
||||
type ISession,
|
||||
} from "./db";
|
||||
|
||||
import type { Readable } from "svelte/store";
|
||||
import { Signal } from "@hibas123/utils";
|
||||
|
||||
export class Session {
|
||||
#client_id = nanoid(22);
|
||||
#peer: Peer;
|
||||
|
||||
#session: IDocumentRef<ISession>;
|
||||
#members: ICollectionRef<IMember>;
|
||||
#messages: ICollectionRef<IMessage>;
|
||||
#self: IDocumentRef<IMember>;
|
||||
|
||||
#name: string;
|
||||
#iv: any;
|
||||
|
||||
#closeSignal = new Signal();
|
||||
|
||||
members: Readable<(IMember & { $id: string })[]>;
|
||||
messages: Readable<(IMessage & { $id: string })[]>;
|
||||
|
||||
get name() {
|
||||
return this.#name;
|
||||
}
|
||||
|
||||
set name(value) {
|
||||
this.#name = value;
|
||||
this.#self.update({ name: UpdateTypes.Value(value) });
|
||||
}
|
||||
|
||||
constructor(id: string, name: string) {
|
||||
this.#name = name;
|
||||
|
||||
this.#peer = new Peer(this.#client_id, {
|
||||
host: window.location.hostname,
|
||||
port: window.location.port as any,
|
||||
path: "/peerjs",
|
||||
config: {},
|
||||
});
|
||||
|
||||
this.#session = Sessions.doc(id);
|
||||
this.#members = this.#session.collection("members");
|
||||
this.#messages = this.#session.collection("messages");
|
||||
this.#self = this.#members.doc(this.#client_id);
|
||||
this.members = collectionToStore(this.#members);
|
||||
this.messages = collectionToStore(this.#messages);
|
||||
|
||||
this.registerSelf();
|
||||
this.#iv = setInterval(() => this.tick(), 5000);
|
||||
}
|
||||
|
||||
tick() {
|
||||
this.#self.update({ lastActive: UpdateTypes.Value(Date.now()) });
|
||||
}
|
||||
|
||||
registerSelf() {
|
||||
this.#self.set({
|
||||
name: this.#name,
|
||||
lastActive: Date.now(),
|
||||
offline: false,
|
||||
});
|
||||
}
|
||||
|
||||
close() {
|
||||
this.#closeSignal.sendSignal();
|
||||
clearInterval(this.#iv);
|
||||
this.#self.update({ offline: UpdateTypes.Value(true) });
|
||||
this.#peer.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
let bitrate = new URL(window.location.href).searchParams.get("br") || 50000;
|
||||
|
||||
function bitrateTransform(sdp: string) {
|
||||
var arr = sdp.split("\r\n");
|
||||
arr.forEach((str, i) => {
|
||||
if (/^a=fmtp:\d*/.test(str)) {
|
||||
console.log("found fmtp");
|
||||
arr[i] =
|
||||
str +
|
||||
`;x-google-max-bitrate=${bitrate};x-google-min-bitrate=0;x-google-start-bitrate=12000`;
|
||||
} else if (/^a=mid:(1|video)/.test(str)) {
|
||||
console.log("found mid");
|
||||
arr[i] += "\r\nb=AS:" + bitrate;
|
||||
}
|
||||
});
|
||||
|
||||
let res = arr.join("\r\n");
|
||||
console.log(sdp, res);
|
||||
return res;
|
||||
}
|
5
Client/src/bootstrap.ts
Normal file
5
Client/src/bootstrap.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import App from "./App.svelte";
|
||||
|
||||
new App({
|
||||
target: document.body,
|
||||
});
|
43
Client/src/db.ts
Normal file
43
Client/src/db.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { AwaitStore } from "@hibas123/utils";
|
||||
import Client, { type ICollectionRef } from "@rtdb2/sdk";
|
||||
import { readable } from "svelte/store";
|
||||
|
||||
const client = new Client(
|
||||
"https://rtdb.hibas123.de",
|
||||
"screen_share",
|
||||
"screen_share"
|
||||
);
|
||||
|
||||
(window as any).db = client;
|
||||
|
||||
export const Sessions = client.collection<ISession>("sessions");
|
||||
|
||||
export interface ISession {}
|
||||
|
||||
export interface IMember {
|
||||
lastActive: number;
|
||||
offline: boolean;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface IMessage {
|
||||
sender: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export function collectionToStore<T>(coll: ICollectionRef<T>) {
|
||||
return readable<(T & { $id: string })[]>([], (set) => {
|
||||
const cancel = new AwaitStore(false);
|
||||
(async () => {
|
||||
const itr = await coll.onSnapshot();
|
||||
cancel.awaitValue(true).then(() => itr.close());
|
||||
for await (const snapshot of itr) {
|
||||
set(snapshot.docs.map((doc) => ({ ...doc.data(), $id: doc.id })));
|
||||
}
|
||||
})();
|
||||
|
||||
return () => {
|
||||
cancel.send(true);
|
||||
};
|
||||
});
|
||||
}
|
80
Client/src/pages/index.svelte
Normal file
80
Client/src/pages/index.svelte
Normal file
@ -0,0 +1,80 @@
|
||||
<script lang="ts">
|
||||
import Button from "@smui/button";
|
||||
import Textfield from "@smui/textfield";
|
||||
import Paper, { Title as PTitle, Content as PContent } from "@smui/paper";
|
||||
import { nanoid } from "nanoid";
|
||||
import { url } from "@roxi/routify";
|
||||
import Snackbar, { Actions, Label } from "@smui/snackbar";
|
||||
import type { SnackbarComponentDev } from "@smui/snackbar";
|
||||
import IconButton from "@smui/icon-button";
|
||||
|
||||
let sessionID = "";
|
||||
let errorSnack: SnackbarComponentDev;
|
||||
|
||||
function create() {
|
||||
sessionID = nanoid(22);
|
||||
connect();
|
||||
}
|
||||
|
||||
function connect() {
|
||||
if (sessionID.length < 22) {
|
||||
errorSnack.open();
|
||||
return;
|
||||
}
|
||||
|
||||
window.history.pushState(
|
||||
undefined,
|
||||
undefined,
|
||||
$url(`/session/${sessionID}`)
|
||||
);
|
||||
sessionID = "";
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="outer">
|
||||
<div class="inner">
|
||||
<Paper elevation={6}>
|
||||
<PContent>
|
||||
<PTitle>Create Session</PTitle>
|
||||
<div style="margin-top: 1rem" />
|
||||
<Button variant="raised" on:click={create}>Create</Button>
|
||||
</PContent>
|
||||
</Paper>
|
||||
<Paper elevation={6}>
|
||||
<PContent>
|
||||
<PTitle>Join Session</PTitle>
|
||||
<Textfield
|
||||
label="Session ID"
|
||||
bind:value={sessionID}
|
||||
style="width: 100%;"
|
||||
/>
|
||||
<div style="margin-top: 1rem" />
|
||||
<Button variant="raised" on:click={connect}>Connect</Button>
|
||||
</PContent>
|
||||
</Paper>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Snackbar bind:this={errorSnack}>
|
||||
<Label>Invalid Session!</Label>
|
||||
<Actions>
|
||||
<IconButton class="material-icons" title="Dismiss">close</IconButton>
|
||||
</Actions>
|
||||
</Snackbar>
|
||||
|
||||
<style>
|
||||
.outer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.inner {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(150px, 300px));
|
||||
grid-template-rows: auto;
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
42
Client/src/pages/session/[sessionid]/index.svelte
Normal file
42
Client/src/pages/session/[sessionid]/index.svelte
Normal file
@ -0,0 +1,42 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
|
||||
import { Session } from "../../../api";
|
||||
export let sessionid: string;
|
||||
|
||||
let session = new Session(sessionid, "");
|
||||
let members = session.members;
|
||||
|
||||
onMount(() => {
|
||||
return () => {
|
||||
session.close();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- {sessionid} -->
|
||||
|
||||
<div class="outer">
|
||||
<div class="members">
|
||||
{#each $members as member (member.$id)}
|
||||
<div class="member">
|
||||
<div class="name">{member.name || "anon"}</div>
|
||||
<div class="id">{member.$id}</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="content">Content</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.outer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 200px 1fr;
|
||||
}
|
||||
</style>
|
28
Client/src/theme/_smui-theme.scss
Normal file
28
Client/src/theme/_smui-theme.scss
Normal file
@ -0,0 +1,28 @@
|
||||
@use "sass:color";
|
||||
|
||||
@use "@material/theme/color-palette";
|
||||
|
||||
// Svelte Colors!
|
||||
@use "@material/theme/index" as theme with
|
||||
(
|
||||
$primary: #1e88e5,
|
||||
$secondary: #d8701b,
|
||||
$surface: #fff,
|
||||
$background: #fff,
|
||||
$error: color-palette.$red-900
|
||||
);
|
||||
|
||||
@import "@material/typography/mdc-typography";
|
||||
|
||||
// html,
|
||||
// body {
|
||||
// background-color: theme.$surface;
|
||||
// color: theme.$on-surface;
|
||||
// }
|
||||
|
||||
// a {
|
||||
// color: #40b3ff;
|
||||
// }
|
||||
// a:visited {
|
||||
// color: color.scale(#40b3ff, $lightness: -35%);
|
||||
// }
|
28
Client/src/theme/dark/_smui-theme.scss
Normal file
28
Client/src/theme/dark/_smui-theme.scss
Normal file
@ -0,0 +1,28 @@
|
||||
@use "sass:color";
|
||||
|
||||
@use "@material/theme/color-palette";
|
||||
|
||||
// Svelte Colors! (Dark Theme)
|
||||
@use "@material/theme/index" as theme with
|
||||
(
|
||||
$primary: #1e88e5,
|
||||
$secondary: #d8701b,
|
||||
$surface: color.adjust(color-palette.$grey-900, $blue: +4),
|
||||
$background: #000,
|
||||
$error: color-palette.$red-700
|
||||
);
|
||||
|
||||
@import "@material/typography/mdc-typography";
|
||||
|
||||
// html,
|
||||
// body {
|
||||
// background-color: #000;
|
||||
// color: theme.$on-surface;
|
||||
// }
|
||||
|
||||
// a {
|
||||
// color: #40b3ff;
|
||||
// }
|
||||
// a:visited {
|
||||
// color: color.scale(#40b3ff, $lightness: -35%);
|
||||
// }
|
Reference in New Issue
Block a user