about summary refs log blame commit diff
path: root/users/Profpatsch/blog/default.nix
blob: 6cad24507b21f6a4f79824488eef5b45fc234c72 (plain) (tree)
1
2
3
4
5
6
7
8
9
10




                                                                    
                                                                        



                                                                
     







                          
            



                                           





                                                                                     


     






                                                                    
                                   
                                                           

    
                                                                   
                                    

                     
                                                          




                            
                                








                                                                              
                                     
                                                                     

                                       



                    
                                                  



              
                                                       


                                                                         
                                                                               


        
                                                                    
                                                                     
                                                         






                                       
                                      
     
                                                      

                                 
                                                 




                                                 
                                                            


                                                               
                                                        


                                         
                                                        








                                                       
                                                         

                                                                       
                                                      



                                              
                                                         




                                                               
                                                                       































                                                                               

                                                
                                                                    











                                                                              
                                                               














                                                                                                                                                                                                                                                                                         
                                                              


                                                                                       

                                                                                 





                                                                       
                                                     



                                                              
                                           



                                    
                                            






                                                                       

                               

                




                 
{ depot, pkgs, lib, ... }:

let
  bins = depot.nix.getBins pkgs.lowdown [ "lowdown" ]
      // depot.nix.getBins pkgs.cdb [ "cdbget" "cdbmake" "cdbdump" ]
      // depot.nix.getBins pkgs.coreutils [ "mv" "cat" "printf" "test" ]
      // depot.nix.getBins pkgs.s6-networking [ "s6-tcpserver" ]
      // depot.nix.getBins pkgs.time [ "time" ]
      ;

  # /
  toplevel = [
    {
      route = [ "notes" ];
      name = "Notes";
      page = router;
    }
  ];

  # /notes/*
  notes = [
    {
      route = [ "notes" "preventing-oom" ];
      name = "Preventing OOM";
      page = renderNote "preventing-oom" ./notes/preventing-oom.md;
    }
    {
      route = [ "notes" "rust-string-conversions" ];
      name = "Converting between different String types in Rust";
      page = renderNote "rust-string-conversions" ./notes/rust-string-conversions.md;
    }
  ];

  # convert a note to html via lowdown
  renderNote = name: note: depot.nix.runExecline "${name}.html" {} [
    "importas" "out" "out"
    bins.lowdown "-s" "-Thtml" "-o" "$out" note
  ];

  # all notes with `route` converted to an absolute path
  notesFullRoute = lib.pipe notes [
    (map (x@{route, ...}: x // { route = mkRoute route; }))
  ];

  # a cdb from route to a netencoded version of data for each route
  router = lib.pipe notesFullRoute [
    (map (x: {
      name = x.route;
      value = depot.users.Profpatsch.netencode.gen.dwim x;
    }))
    lib.listToAttrs
    (cdbMake "notes-router")
  ];

  # look up a route by path ($1)
  router-lookup = depot.nix.writeExecline "router-lookup" { readNArgs = 1; } [
    cdbLookup router "$1"
  ];

  runExeclineStdout = name: args: cmd: depot.nix.runExecline name args ([
    "importas" "-ui" "out" "out"
    "redirfd" "-w" "1" "$out"
  ] ++ cmd);

  index = runExeclineStdout "index" {
    stdin = depot.users.Profpatsch.netencode.gen.dwim notesFullRoute;
  } [
    "withstdinas" "-in" "TEMPLATE_DATA"
    "pipeline" [
      bins.printf ''
        <ul>
        {{#.}}
          <li><a href="{{route}}">{{name}}<a></li>
        {{/.}}
        </ul>
      ''
    ]
    depot.users.Profpatsch.netencode.netencode-mustache
  ];

  arglibNetencode = val: depot.nix.writeExecline "arglib-netencode" { } [
    "export" "ARGLIB_NETENCODE" (depot.users.Profpatsch.netencode.gen.dwim val)
    "$@"
  ];

  # A simple http server that serves the site. Yes, it’s horrible.
  notes-server = { port }: depot.nix.writeExecline "blog-server" {} [
    (depot.users.Profpatsch.lib.runInEmptyEnv [ "PATH" ])
    bins.s6-tcpserver "127.0.0.1" port
    bins.time "--format=time: %es" "--"
    runOr return400
    "pipeline" [
      (arglibNetencode {
        what = "request";
      })
      depot.users.Profpatsch.read-http
    ]
    depot.users.Profpatsch.netencode.record-splice-env
    runOr return500
    "importas" "-i" "path" "path"
    "if" [ depot.tools.eprintf "GET \${path}\n" ]
    runOr return404
    "backtick" "-ni" "TEMPLATE_DATA" [
      "ifelse" [ bins.test "$path" "=" "/notes" ]
        [ "export" "content-type" "text/html"
          "export" "serve-file" index
          depot.users.Profpatsch.netencode.env-splice-record
        ]
      # TODO: ignore potential query arguments. See 404 message
      "pipeline" [ router-lookup "$path" ]
      depot.users.Profpatsch.netencode.record-splice-env
      "importas" "-ui" "page" "page"
      "export" "content-type" "text/html"
      "export" "serve-file" "$page"
      depot.users.Profpatsch.netencode.env-splice-record
    ]
    runOr return500
    "if" [
      "pipeline" [ bins.printf ''
        HTTP/1.1 200 OK
        Content-Type: {{{content-type}}}; charset=UTF-8
        Connection: close

      '' ]
      depot.users.Profpatsch.netencode.netencode-mustache
    ]
    "pipeline" [ "importas" "t" "TEMPLATE_DATA" bins.printf "%s" "$t" ]
    depot.users.Profpatsch.netencode.record-splice-env
    "importas" "-ui" "serve-file" "serve-file"
    bins.cat "$serve-file"
  ];

  # run argv or $1 if argv returns a failure status code.
  runOr = depot.nix.writeExecline "run-or" { readNArgs = 1; } [
    "foreground" [ "$@" ]
    "importas" "?" "?"
    "ifelse" [ bins.test "$?" "-eq" "0" ]
    []
    "if" [ depot.tools.eprintf "runOr: exited \${?}, running \${1}\n" ]
    "$1"
  ];

  return400 = depot.nix.writeExecline "return400" {} [
    bins.printf "%s" ''
      HTTP/1.1 400 Bad Request
      Content-Type: text/plain; charset=UTF-8
      Connection: close

    ''
  ];

  return404 = depot.nix.writeExecline "return404" {} [
    bins.printf "%s" ''
      HTTP/1.1 404 Not Found
      Content-Type: text/plain; charset=UTF-8
      Connection: close

      This page doesn’t exist! Query arguments are not handled at the moment.
    ''
  ];

  return500 = depot.nix.writeExecline "return500" {} [
    bins.printf "%s" ''
      HTTP/1.1 500 Internal Server Error
      Content-Type: text/plain; charset=UTF-8
      Connection: close

      Encountered an internal server error. Please try again.
    ''
  ];

  capture-stdin = depot.nix.writers.rustSimple {
    name = "capture-stdin";
    dependencies = [ depot.users.Profpatsch.execline.exec-helpers ];
  } ''
    extern crate exec_helpers;
    use std::io::Read;
    fn main() {
      let (args, prog) = exec_helpers::args_for_exec("capture-stdin", 1);
      let valname = &args[1];
      let mut v : Vec<u8> = vec![];
      std::io::stdin().lock().read_to_end(&mut v).unwrap();
      exec_helpers::exec_into_args("capture-stdin", prog, vec![(valname, v)]);
    }
  '';

  # go from a list of path elements to an absolute route string
  mkRoute = route: "/" + lib.concatMapStringsSep "/" urlencodeAscii route;

  # urlencodes, but only ASCII characters
  # https://en.wikipedia.org/wiki/Percent-encoding
  urlencodeAscii = urlPiece:
    let
      raw = [ "!" "#" "$" "%" "&" "'" "(" ")" "*" "+" "," "/" ":" ";" "=" "?" "@" "[" "]" ];
      enc = [ "%21" "%23" "%24" "%25" "%26" "%27" "%28" "%29" "%2A" "%2B" "%2C" "%2F" "%3A" "%3B" "%3D" "%3F" "%40" "%5B" "%5D" ];
      rest = [ "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "-" "_" "." "~" ];
    in
    assert lib.assertMsg (lib.all (c: builtins.elem c (raw ++ rest)) (lib.stringToCharacters urlPiece))
      "urlencodeAscii: the urlPiece must only contain valid url ASCII characters, was: ${urlPiece}";
    builtins.replaceStrings raw enc urlPiece;


  # create a cdb record entry, as required by the cdbmake tool
  cdbRecord = key: val:
    "+${toString (builtins.stringLength key)},${toString (builtins.stringLength val)}:"
    + "${key}->${val}\n";

  # create a full cdbmake input from an attribute set of keys to values (strings)
  cdbRecords =
    with depot.nix.yants;
    defun [ (attrs (either drv string)) string ]
    (attrs:
      (lib.concatStrings (lib.mapAttrsToList cdbRecord attrs)) + "\n");

  # run cdbmake on a list of key/value pairs (strings
  cdbMake = name: attrs: depot.nix.runExecline "${name}.cdb" {
    stdin = cdbRecords attrs;
  } [
    "importas" "out" "out"
    depot.users.Profpatsch.lib.eprint-stdin
    "if" [ bins.cdbmake "db" "tmp" ]
    bins.mv "db" "$out"
  ];

  # look up a key ($2) in the given cdb ($1)
  cdbLookup = depot.nix.writeExecline "cdb-lookup" { readNArgs = 2; } [
    # cdb ($1) on stdin
    "redirfd" "-r" "0" "$1"
    # key ($2) lookup
    bins.cdbget "$2"
  ];

in depot.nix.utils.drvTargets {
   inherit
    router
    notes-server
    index
    router-lookup
    ;

}