v hyper.dev · Petit Cloud - 1 - Kickstart

In the previous article, we set a goal to deploy a program in one hip command line hop, let’s kickstart the code with an outline of the application server.

Any resemblance to competitor technology is wholly, and fully coincidental.

Continuation

We want to deploy http web application stuffed into a hello library that looks like the following:

;; hello.scm
(library (hello)
  (export main)
  (import (petit-cloud application))

  (define main
    (lambda (method path headers body)
      (values 200
              (list (cons 'content-type "text/plain"))
              (string->utf8 "Hello schemer!\n")))))

The expected, so called workflow, is that given an existing application server running at www.example:9999, we want to deploy the above library with the following one-liner:

#;sh> petit-cloud deploy www.example:9999 hello.scm

When that command is issued, we will be prompted for a password, after a nanowhile, we will be able the manually test it with:

#;sh> curl http://www.example:9999
Hello schemer!

The application server will be listening to port 9999 of all available network interfaces, that can be done with:

(define-values (client-accept close)
  (petit-cloud-http-connect "0.0.0.0" 9999))

The variable client-socket is a generator of three objects read, write, and close, that work as follow:

The simplest way to use it is:

(define-values (client-accept close)
  (petit-cloud-http-connect "0.0.0.0" 9999))

(define-values (read write close)
  ;; client-accept will pause
  ;; until a HTTP request hit
  ;; the port 9999
  (client-accept))

(define-values (method url headers body) (read))
;; let's reply
(write 200
       (list (cons 'content-type "text/plain"))
       (string->utf8 "Hello schemers\n"))
(close)

It is possible accept multiple clients simultaneously, by passing a procedure to petit-cloud-http-connect:

(define client-accept
  (lambda (read write close)
    ;; where is everyone
    (define-values (method url headers body) (read))
    ;; reply
    (write 200
           (list (cons 'content-type "text/plain"))
           (string->utf8 "Hello schemers\n"))
    ;; the end
    (close)))
           
(petit-cloud-http-connect "0.0.0.0"
                          9999
                          client-accept)

The command call petit-cloud deploy will hit the application server with a method that is the symbol 'POST, and an url that is:

(list 9999
      (list "example" "www")
      ("_" "api" "petit" "cloud")
      (list)
      (list))

And the body is the bytevector representation of hello.scm at the start of the article.

We can implement a predicate that returns #t when it is a call by petit-cloud deploy:

(define petit-cloud-deploy?
  (lambda (method path)
    (equal? (cons 'POST 
                  (list 9999
                        (list "example" "www")
                        ("_" "api" "petit" "cloud")
                        (list)
                        (list)))
            (cons method path))))

If the request is not a deployment, we fallback to the application procedure returned by the parameter petit-cloud-current-application.

At this point, and without any error handling, our application server code looks like the following:

(import (petit-cloud))


(define petit-cloud-deploy?
  (lambda (method path)
    (equal (cons 'POST 
                 (list 9999
                       ;; TODO: do not hardcode port, and domain
                       (list "example" "www")
                       (list "_" "api" "petit" "cloud")
                       (list)
                       (list)))
           (cons method path))))

(define client-accept
  (lambda (read write close)
    (define-values (method url headers body) (read))
    (if (petit-cloud-deploy? method path)
        (let ((application (make-petit-cloud-application body)))
          (petit-cloud-current-application application)
          (values 201 (list) (bytevector)))
        (let ((application (petit-cloud-current-application)))
          (application method url headers body)))))
           
(petit-cloud-http-connect "0.0.0.0" 9999 client-accept)

Backtracking

Let’s summarize:

What (make-petit-cloud-application body) do is very interesting. Tho, at this time, that is only food for thought.

happy jumping broccoli is food