Created
February 11, 2022 16:36
-
-
Save svetlyak40wt/748cf976df847df6d0fee1a38aef1251 to your computer and use it in GitHub Desktop.
Example of a simple file uploader using Common Lisp and Ningle framework
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; License: MIT | |
(uiop:define-package #:ningle-upload | |
(:use #:cl) | |
(:import-from #:cl-fad) | |
(:import-from #:ningle) | |
(:import-from #:spinneret) | |
(:import-from #:log4cl)) | |
(in-package #:ningle-upload) | |
(defvar *app* (make-instance 'ningle:app)) | |
(defvar *server* nil) | |
(defparameter *downloads-dir* #P"/tmp/downloads/") | |
(setf (ningle:route *app* "/") | |
(lambda (params) | |
(declare (ignore params)) | |
(spinneret:with-html-string | |
(:h1 "Ningle Uploader Example") | |
(:h2 "Already Uploaded") | |
(let ((files | |
(when (probe-file *downloads-dir*) | |
(cl-fad:list-directory *downloads-dir*)))) | |
(if files | |
(:ul | |
(loop for file in files | |
do (:li (:p (file-namestring file))))) | |
(:p "There is no files yet."))) | |
(:h2 "Add More") | |
(:form :method "POST" | |
:action "/" | |
:enctype "multipart/form-data" | |
(:input :type "file" | |
:multiple t | |
:name "upload") | |
(:input :type "submit"))))) | |
(setf (ningle:route *app* "/" :method :POST) | |
(lambda (params) | |
;; In case of multiple files, params will have a multiple "upload" | |
;; entries: | |
;; | |
;; (("upload" #<FLEXI-STREAMS::VECTOR-INPUT-STREAM {700821F9F3}> | |
;; "file1.png" "image/png") | |
;; ("upload" #<FLEXI-STREAMS::VECTOR-INPUT-STREAM {7008223413}> | |
;; "file2.png" "image/png") | |
;; ("upload" #<FLEXI-STREAMS::VECTOR-INPUT-STREAM {7008223F23}> | |
;; "file3.png" "image/png")) | |
;; | |
;; And we need to process them one by one: | |
(loop for row in params | |
for name = (first row) | |
when (string= name "upload") | |
;; Here stream will have type FLEXI-STREAMS::VECTOR-INPUT-STREAM | |
do (destructuring-bind (stream filename content-type) | |
(rest row) | |
(when stream | |
(log:info "Accepting upload." filename content-type) | |
(let ((full-path (merge-pathnames filename *downloads-dir*))) | |
(ensure-directories-exist full-path) | |
(uiop:slurp-input-stream full-path stream)))) | |
finally | |
;; Redirecting user back to the list of files: | |
(setf (lack.response:response-status ningle:*response*) | |
302 | |
(lack.response:response-headers ningle:*response*) | |
(append (lack.response:response-headers ningle:*response*) | |
(list :location "/")))))) | |
(defun start (&key (interface "localhost") | |
(port 8080)) | |
(setf *server* | |
(clack:clackup *app* | |
:address interface | |
:port port))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment