blob: 3fe237a5aa6f033224ab2183394f3512d07f56b4 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
(defpackage :webstats
(:use :common-lisp :hunchentoot :spinneret))
(defpackage :webstats-js
(:use :cl :parenscript))
(in-package :webstats-js)
(setf *js-target-version* "1.9")
(ps::define-statement-operator for-of ((var iterable) &rest body)
`(ps-js::for-of ,(ps::compile-expression var)
,(ps::compile-expression iterable)
,(ps::compile-loop-body (list var) body)))
(ps::defprinter ps-js::for-of (var object body-block)
"for (const "(ps::ps-print var)" of "(ps::ps-print object)") "
(ps::ps-print body-block))
(in-package :webstats)
(yesql:import log-queries
:from "queries.sql"
:as :cl-yesql/sqlite
:binding :all-functions)
;; (sqlite:with-open-database (db "test.db")
;; (drop-stats-table db)
;; (create-stats-table db))
;; (sqlite:with-open-database (db "test.db")
;; (insert db
;; :click nil
;; :page "ho"
;; :referer "ref"
;; :ip "13"
;; :user-agent "sly"
;; :title "try"))
(hunchentoot:define-easy-handler
(visit :uri "/visit" :default-request-type :both)
(title page referer click)
(format nil "you are our visit ~d"
(insert *sqlite*
:click click
:page page
:referer referer
:ip (remote-addr*)
:user-agent (user-agent)
:title title)))
(hunchentoot:define-easy-handler (stat-js :uri "/stats.js") ()
(setf (hunchentoot:content-type*) "text/javascript")
(ps:ps-compile-file "stats.paren"))
(hunchentoot:define-easy-handler (metric :uri "/metric.json") (q)
(setf (hunchentoot:content-type*) "application/json")
(cl-json:encode-json-to-string
(apply #'mapcar #'list
(cond
((string= q "all")
(activity-stats *sqlite*))
((string= q "split")
(activity-places *sqlite*))
((list (list)))))))
(hunchentoot:define-easy-handler (graphs :uri "/graphs") ()
(with-html-string
(:doctype)
(:html
(:head (:title "hu yu ipi")
(:meta :charset "utf-8")
(:link :rel "stylesheet" :href "/webstats/static/uPlot.min.css")
(:script :async t :src "/webstats/static/uPlot.iife.min.js" :type "text/javascript")
(:script :async t :src "/stats/stats.js" :type "text/javascript")
(:script :async t :src "http://127.0.0.1:8095/skewer"))
(:body
(:h1 "great graph stats")
(:div :id "graph")
(:script
(:raw
(ps:ps
(add-event-listener
"load"
(lambda ()
(ps:chain (fetch "/stats/metric.json?q=all")
(then #'response-to-json)
(then #'plot)))))))))))
(defvar *acceptor*)
(defvar *sqlite*)
(defun start-server (port)
(setf *acceptor*
(make-instance 'hunchentoot:easy-acceptor :port port))
(setf *sqlite* (sqlite:connect "test.db"))
(hunchentoot:start *acceptor*))
(defun main ()
(let ((port (parse-integer (or (uiop:getenv "PORT")
"4252"))))
(start-server port)
(format *standard-output* "Hunchentoot server started on port ~d.~&" port)
(handler-case (bt:join-thread
(find-if (lambda (th)
(search "hunchentoot" (bt:thread-name th)))
(bt:all-threads)))
;; Catch a user's C-c
(#+sbcl sb-sys:interactive-interrupt
#+ccl ccl:interrupt-signal-condition
#+clisp system::simple-interrupt-condition
#+ecl ext:interactive-interrupt
#+allegro excl:interrupt-signal
() (progn
(format *error-output* "Aborting.~&")
(hunchentoot:stop *acceptor*)
(sqlite:disconnect *sqlite*)
(uiop:quit)))
(error (c) (format t "Woops, an unknown error occured:~&~a~&" c)))))
(defun create-static-assets ()
(let ((ps:*ps-print-pretty* nil))
(with-open-file (ps:*parenscript-stream*
"stats.js" :direction :output
:if-exists :supersede)
(ps:ps-compile-file "stats.paren"))))
|