From 14b7337949d00d7b6171293fd34d094435e1c181 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Tue, 27 Dec 2022 19:06:03 +0700 Subject: [PATCH] Last push of documentation for the client stuff. --- client/main.js | 5 +++ client/stores.js | 31 ++++++++++++++- client/websocket.js | 23 +++++++++++ client/wt.js | 94 ++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 142 insertions(+), 11 deletions(-) diff --git a/client/main.js b/client/main.js index 7221068..42e7070 100644 --- a/client/main.js +++ b/client/main.js @@ -1,3 +1,8 @@ +/* + This is the main file for the client Svelte app. Usually you wouldn't need to + modify this unless you want to alter the Svelte configuration or add some + necessary code. + */ import App from '$/client/App.svelte'; const app = new App({ diff --git a/client/stores.js b/client/stores.js index 0750904..b2574f0 100644 --- a/client/stores.js +++ b/client/stores.js @@ -1,11 +1,28 @@ +/* + The main Svelte stores used in the application. The main one is the `user`, which + contains a store for the current user. Svelte stores are a useful way to maintain + information that's used across pages. I've left in a few that I used for caching + in my courses at https://learnjsthehardway.com so you can see how to use a store + for caching. + */ import { writable } from 'svelte/store'; - -// look in api/login.js and client/pages/Login.svelte for where this is initially setup +/* + Look in api/login.js and client/pages/Login.svelte for where this is initially setup. + */ export const user = writable({ authenticated: undefined, // yes, this is on purpose }); +/* + I used this for some basic caching of course items, since constantly loading + them on every click was pointless. The course material doesn't change much, + so caching it makes sense. Why didn't I use Service Workers instead? Service + Workers are very unreliable when it comes to reloading. They require a lot of + extra gear just to make simple refreshing a page of content work. If what you + cache persists across refresh the go ahead and use Service Worker caching. If + not then just do it this way. + */ export const cache = writable({ courses: {}, modules: {}, @@ -13,6 +30,9 @@ export const cache = writable({ recents: {} }); +/* + Clears out the cache. Again, mostly a demo. + */ export const cache_reset = () => { cache.update(() => ({ courses: {}, @@ -22,6 +42,13 @@ export const cache_reset = () => { })); } +/* + Use for video configuration information that's shared between + video pages. + */ export const video_config = writable({video_ready: false}); +/* + The user's darkmode setting. + */ export const darkmode = writable({theme: "light"}); diff --git a/client/websocket.js b/client/websocket.js index 384c90d..6e2cd33 100644 --- a/client/websocket.js +++ b/client/websocket.js @@ -1,12 +1,27 @@ +/* + Helpers for dealing with the `socket/` handlers, similar to the + code in `client/api.js`. WebSockets already work well with JSON + data, so this mostly handles create a single connection, and + reconnecting when you need to. + */ import { inject_remote } from "$/client/components/Source.svelte"; let raw_socket; +/* + Load the `/js/socket.io.min.js` file using `client/components/Sourse.svelte:inject_remote`. + This makes it so if you don't use the socket.io stuff then you won't download the code. + */ export const configure_socket = async () => { await inject_remote(document, "/js/socket.io.min.js"); } +/* + Connect to the server __once__. This should maintain the connection + in the SPA for as long as possible and return only one. + + `reconnection boolean` -- The reconnection policy that's passed to socket.io `io()`. + */ export const connect_socket = (reconnection=false) => { if(raw_socket === undefined) { raw_socket = io({ reconnection }); @@ -15,6 +30,14 @@ export const connect_socket = (reconnection=false) => { return raw_socket; } +/* + This is actually the way you should connect a socket in most pages. + This will detect if a connection already exists, and if it does it + simply disconnects, then reconnects. + + If there isn't a connection yet then it will call `connect_socket()` + to establish the first one. + */ export const reconnect_socket = () => { if(raw_socket !== undefined) { raw_socket.disconnect(); diff --git a/client/wt.js b/client/wt.js index 51c363d..7916e54 100644 --- a/client/wt.js +++ b/client/wt.js @@ -1,18 +1,28 @@ +/* + This needs an entire rewrite using the FSM code. Most of this is hacked on + garbage that is unreliable at the best of times. The documentation here is + mostly give what I have a bit of help, and I keep this _mostly_ as an example + of how to work with an older API. In the future I want to rewrite this--or write + an alternative--that uses the `client/fsm.js` library similar to how `HLSVideo.svelte` + works. + */ + const seedTimeout = 60000; import { webtorrent, base_host } from '$/client/config.js'; import assert from "$/client/assert.js"; import { log } from "$/client/logging.js"; -/* This needs an entire rewrite using the FSM code. Most of this is hacked on - * garbage that is unreliable at the best of times. - */ - -// WARNING: having svelte build the webtorrent client into the script makes it slow to load and massive. -// it's much faster to set it as a script variable in the index.html but that might cause loading problems -// WebTorrent then comes from the public/index.html file, not from an import in here let LAZY_CLIENT; // this is lazy loaded by getClient +/* + Load the massive WebTorrent client javascript. + + ___WARNING___: having svelte build the webtorrent client into the script + makes it slow to load and massive. it's much faster to set it as a script + variable in the index.html but that might cause loading problems WebTorrent + then comes from the public/index.html file, not from an import in here + */ const getClient = () => { // super hacks! if(LAZY_CLIENT) { @@ -34,7 +44,20 @@ const getClient = () => { } } +/* + Base class for handling WebTorrent events. Look at the `VideoEvents` class + in `client/components/WTVideo.svelte` for how to use it. You subclass this + if you want to give visual feedback to different events in WebTorrent, such + as new clients connecting, download rates, etc. + */ export class WTEvents { + /* + Takes a `Media` object and video player options, then sets up the + necessary things to make a video play after WebTorrent has downloaded it. + + + `media Media` -- Media object from the database. + + `video_opts Object` -- Default is `{autoplay: false, controls: true, muted: false}`. + */ constructor(media, video_opts) { assert(media, "Media must exist."); this.media = media; @@ -42,12 +65,17 @@ export class WTEvents { this.appendId = `append-${media.target_id}`; } + /* Set the torrent to use. */ setTorrent(torrent) { // TODO: refine this this.media.torrent = torrent; this.torrent = torrent; } + /* + Does the work needed when a video is ready. + Be sure to call it with super if you override. + */ videoReady(file) { this.media.kind = 'video'; file.renderTo(`#${this.appendId}`, this.video_opts); @@ -57,6 +85,10 @@ export class WTEvents { }); } + /* + Same as videoReady. This will setup HTML5 `