warning: this library is a huge work in progress.
main TODOs:
(robusta encoding html) can produce unsafe html(robusta encoding json) does not follow the cited
standardgit grep TODO:this library implements a basic http server
Exported values:
(respond r resp)response(bind port f . logger)l10nizer should be started before calls to make-l10n
as threads don't survive between compile & runtime (when compiling to binaries), l10nizer can dump its map as a thunk to later recover data at runtime
for example:
;; -*- mode: owl; compile-command: "ol -x c -o - temp.scm | tcc -run -" -*-
(import (robusta l10n))
(start-l10nizer)
(make-l10n (EN)
main.greet => "Hello, World!"
main.farwell => "Goodbye, World!")
(make-l10n (RU)
main.greet => "Привет, мир!"
main.farwell => "Прощай, мир!")
(print-to stderr " compile-time")
(print-to stderr (l10n-get 'EN 'main.greet))
(print-to stderr (l10n-get 'RU 'main.greet))
(define restart! (interact 'l10n (tuple 'dump)))
(λ (_)
(print-to stderr " run-time")
(restart!)
(print-to stderr (l10n-get 'EN 'main.farwell))
(print-to stderr (l10n-get 'RU 'main.farwell))
0)Exported values:
(start-l10nizer)(start-l10nizer* base default)make-l10n(make-l10n-getter lang)(l10n-get lang it)safer and faster way to host robusta web applications.
Example configurations, assuming web app running at 127.0.0.1:8080:
<VirtualHost *:80>
DocumentRoot /var/www/html
ProxyPassMatch ^/(.*)$ fcgi://127.0.0.1:8080/
<Directory />
Require all granted
</Directory>
</VirtualHost>
server "robusta.local" {
listen on 0.0.0.0 port 80
log style forwarded
location "*" {
fastcgi socket tcp 127.0.0.1 8080
}
}
Exported values:
(fastcgi-bind port f . logger)Exported values:
make-dispatcher(static-dispatcher from base request)(static-index path ipath)(redirect path . code)(dispatcher lst)with-http-basic-auththis loosely implements the ECMA-404 standard for json encoding and decoding
it can also encode json, where objects are defined like
this: '((a . b) (c . d)), so a list with key-value
pairs.
https://ecma-international.org/publications-and-standards/standards/ecma-404/
Exported values:
(decode s)(encode v)Exported values:
(list->base64 l)(base64->list s)(string->base64 s)(base64->string s)encodedecodeExamples:
(base64->string (string->base64 "abcd")) =
"abcd"Exported values:
(encode-thing v)(encode l)(decode-form-nosym data)(decode-form data)(decode s)this library was originally written for chai but development will continue here.
Exported values:
(encode*/printer lst self-closing-tags f)(encode/printer lst f)(encode* lst self-closing-tags)encode(make-streamer f inexact-buffer-size)Exported values:
(path->mime p)(ext->mime ext)you probably shouldn't use this library by itself. it's nicely
packaged inside of (robusta dispatcher)
Exported values:
(chunked-post-data->file pd path)(chunked-post-data->list pd)(maybe-parse-post-data pd content-type)(parse-by-fd fd)Exported values:
(content-length c)(lowercase s)(flatten l)hex?get-single-hex(bytes->number digits base)(bool->string v)(->string x)(object? lst)Exported values:
(execute* ptr s arg)(start-migrate-thread)(add-migration f)(start-schema-thread schema)(add-column table column t)(get-migrator)(get-schema table)(table-has-column? ptr name col)(list->sql-list lst)define-table(db-refresher db-file)(db)(db-get table items . id)(db-get* table items . id)(db-get-where table items where arg)bind and
fastcgi-bind: (robusta log)Exported values:
(common-date)(make-logger fn)(make-file-logger filename)(make-stdout-logger)No documentation provided.
Exported values:
(exports (robusta dispatcher))(exports (robusta fastcgi))(exports (robusta http))(exports (robusta l10n))(exports (robusta log))(exports (robusta mime))respondresponser/bindb64/encodeb64/decodehtml/encodehtml/encode*html/encode/printerhtml/encode*/printerhtml/make-streamerjson/encodejson/decodeurl/encode-thingurl/encodeurl/decode-formurl/decode(import (robusta server))
(bind
8080
(λ (r)
(respond
r (response
code => 200
content => "hello!"
headers => '((Content-type . "text/html"))))))(import
(robusta server)
(robusta dispatcher))
(define (index request)
(response
code => 200
headers => '((Content-type . "text/html"))
content => "this is the index page"))
(define (about request)
(response
code => 200
headers => '((Content-type . "text/html"))
content => "this is an about page"))
(define dispatcher (make-dispatcher
"/" => index
"/about" => about))
(bind 8080 dispatcher)(import
(robusta full))
(define app
(make-dispatcher
"/" => (λ (req)
(response
content => (λ (stream)
(let loop ((n 10))
(if (= n 0)
#t
(begin
(stream '(#\a 10))
(sleep 500)
(loop (- n 1))))))))))
(bind 8080 app)(import
(robusta server)
(robusta dispatcher))
(define app
(make-dispatcher
"/" => (λ (req)
(with-http-basic-auth (req "login" "password")
(response
code => 200
headers => '((Content-type . "text/html"))
content => "ok")))))
(bind 8080 app)(import (prefix (robusta encoding json) json/))
(define json-string "[1, 2, [3], [[4]], [[[5]]], [[[[6]]]], 7]")
(define json-structure '((a . "10") (b . #f)))
(print (json/decode json-string)) ; → (1 2 (3) ((4)) (((5))) ((((6)))) 7)
(print (json/encode json-structure)) ; → {"a":"10","b":false}(import
(prefix (robusta server) robusta/)
(prefix (robusta dispatcher) robusta/)
(prefix (robusta encoding html) html/))
(define (idx request)
(robusta/response
code => 200
headers => '((Content-type . "text/html"))
content => (html/encode '(html (head) (body (p "this the only page"))))))
(robusta/bind 8080 (robusta/make-dispatcher "m/^.*$/" => idx))If you have a bigger document, you should probably "stream" it
instead of constructing a big string with the final html code. This will
be faster, as constructing strings like it is done in
html/encode is a both memory and cpu heavy operation in
owl.
(import
(robusta full))
(define html
`(html
(head ((link (rel . "stylesheet") (href . "style.css"))))
(body
,@(map
(λ (i) `((p (class . "klass")) ,(str "test" i)))
(iota 0 1 1000)))))
(define I* (λ (_) I*))
(print ";; Defined html")
(print ";; html/encode ->string")
,time (html/encode html)
(print ";; html/encode/printer")
,time (html/encode/printer html I*)
;; ^
;; this function is the "streaming" function
;; it is of a form (λ (s) whatever), where s is either
;; * a string of "something" that is the continuation of a html document, or
;; * eof-object
;; it MUST return either itself, or another function. its return value will be used in every consequent call
;; as the function getting called, so it's possible to have user data flowing
;;; This is also an example of what can be used as (λ (s) whatever) in encode/printer context (as a printer)
(define (displayer-to fd)
(letrec ((f (λ (s)
(display-to fd s)
f))) ; it returns itself
f))
(print ";; html/encode/printer w/ 2kb streamer")
,time (html/encode/printer html (html/make-streamer I (<< 1 11)))
;; ^- this is ANY λs.whatever, it does not need to return anything meaningful
;; it may be `display' or whatever you please(import
(robusta server)
(robusta dispatcher)
(prefix (robusta encoding html) html/))
(define index-html
(html/encode
`(html
(head)
(body "see the static pages" ((a (href . "static/")) "here")))))
(define (static! req) (static-dispatcher "static" "/static/" req))
;; ^ ^
;; | \_ static route url base
;; \_ directory with static files
(define dis (make-dispatcher
"m/static(\\/.*)?/" => static!
"m/\\/?/" => (λ (req)
(response
code => 200
headers => '((Content-type . "text/html"))
content => index-html))))
(bind 8080 dis)(import
(robusta server)
(robusta log)
(robusta dispatcher))
(define logger (make-stdout-logger))
(define app (make-dispatcher "/" => (λ _ (response content => "hello"))))
(bind 8080 app logger)(import
(robusta server)
(prefix (robusta dispatcher) D/)
(prefix (robusta encoding html) html/))
(define dispatcher
(D/make-dispatcher
"/" => (λ (req)
(let* ((M (get req 'method #f))
(n (if (eqv? M 'GET)
0
(string->number (cdr (assq 'n (get req 'post-data #n)))))))
(response
code => 200
headers => '((Content-type . "text/html"))
content => (html/encode
`(body
(p "n: " ,n)
((form (method . "POST"))
((input (type . "hidden")
(name . "n")
(value . ,(number->string (+ n 1)))))
(button "+"))
((form (method . "POST"))
((input (type . "hidden")
(name . "n")
(value . ,(number->string (- n 1)))))
(button "-")))))))))
(bind 8080 dispatcher)(import
(prefix (robusta db tsv) tsv/)
(prefix (owl sys) sys/))
(define (self s) s)
(define dbname "db.tsv")
(define schema
;; col-name type-pred thing->string string->thing
`((uname ,string? ,self ,self)
(passwd ,string? ,self ,self)
(secret-num ,number? ,number->string ,string->number)))
(when (sys/file? dbname)
(sys/unlink dbname))
;; th = tsv handle
(define th (tsv/open "db.tsv" schema))
(tsv/insert-into th '("admin" "zaq1@WSX" 10))
(tsv/insert-into th '("user0" "helloworld" 120))
(print (tsv/filter-by th (λ (u p s) (= s 120))))
(print (tsv/get-column th 'passwd))
(tsv/delete-from th (λ (u p s) (string-ci=? u "USER0")))
(print (tsv/get-all th))
(tsv/close th)(import (prefix (robusta encoding url) url/))
(define al '((a . b) (c . d) (e . 10) (f . "1") (g . #false)))
;; everything str'd as types get stripped
(print (string=? (str (url/decode-form (url/encode al))) (str al)))