From 9493e2dbf9671d55fea2a96aa057589670e9673a Mon Sep 17 00:00:00 2001 From: Ben Sima Date: Tue, 31 Mar 2020 17:12:09 -0700 Subject: Massively improve the que-website curl was throwing an exception if the file got too long, because I was passing the entire file contents in the arguments to curl. I tried using a tmp file but that didn't work for some reason. So I switched to req and that seems to work well. I also made it faster by serving all pages concurrently, and I spruced up the CSS a ton. --- Run/Que/Website.hs | 102 ++++++++++++++++++++++++++++---------------- Run/Que/index.md | 47 ++++----------------- Run/Que/quescripts.md | 38 +++++++++++++++++ Run/Que/style.css | 114 ++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 224 insertions(+), 77 deletions(-) create mode 100644 Run/Que/quescripts.md (limited to 'Run/Que') diff --git a/Run/Que/Website.hs b/Run/Que/Website.hs index 1de6bca..e6b458c 100644 --- a/Run/Que/Website.hs +++ b/Run/Que/Website.hs @@ -1,45 +1,77 @@ +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE LambdaCase #-} + -- | spawns a few processes that serve the que.run website module Run.Que.Website where -import Prelude +import qualified Control.Concurrent.Async as Async +import qualified Data.ByteString.Char8 as BS +import qualified Data.Text as Text +import Network.HTTP.Req +import Protolude import System.Environment as Environment import System.FilePath ( () ) import qualified System.Process as Process +import qualified System.Exit as Exit main :: IO () main = do - args <- Environment.getArgs - let [src, ns] = if length args == 2 - then take 2 args - else if length args == 1 - then args ++ ["/"] - else error "usage: que-website [namespace]" - homepage <- getHomepageHtml (src "style.css") (src "index.md") - client <- readFile $ src "client.py" + (src, ns) <- Environment.getArgs >>= \case + [src] -> return (src, "/") + [src, ns] -> return (src, ns) + _ -> Exit.die "usage: que-website [namespace]" + putStrLn $ "serving " ++ src ++ " at " ++ ns - loop ns homepage client - -loop :: String -> FilePath -> FilePath -> IO () -loop ns homepage client = - serve (ns "index.html") homepage - >> serve (ns "_client/python") client - >> loop ns homepage client - -getHomepageHtml :: String -> String -> IO String -getHomepageHtml style index = Process.readProcess - "pandoc" - [ "--self-contained" - , "--css" - , style - , "-i" - , index - , "--from" - , "markdown" - , "--to" - , "html" - ] - [] - -serve :: FilePath -> FilePath -> IO () -serve path file = - Process.callProcess "curl" ["https://que.run" ++ path, "-d", file] + loop (Text.pack ns) $ Sources { index = src "index.md" + , client = src "client.py" + , quescripts = src "quescripts.md" + , style = src "style.css" + } + +data Sources = Sources + { index :: FilePath + , quescripts :: FilePath + , client :: FilePath + , style :: FilePath + } + +loop :: Text -> Sources -> IO () +loop ns pages@Sources {..} = do + _ <- + Async.runConcurrently + $ (,,,) + <$> Async.Concurrently + (toHtml style index >>= serve (https "que.run" /: ns /: "index.html")) + <*> Async.Concurrently + ( BS.readFile client + >>= serve (https "que.run" /: ns /: "_client" /: "python") + ) + <*> Async.Concurrently + ( toHtml style quescripts + >>= serve (https "que.run" /: ns /: "_page" /: "quescripts") + ) + loop ns pages + + +toHtml :: FilePath -> FilePath -> IO ByteString +toHtml style md = + BS.pack + <$> Process.readProcess + "pandoc" + [ "--self-contained" + , "--css" + , style + , "-i" + , md + , "--from" + , "markdown" + , "--to" + , "html" + ] + [] + +serve :: Url scheme -> ByteString -> IO () +serve path content = runReq defaultHttpConfig $ do + _ <- req POST path (ReqBodyBs content) ignoreResponse mempty + liftIO $ return () diff --git a/Run/Que/index.md b/Run/Que/index.md index b619de7..59a7ad8 100644 --- a/Run/Que/index.md +++ b/Run/Que/index.md @@ -12,7 +12,7 @@ que is the concurrent, async runtime in the cloud HTTP routes on que.run are Golang-like channels with a namespace and a path. For example: `https://que.run/example/path/subpath`. -## download the client +## Quickstart There is a simple script `que` that acts as a client you can use to interact with the `que.run` service. @@ -25,44 +25,13 @@ Download it to somewhere on your `$PATH` and make it executable: The client requires a recent version of Python 3. -## examples +## Quescripts -Here are some example applications, I will update these in the coming -weeks with additional useful scripts. +We are collecting a repository of scripts that make awesome use of que: -### desktop notifications +- remote desktop notifications +- two-way communication with your phone +- ephemeral, serverless chat rooms +- collaborative jukebox -Lets say we are running a job that takes a long time, maybe we are -compiling or running a large test suite. Instead of watching the -terminal until it completes, or flipping back to check on it every so -often, we can create a listener that displays a popup notification when -the job finishes. - -In one terminal run the listener: - - que example/notify --then "notify-send '\que' '\msg'" - -In some other terminal run the job that takes forever: - - runtests ; echo "tests are done" | que example/notify - - -When terminal 2 succeeds, terminal 1 will print "tests are done", then -call the `notify-send` command, which displays a notification toast in -Linux with title "`example/notify`" and content "`tests are done`". - -Que paths are multi-producer and multi-consumer, so you can add as many -terminals as you want. - -On macOS you could use: - - osascript -e 'display notification "\msg" with title "\que"' - -in place of notify-send. - -### ephemeral, serverless chat rooms - -coming soon... - -### collaborative jukebox - -coming soon... +See the examples diff --git a/Run/Que/quescripts.md b/Run/Que/quescripts.md new file mode 100644 index 0000000..204328a --- /dev/null +++ b/Run/Que/quescripts.md @@ -0,0 +1,38 @@ +% Quescripts + +## Remote desktop notifications + +Lets say we are running a job that takes a long time, maybe we are +compiling or running a large test suite. Instead of watching the +terminal until it completes, or flipping back to check on it every so +often, we can create a listener that displays a popup notification when +the job finishes. + +In one terminal run the listener: + + que example/notify --then "notify-send '\que' '\msg'" + +In some other terminal run the job that takes forever: + + runtests ; echo "tests are done" | que example/notify - + +When terminal 2 succeeds, terminal 1 will print "tests are done", then +call the `notify-send` command, which displays a notification toast in +Linux with title "`example/notify`" and content "`tests are done`". + +Que paths are multi-producer and multi-consumer, so you can add as many +terminals as you want. + +On macOS you could use: + + osascript -e 'display notification "\msg" with title "\que"' + +in place of notify-send. + +## Ephemeral, serverless chat rooms + +coming soon + +## Collaborative jukebox + +coming soon diff --git a/Run/Que/style.css b/Run/Que/style.css index fa73fa4..1933a5d 100644 --- a/Run/Que/style.css +++ b/Run/Que/style.css @@ -1,4 +1,112 @@ -/* perfect motherfucking css framework */ -body{max-width:650px;margin:40px auto;padding:0 10px;font:18px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";color:#444}h1,h2,h3{line-height:1.2}@media (prefers-color-scheme: dark){body{color:white;background:#444}a:link{color:#5bf}a:visited{color:#ccf}} +:root { + /* base (http://chriskempson.com/projects/base16/) */ + --base00: #181818; + --base01: #282828; + --base02: #383838; + --base03: #585858; + --base04: #b8b8b8; + --base05: #d8d8d8; + --base06: #e8e8e8; + --base07: #f8f8f8; -/* my stuff */ + /* highlights */ + --base08: #ab4642; + --base09: #dc9656; + --base0A: #f7ca88; + --base0B: #a1b56c; + --base0C: #86c1b9; + --base0D: #7cafc2; + --base0E: #ba8baf; + --base0F: #a16946; +} + +@import 'https://fonts.googleapis.com/css?family=Galada:400|Open+Sans:400,300'; + +/* dark theme */ +@media ( prefers-color-scheme: dark ), ( prefers-color-scheme: no-preference ) { + body + { color: var(--base05); + ; background: var(--base00) + } + + header, h1, h2, h3 + { color: var(--base0A) } + + a:link, a:link button, a:visited, a:visited button + { color: var(--base0D) } + + a:hover + { color: var(--base0C) } + + pre + { background-color: var(--base01) } + + code + { color: var(--base0B) + } +} + +/* light theme */ + +@media ( prefers-color-scheme: light) { + body + { background-color: var(--base07) + ; color: var(--base00) + } + + pre + { background-color: var(--base06) } + + code + { color: var(--base0B) } +} + +/* structure and layout */ + +body +{ max-width: 650px +; margin: 40px auto +; padding: 0 10px +; font: 18px/1.5 + "Open Sans", + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol", + "Noto Color Emoji" +; display: flex +; flex-direction: column +; align-items: auto +} + +header#title-block-header, +h1, +h2, +h3 +{ line-height: 1.2 +; align-self: center +; text-transform: lowercase +} + +pre +{ padding: .5rem } + +pre,code +{ overflow-x: scroll +; white-space: pre +} + +#quescripts-btn +{ border-width: 2px +; border-style: solid +} + +#quescripts-btn +{ font-size: 1.2rem +; padding: 1rem +; text-decoration: none +; text-align: center +; display: block +; max-width: 400px +; margin: auto +} -- cgit v1.2.3