Giter VIP home page Giter VIP logo

lucerne's Introduction

Lucerne: a web framework

Build Status Coverage Status Quicklisp

Read the docs.

Usage

(defapp app)

@route app "/"
(defview index ()
  (respond "<h1>Welcome to Lucerne</h1>"))

@route app "/greet/:name"
(defview greet (name)
  (respond (format nil "Hello, ~A!" name)))

(start app)

License

Copyright (c) 2014-2018 Fernando Borretti ([email protected])

Licensed under the MIT License.

lucerne's People

Contributors

eudoxia0 avatar gschjetne avatar jorams avatar nightblues avatar zodmaner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lucerne's Issues

Please move to Clack v2 and Lack

I'm going to delete clack-v1-compat in the near future at fukamachi/clack#141.

The reason is that I found a failed test in clack-v1-compat, and I couldn't find easy way to fix it.
v2 is now fairy stable and I don't feel it's reasonable to maintain the both code base.

Please consider to switching to Clack v2 and Lack.

Strange disconnection on Android, Appcelerator Titanium client

I am running into a rather curious problem while using this particular client with a backend API I wrote using Lucerne.

What happens on the TCP side of things is the reply seems to be sent back to the client, but the ACK to the reply is never received and the client times out. With bare Clack everything works just fine. I am using SBCL 1.3.5 at the moment.

Other clients, such as the iOS client used by the Titanium app compiled for iOS, work just fine with Lucerne.

The Android Ti client works just fine with node.js, Clack, plain Hunchentoot, Nginx, and Apache. Of all the combinations I’ve tried so far, only with the combination Lucerne on top of Clack using Hunchentoot, causes problems, on this particular client.

When Lucerne-app is proxied through nginx we get a 499 error indicating the client has disconnected prematurely.

This is a barebones client that exhibits the problem:

function sendRequest(e) {
    console.log('http request started');
    var httpClient = Ti.Network.createHTTPClient({
        onload : function(){
            console.log('Data '+this.responseText);
            alert ('success!');
        },
        onerror: function(error){
            console.log('Error '+ this.responseText+' status '+this.status);
            alert('fail!\n');
        }
    });
    httpClient.setTimeout(4*1000); 
    httpClient.open('GET','http://192.168.69.185:8003/');
    httpClient.send();
}

$.index.open();

The Lucerne app is just the generator skeleton app with a simplified / route:

@route app “/“
(defview index ()
  (respond “Hello, Lucerne!” :type “text/plain”))

Clack was tested with the very minimal:

(clackup (lambda (env) '(200 (:content-type “text/plain”) (“Hello, Clack!”))))
I've attached the packet captures from the above tests, showing the normal and anomalous behaviour in tihttclient-test-pcapng.tar.gz

:get method doesn't work

When I try this:

@route app "/index"
(defview hello ()
(with-params (test)
(respond (format nil "Hello, world! ~a" test))))

This doesn't work. Should print "Hello, world! lisp" when the url is "/index?test=lisp" ?

Test suite does not run on CCL 1.10

I tried running the test suite on CCL because I can't get sub-apps to work. The tests do not run.

Bad interval for sequence operation on NIL : start = 6, end = 0
   [Condition of type SIMPLE-ERROR]
(ql:quickload :lucerne-test :verbose t)
To load "lucerne-test":
  Load 1 ASDF system:
    lucerne-test
; Loading "lucerne-test"
.....
Running test suite BASIC
 Running test CLACK-ERRORS 
;Compiler warnings :
;   In %INNER-TEST-CLACK-ERRORS: Unused lexical variable &REST
To load "clack-handler-hunchentoot":
  Load 1 ASDF system:
    clack-handler-hunchentoot
; Loading "clack-handler-hunchentoot"

Hunchentoot server is started.
Listening on localhost:4545.
.

The tests pass when I run them on SBCL

Some systems failed to build for Quicklisp dist

Building with SBCL 2.1.6 / ASDF 3.3.5 for quicklisp dist creation.

Trying to build commit id 7037f2c

lucerne-auth fails to build with the following error:

Unhandled ASDF/FIND-COMPONENT:MISSING-DEPENDENCY in thread #<SB-THREAD:THREAD "main thread" RUNNING {1001BE8103}>: Component :CLACK-V1-COMPAT not found, required by #<SYSTEM "lucerne">

lucerne-hello-world fails to build with the following error:

Unhandled ASDF/FIND-COMPONENT:MISSING-DEPENDENCY in thread #<SB-THREAD:THREAD "main thread" RUNNING {1001BE8103}>: Component :CLACK-V1-COMPAT not found, required by #<SYSTEM "lucerne">

lucerne-test fails to build with the following error:

Unhandled ASDF/FIND-COMPONENT:MISSING-DEPENDENCY in thread #<SB-THREAD:THREAD "main thread" RUNNING {1001BE8103}>: Component :CLACK-V1-COMPAT not found, required by #<SYSTEM "lucerne">

lucerne-utweet fails to build with the following error:

Unhandled ASDF/FIND-COMPONENT:MISSING-DEPENDENCY in thread #<SB-THREAD:THREAD "main thread" RUNNING {1001BE8103}>: Component :CLACK-V1-COMPAT not found, required by #<SYSTEM "lucerne">

lucerne fails to build with the following error:

Unhandled ASDF/FIND-COMPONENT:MISSING-DEPENDENCY in thread #<SB-THREAD:THREAD "main thread" RUNNING {1001BE8103}>: Component :CLACK-V1-COMPAT not found, required by #<SYSTEM "lucerne">

Full log here

creating a new defview

If I write a new defview with the @route reader macro, it is not added to the routing table upon C-c C-c. However, If I restart my Lisp image, it's displayed in my web browser. Is there something I must do to iteratively define pages?

Clack added :server keyword, causing a code break on sites like Heroku

Hello,

Clack recently added the ability to specify a server address on start up. In the process, they changed the default address from "0.0.0.0" to "127.0.0.1" on Hunchentoot. This shouldn't matter in most cases, but for sites like Heroku, it caused the app to never properly bind to the port, cause as startup timeout.

A simple change in start in the keyword args should resolve this (and add this feature). I'll try to create a pull request when I have more time.

In the meantime, I was able to use this as a work around:

(defmethod lucerne.ctl:start ((app lucerne.app:base-app) &key (port 8000) (server :hunchentoot) (address "0.0.0.0") debug silent)
  "Bring up @cl:param(app), by default on @cl:param(port) 8000. If the server
was not running, it returns @c(T). If the server was running, it restarts it and
returns @c(NIL)."
  (let ((rebooted nil))
    (when (lucerne.app:handler app)
      ;; The handler already exists, meaning the server is running. Bring it
      ;; down before bringing it up again.
      (setf rebooted t)
      (clack:stop (lucerne.app:handler app)))
    (setf (lucerne.app:handler app)
          (clack:clackup
           (lack:builder (let ((clack-app (lucerne.app:build-app app)))
                           (if debug
                               (funcall clack-errors:*clack-error-middleware*
                                        clack-app
                                        :debug t)
                               clack-app)))
           :port port
           :server server
           :address address
           :use-default-middlewares nil
           :silent silent))
    (sleep 1)
    ;; If it was rebooted, return nil. Otherwise t.
    (not rebooted)))

This might come in handy for other folks in the meantime.

Thanks!

Respond should provide parameter for HTTP headers

It will be useful if respond can be used to set custom HTTP headers. At the moment I have to use a custom respond-like function everywhere I need to return custom headers.

This will also address my original question in #13.

How to access the query parameters ?

Hi,
I like the with-params macro, but I don't see something equivalent for the url query parameters. How can we access them ? I didn't find anything in the doc nor in the code. I bet they are in a clack *request* object, named query-string, but I don't know how to access them: clack is not documented and this help isn't clear on that (BTW, how to explore the *request* in slime's debugger, while I'm on a break for instance ? it only prints as "CLACK:REQUEST<REQUEST>")
Thanks

Is there an easy way to set cookies

The only way I manage to set cookies is by doing this:

(defview page ()
   (list 200  
         (list :content-type "text"
               :set-cookie "sessionToken=abc123")
         (list "HI")))

The session middleware doesn't do what I need and I can not find another way to set cookies.

Is this the recommended way or am I missing something?

Lucerne is broken since new quicklisp version of http-body

It looks like the new version of http-body (http-body-20190813-git) has broken Lucerne. It appears that the commits since August 10th are the culprit.

With the latest version of quicklisp, running this now produces an error:

(ql:quickload :lucerne)
(annot:enable-annot-syntax)
(in-package :lucerne)

(defapp app)

@route app "/"
(defview index ()
  (respond "<h1>Welcome to Lucerne</h1>"))

@route app "/greet/:name"
(defview greet (name)
  (respond (format nil "Hello, ~A!" name)))

(start app)

When trying to visit a url, it's getting an error in http-body::parse:

The value of STRING is NIL, which is not of type STRING.
   [Condition of type SIMPLE-TYPE-ERROR]

Restarts:
 0: [STORE-VALUE] Supply a new value for STRING.
 1: [ABORT] abort thread (#<THREAD "hunchentoot-worker-127.0.0.1:45298" RUNNING {10015252E3}>)

Backtrace:
  0: (SB-KERNEL:CHECK-TYPE-ERROR STRING NIL STRING NIL)
  1: (HTTP-BODY.UTIL:STARTS-WITH "application/json" #<unavailable argument>)
      Locals:
        PREFIX = "application/json"
  2: (HTTP-BODY:PARSE NIL NIL #<CIRCULAR-STREAMS:CIRCULAR-INPUT-STREAM {100186F053}>)
      Locals:
        CONTENT-LENGTH = NIL
        CONTENT-TYPE = NIL
        FN = HTTP-BODY.JSON:JSON-PARSE
        STREAM = #<CIRCULAR-STREAMS:CIRCULAR-INPUT-STREAM {100186F053}>
  3: (CLACK.REQUEST:MAKE-REQUEST (:REQUEST-METHOD :GET :SCRIPT-NAME "" :PATH-INFO "/" ...))
      Locals:
        ENV = (:REQUEST-METHOD :GET :SCRIPT-NAME "" :PATH-INFO "/" ...)
        REQ = #<CLACK.REQUEST:<REQUEST> {100186ED63}>
  4: ((:METHOD LACK.COMPONENT:CALL (LUCERNE.APP:BASE-APP T)) #<LUCERNE.APP:BASE-APP {10049CE4F3}> (:REQUEST-METHOD :GET :SCRIPT-NAME "" :PATH-INFO "/" ...)) [fast-method]
  5: ((:METHOD HUNCHENTOOT:ACCEPTOR-DISPATCH-REQUEST (CLACK.HANDLER.HUNCHENTOOT::CLACK-ACCEPTOR T)) #<CLACK.HANDLER.HUNCHENTOOT::CLACK-ACCEPTOR (host 0.0.0.0, port 8000)> #<HUNCHENTOOT:REQUEST {100186DC33}..
  6: ((:METHOD HUNCHENTOOT:HANDLE-REQUEST (HUNCHENTOOT:ACCEPTOR HUNCHENTOOT:REQUEST)) #<CLACK.HANDLER.HUNCHENTOOT::CLACK-ACCEPTOR (host 0.0.0.0, port 8000)> #<HUNCHENTOOT:REQUEST {100186DC33}>) [fast-metho..
  7: ((:METHOD HUNCHENTOOT:PROCESS-REQUEST (T)) #<HUNCHENTOOT:REQUEST {100186DC33}>) [fast-method]
  8: (HUNCHENTOOT::DO-WITH-ACCEPTOR-REQUEST-COUNT-INCREMENTED #<CLACK.HANDLER.HUNCHENTOOT::CLACK-ACCEPTOR (host 0.0.0.0, port 8000)> #<CLOSURE (LAMBDA NIL :IN HUNCHENTOOT:PROCESS-CONNECTION) {100186D1CB}>)
  9: ((:METHOD HUNCHENTOOT:PROCESS-CONNECTION (HUNCHENTOOT:ACCEPTOR T)) #<CLACK.HANDLER.HUNCHENTOOT::CLACK-ACCEPTOR (host 0.0.0.0, port 8000)> #<USOCKET:STREAM-USOCKET {1001524613}>) [fast-method]
 10: ((:METHOD HUNCHENTOOT:PROCESS-CONNECTION :AROUND (HUNCHENTOOT:ACCEPTOR T)) #<CLACK.HANDLER.HUNCHENTOOT::CLACK-ACCEPTOR (host 0.0.0.0, port 8000)> #<USOCKET:STREAM-USOCKET {1001524613}>) [fast-method]
 11: ((:METHOD HUNCHENTOOT:PROCESS-CONNECTION :AROUND (CLACK.HANDLER.HUNCHENTOOT::CLACK-ACCEPTOR T)) #<CLACK.HANDLER.HUNCHENTOOT::CLACK-ACCEPTOR (host 0.0.0.0, port 8000)> #<USOCKET:STREAM-USOCKET {1001524..
 12: ((FLET HUNCHENTOOT::PROCESS-CONNECTION% :IN HUNCHENTOOT::HANDLE-INCOMING-CONNECTION%) #<CLACK.HANDLER.HUNCHENTOOT::CLACK-ACCEPTOR (host 0.0.0.0, port 8000)> #<USOCKET:STREAM-USOCKET {1001524613}>)
 13: ((LAMBDA NIL :IN BORDEAUX-THREADS::BINDING-DEFAULT-SPECIALS))
 14: ((FLET SB-UNIX::BODY :IN SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE))
 15: ((FLET "WITHOUT-INTERRUPTS-BODY-4" :IN SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE))
 16: ((FLET SB-THREAD::WITH-MUTEX-THUNK :IN SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE))
 17: ((FLET "WITHOUT-INTERRUPTS-BODY-1" :IN SB-THREAD::CALL-WITH-MUTEX))
 18: (SB-THREAD::CALL-WITH-MUTEX #<CLOSURE (FLET SB-THREAD::WITH-MUTEX-THUNK :IN SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE) {7F8C805CED7B}> #<SB-THREAD:MUTEX "thread result lock" owner: #<SB-THREAD:THR..
 19: (SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE #<SB-THREAD:THREAD "hunchentoot-worker-127.0.0.1:45298" RUNNING {10015252E3}> NIL #<CLOSURE (LAMBDA NIL :IN BORDEAUX-THREADS::BINDING-DEFAULT-SPECIALS) {..
 --more--

If I revert back to the http-body-20181210-git version Lucerne works fine.

I don't have a solution/workaround suggestion at the moment and am not sure how to proceed. But I did want to bring it to your attention. I'll try to play with it more if I have some time.

Thank you!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.