diff options
Diffstat (limited to 'fig-frontend-client/src')
| -rw-r--r-- | fig-frontend-client/src/Audio.js | 30 | ||||
| -rw-r--r-- | fig-frontend-client/src/Audio.purs | 10 | ||||
| -rw-r--r-- | fig-frontend-client/src/Auth.js | 45 | ||||
| -rw-r--r-- | fig-frontend-client/src/Auth.purs | 29 | ||||
| -rw-r--r-- | fig-frontend-client/src/Config.js | 4 | ||||
| -rw-r--r-- | fig-frontend-client/src/Config.purs | 6 | ||||
| -rw-r--r-- | fig-frontend-client/src/Main.purs | 156 | ||||
| -rw-r--r-- | fig-frontend-client/src/Model.js | 108 | ||||
| -rw-r--r-- | fig-frontend-client/src/Model.purs | 10 | ||||
| -rw-r--r-- | fig-frontend-client/src/UI.js | 2 | ||||
| -rw-r--r-- | fig-frontend-client/src/UI.purs | 13 |
11 files changed, 0 insertions, 413 deletions
diff --git a/fig-frontend-client/src/Audio.js b/fig-frontend-client/src/Audio.js deleted file mode 100644 index 2a9ae54..0000000 --- a/fig-frontend-client/src/Audio.js +++ /dev/null @@ -1,30 +0,0 @@ -let initialized = false; -let ctx = null; -let voiceTracks = null; - -function initializeCtx() { - if (!initialized) { - try { - initialized = true; - ctx = new window.AudioContext(); - voiceTracks = [ - document.getElementById("lcolonq-audio-voice-0"), - document.getElementById("lcolonq-audio-voice-1"), - document.getElementById("lcolonq-audio-voice-2"), - document.getElementById("lcolonq-audio-voice-3"), - document.getElementById("lcolonq-audio-voice-4"), - document.getElementById("lcolonq-audio-voice-5"), - document.getElementById("lcolonq-audio-voice-6"), - ]; - } catch (e) { - initialized = false; - } - } -} - -export const _playVoice = (b) => (i) => () => { - if (b) initializeCtx(); - try { - if (initialized) voiceTracks[i].play(); - } catch (e) {} -}; diff --git a/fig-frontend-client/src/Audio.purs b/fig-frontend-client/src/Audio.purs deleted file mode 100644 index 8f1f319..0000000 --- a/fig-frontend-client/src/Audio.purs +++ /dev/null @@ -1,10 +0,0 @@ -module Audio where - -import Prelude - -import Effect (Effect) -import Effect.Class (class MonadEffect, liftEffect) - -foreign import _playVoice :: Boolean -> Int -> Effect Unit -playVoice :: forall m. MonadEffect m => Boolean -> Int -> m Unit -playVoice b i = liftEffect $ _playVoice b i diff --git a/fig-frontend-client/src/Auth.js b/fig-frontend-client/src/Auth.js deleted file mode 100644 index 7254c40..0000000 --- a/fig-frontend-client/src/Auth.js +++ /dev/null @@ -1,45 +0,0 @@ -function generateNonce() { - var arr = new Uint8Array(20); - window.crypto.getRandomValues(arr); - return Array.from(arr, b => b.toString(16).padStart(2, "0")).join(""); -} - -export const _startTwitchAuth = (clientID) => (redirectURL) => () => { - const nonce = generateNonce(); - document.cookie = `authnonce=${nonce}; path=/; max-age=3000`; - window.location.href = - `https://id.twitch.tv/oauth2/authorize?response_type=id_token` - + `&client_id=${clientID}` - + `&redirect_uri=${redirectURL}` - + `&scope=openid` - + `&nonce=${nonce}` - + `&claims=${JSON.stringify({id_token: {preferred_username: null}})}` - ; -}; - -function getFragmentQuery() { - let query = new Map(); - const hashQuery = document.location.hash.slice(1).split("&"); - for (let equals of hashQuery) { - const pair = equals.split("="); - query.set(decodeURIComponent(pair[0]), decodeURIComponent(pair[1])); - } - return query; -} - -export const _getToken = (Just) => (Nothing) => (pair) => () => { - const frag = getFragmentQuery(); - const token = frag.get("id_token"); - if (token) { - document.cookie = `id_token=${token}; path=/; SameSite=Strict`; - } - let id_token = null; - let authnonce = null; - for (let c of document.cookie.split("; ")) { - const [k, v] = c.split("="); - if (k === "id_token") id_token = v; - else if (k === "authnonce") authnonce = v; - } - if (id_token && authnonce) return Just(pair(id_token)(authnonce)); - return Nothing; -}; diff --git a/fig-frontend-client/src/Auth.purs b/fig-frontend-client/src/Auth.purs deleted file mode 100644 index 2a53629..0000000 --- a/fig-frontend-client/src/Auth.purs +++ /dev/null @@ -1,29 +0,0 @@ -module Auth where - -import Prelude - -import Config (authRedirectURL, clientID) -import Data.Array (fold) -import Data.Maybe (Maybe(..)) -import Data.Tuple (Tuple(..)) -import Effect (Effect) -import Effect.Class (class MonadEffect, liftEffect) - -foreign import _startTwitchAuth :: String -> String -> Effect Unit -startTwitchAuth :: forall m. MonadEffect m => m Unit -startTwitchAuth = liftEffect $ _startTwitchAuth clientID authRedirectURL - -type AuthInfo = Tuple String String -foreign import _getToken :: forall a. (a -> Maybe a) -> Maybe a -> (a -> a -> Tuple a a) -> Effect (Maybe (Tuple String String)) -getToken :: forall m. MonadEffect m => m (Maybe AuthInfo) -getToken = liftEffect $ _getToken Just Nothing Tuple - -authHeader :: AuthInfo -> String -authHeader (Tuple t n) = - fold - [ "FIG-TWITCH token=\"" - , t - , "\", nonce=\"" - , n - , "\"" - ] diff --git a/fig-frontend-client/src/Config.js b/fig-frontend-client/src/Config.js deleted file mode 100644 index 25259c7..0000000 --- a/fig-frontend-client/src/Config.js +++ /dev/null @@ -1,4 +0,0 @@ -export const mode = globalThis.mode; -export const apiServer = globalThis.apiServer; -export const clientID = globalThis.clientID; -export const authRedirectURL = globalThis.authRedirectURL; diff --git a/fig-frontend-client/src/Config.purs b/fig-frontend-client/src/Config.purs deleted file mode 100644 index 536f163..0000000 --- a/fig-frontend-client/src/Config.purs +++ /dev/null @@ -1,6 +0,0 @@ -module Config where - -foreign import mode :: Int -foreign import apiServer :: String -foreign import clientID :: String -foreign import authRedirectURL :: String diff --git a/fig-frontend-client/src/Main.purs b/fig-frontend-client/src/Main.purs deleted file mode 100644 index 48a6e9d..0000000 --- a/fig-frontend-client/src/Main.purs +++ /dev/null @@ -1,156 +0,0 @@ -module Main where - -import Prelude - -import Audio as Audio -import Auth (AuthInfo, authHeader, getToken, startTwitchAuth) -import Config as Config -import Data.Array (head) -import Data.Array as Array -import Data.Foldable (fold) -import Data.Maybe (Maybe(..)) -import Data.Traversable (for, for_) -import Data.Tuple (Tuple(..)) -import Effect (Effect) -import Effect.Aff (Aff, launchAff_) -import Effect.Class (class MonadEffect, liftEffect) -import Effect.Console (log) -import Effect.Exception (throw) -import Fetch (fetch) -import Model (startModel) -import UI as UI -import Web.DOM as DOM -import Web.DOM.DOMTokenList as DOM.DTL -import Web.DOM.Document (doctype) -import Web.DOM.Document as DOM.Doc -import Web.DOM.Element as DOM.El -import Web.DOM.Node as DOM.Node -import Web.DOM.NodeList as DOM.NL -import Web.DOM.NonElementParentNode as DOM.NEP -import Web.DOM.ParentNode as DOM.P -import Web.DOM.Text as DOM.Text -import Web.Event.Event as Ev -import Web.Event.EventTarget as Ev.Tar -import Web.HTML as HTML -import Web.HTML.HTMLDocument as HTML.Doc -import Web.HTML.Window as HTML.Win - -maybeToArray :: forall a. Maybe a -> Array a -maybeToArray (Just x) = [x] -maybeToArray Nothing = [] - -byId :: forall m. MonadEffect m => String -> m DOM.Element -byId i = do - w <- liftEffect HTML.window - d <- liftEffect $ HTML.Doc.toDocument <$> HTML.Win.document w - liftEffect (DOM.NEP.getElementById i (DOM.Doc.toNonElementParentNode d)) >>= case _ of - Nothing -> liftEffect $ throw $ "could not find element with id: " <> i - Just e -> pure e - -queryAll :: forall m. MonadEffect m => String -> m (Array DOM.Element) -queryAll q = do - w <- liftEffect HTML.window - d <- liftEffect $ HTML.Doc.toDocument <$> HTML.Win.document w - nl <- liftEffect (DOM.P.querySelectorAll (DOM.P.QuerySelector q) (DOM.Doc.toParentNode d)) - ns <- liftEffect $ DOM.NL.toArray nl - pure $ fold $ (maybeToArray <<< DOM.El.fromNode) <$> ns - -query :: forall m . MonadEffect m => String -> m DOM.Element -query q = do - queryAll q >>= head >>> case _ of - Nothing -> liftEffect $ throw $ "could not find element matching query: " <> q - Just x -> pure x - -listen :: forall m. MonadEffect m => DOM.Element -> String -> (Ev.Event -> Effect Unit) -> m Unit -listen e ev f = do - l <- liftEffect $ Ev.Tar.eventListener f - liftEffect $ Ev.Tar.addEventListener (Ev.EventType ev) l false $ DOM.El.toEventTarget e - -create :: forall m. MonadEffect m => String -> Array String -> Array DOM.Element -> m DOM.Element -create tag classes children = do - w <- liftEffect HTML.window - d <- liftEffect $ HTML.Doc.toDocument <$> HTML.Win.document w - el <- liftEffect $ DOM.Doc.createElement tag d - cl <- liftEffect $ DOM.El.classList el - for_ classes \c -> - liftEffect $ DOM.DTL.add cl c - for_ children \c -> - appendElement el c - pure el - -appendElement :: forall m. MonadEffect m => DOM.Element -> DOM.Element -> m Unit -appendElement parent child = liftEffect $ DOM.Node.appendChild (DOM.El.toNode child) (DOM.El.toNode parent) - -appendText :: forall m. MonadEffect m => DOM.Element -> String -> m Unit -appendText parent s = do - w <- liftEffect HTML.window - d <- liftEffect $ HTML.Doc.toDocument <$> HTML.Win.document w - n <- liftEffect $ DOM.Doc.createTextNode s d - liftEffect $ DOM.Node.appendChild (DOM.Text.toNode n) (DOM.El.toNode parent) - -setText :: forall m. MonadEffect m => DOM.Element -> String -> m Unit -setText e s = liftEffect $ DOM.Node.setTextContent s $ DOM.El.toNode e - -updateSubtitle :: Aff Unit -updateSubtitle = do - subtitle <- byId "lcolonq-subtitle" - { text: catchphrase } <- fetch (Config.apiServer <> "/catchphrase") {} - catchphrase >>= setText subtitle - -checkAuth :: AuthInfo -> Aff String -checkAuth auth = do - { text: resp } <- - fetch (Config.apiServer <> "/check") - { headers: - { "Authorization": authHeader auth - } - } - resp - -mainHomepage :: Effect Unit -mainHomepage = launchAff_ do - liftEffect $ log "hi" - startModel - marq <- byId "lcolonq-marquee" - { text: motd } <- fetch (Config.apiServer <> "/motd") {} - motd >>= setText marq - - getToken >>= case _ of - Just a@(Tuple t n) -> do - liftEffect $ log t - liftEffect $ log n - checkAuth a >>= log >>> liftEffect - _ -> pure unit - - updateSubtitle - subtitle <- byId "lcolonq-subtitle" - listen subtitle "click" \_ev -> do - startTwitchAuth - launchAff_ updateSubtitle - - for_ (Array.range 0 6) \i -> do - letter <- byId $ "lcolonq-letter-" <> show i - listen letter "click" \_ev -> do - Audio.playVoice true i - listen letter "mouseover" \_ev -> do - Audio.playVoice false i - -mainExtension :: Effect Unit -mainExtension = launchAff_ do - liftEffect $ log "hello from extension" - UI.setInterval 1000.0 do - e <- query ".chat-scrollable-area__message-container" - new <- create "div" [".chat-line__message"] [] - appendText new "test" - appendElement e new - -mainObs :: Effect Unit -mainObs = launchAff_ do - startModel - -main :: Effect Unit -main = case Config.mode of - 0 -> mainHomepage - 1 -> mainExtension - 2 -> mainObs - _ -> throw "unknown mode" diff --git a/fig-frontend-client/src/Model.js b/fig-frontend-client/src/Model.js deleted file mode 100644 index 797bae4..0000000 --- a/fig-frontend-client/src/Model.js +++ /dev/null @@ -1,108 +0,0 @@ -let canvas = document.getElementById("lcolonq-canvas"); -let socket = null; -let currentFrame = null; - -async function decompress(blob) { - let ds = new DecompressionStream("gzip"); - let stream = blob.stream(); - let out = await new Response(stream.pipeThrough(ds)); - return out.arrayBuffer(); -} - -function readCell(dv, base) { - let cell = {}; - let o = base; - if (dv.getUint8(o) == 0) { - return [{type: "bg"}, o + 1]; - } else { - cell.type = "fg"; - cell.custom = dv.getUint8(o + 1); - cell.r = dv.getUint8(o + 2); - cell.g = dv.getUint8(o + 3); - cell.b = dv.getUint8(o + 4); - cell.g0 = dv.getUint32(o + 5); - if (dv.getUint8(o + 9) == 0) { - return [cell, o + 10]; - } else { - cell.g1 = dv.getUint32(o + 10); - return [cell, o + 14]; - } - } -} - -function readKeyframe(dv, base) { - let ret = []; - let o = base; - for (let idx = 0; idx < (64 * 64); ++idx) { - let res = readCell(dv, o); - ret.push(res[0]); - o = res[1]; - } - currentFrame = ret; -} - -function readDiff(dv, base) { - if (currentFrame) { - let len = dv.getUint32(base); - let o = base + 4; - for (let idx = 0; idx < len; ++idx) { - let x = dv.getUint8(o); - let y = dv.getUint8(o + 1); - let c = readCell(dv, o + 2); - currentFrame[x + (y * 64)] = c[0]; - o = c[1]; - } - } -} - -function readPacket(dv) { - if (dv.getUint8(0) == 0) { - readKeyframe(dv, 1); - } else { - readDiff(dv, 1); - } -} - -function renderCellCanvas(ctx, x, y, c) { - if (c && c.type === "fg") { - let msg = c.g1 ? String.fromCodePoint(c.g0, c.g1) : String.fromCodePoint(c.g0); - if (msg.trim().length) { - ctx.fillStyle = "black"; - ctx.fillRect(13 * y, 13 * x, 13, 13); - ctx.fillStyle = `rgba(${c.r}, ${c.g}, ${c.b}, 1.0)`; - ctx.fillText(msg, 13 * y, 13 * x + 10); - } - } -} - -function renderCanvas() { - if (canvas.width != canvas.clientWidth) { - canvas.width = canvas.clientWidth; - } - if (canvas.height != canvas.clientHeight) { - canvas.height = canvas.clientHeight; - } - if (currentFrame) { - let ctx = canvas.getContext("2d"); - ctx.clearRect(0, 0, canvas.width, canvas.height); - ctx.font = "12px Iosevka Comfy"; - for (let y = 0; y < 64; ++y) { - for (let x = 0; x < 64; ++x) { - renderCellCanvas(ctx, x, y, currentFrame[(x * 64) + y]); - } - } - } -} - -export const _startModel = () => { - socket = new WebSocket("wss://colonq.computer/bullfrog/api/channel/listen/model"); - socket.addEventListener("open", (ev) => { - console.log("connected"); - }); - socket.addEventListener("message", async (ev) => { - let arr = await decompress(ev.data); - let view = new DataView(arr); - readPacket(view); - renderCanvas(); - }); -}; diff --git a/fig-frontend-client/src/Model.purs b/fig-frontend-client/src/Model.purs deleted file mode 100644 index a9f2888..0000000 --- a/fig-frontend-client/src/Model.purs +++ /dev/null @@ -1,10 +0,0 @@ -module Model where - -import Prelude - -import Effect (Effect) -import Effect.Class (class MonadEffect, liftEffect) - -foreign import _startModel :: Effect Unit -startModel :: forall m. MonadEffect m => m Unit -startModel = liftEffect _startModel diff --git a/fig-frontend-client/src/UI.js b/fig-frontend-client/src/UI.js deleted file mode 100644 index 0b00e5d..0000000 --- a/fig-frontend-client/src/UI.js +++ /dev/null @@ -1,2 +0,0 @@ -export const _cheatLog = (a) => () => console.log(a); -export const _setInterval = (delay) => (f) => () => setInterval(f, delay); diff --git a/fig-frontend-client/src/UI.purs b/fig-frontend-client/src/UI.purs deleted file mode 100644 index 49d797a..0000000 --- a/fig-frontend-client/src/UI.purs +++ /dev/null @@ -1,13 +0,0 @@ -module UI where - -import Prelude -import Effect (Effect) -import Effect.Class (class MonadEffect, liftEffect) - -foreign import _cheatLog :: forall a. a -> Effect Unit -cheatLog :: forall m a. MonadEffect m => a -> m Unit -cheatLog x = liftEffect $ _cheatLog x - -foreign import _setInterval :: Number -> Effect Unit -> Effect Unit -setInterval :: forall m. MonadEffect m => Number -> Effect Unit -> m Unit -setInterval d f = liftEffect $ _setInterval d f |
