(module plugin-counter mzscheme
(require "hwikiplugin.scm")
(provide register-plugin-counter
)
(def-class
(this (entry _page _context _langs _ip))
(supers)
(private
(define _tm (current-date))
)
(public
(define (ip) _ip)
(define (page) _page)
(define (context) _context)
(define (time) _tm)
(define (accepted-languages) (let ((fh (open-output-string)))
(write _langs fh)
(let ((S (get-output-string fh)))
(close-output-port fh)
S)))
)
(constructor)
)
(define (chan)
(vector (make-semaphore 1)
(make-semaphore 0)
#f
#f
0
))
(define (chan+ c val)
(semaphore-wait (vector-ref c 0))
(debug "counter:chan+ 1")
(if (eq? (vector-ref c 2) #f)
(begin
(vector-set! c 2 (vector val #f))
(vector-set! c 3 (vector-ref c 2)))
(begin
(let ((nv (vector val #f)))
(vector-set! (vector-ref c 2) 1 nv)
(vector-set! c 2 nv))))
(vector-set! c 4 (+ (vector-ref c 4) 1))
(semaphore-post (vector-ref c 1))
(debug "counter:chan+ 2")
(semaphore-post (vector-ref c 0))
(debug "counter:chan+ 3")
)
(define (chan- c)
(debug "counter:chan- 1")
(letrec ((f (lambda ()
(sleep 1)
(semaphore-wait (vector-ref c 0))
(let ((n (vector-ref c 4)))
(semaphore-post (vector-ref c 0))
(display (format "counter:n=~a~%" n))
(if (> n 0)
#t
(f))))))
(f))
(debug "counter:chan- 2")
(semaphore-wait (vector-ref c 0))
(let ((v (vector-ref c 3)))
(if (eq? (vector-ref c 2) (vector-ref c 3))
(begin
(vector-set! c 2 #f)
(vector-set! c 3 #f)
(vector-ref v 0))
(begin
(vector-set! c 3 (vector-ref (vector-ref c 3) 1))))
(vector-set! c 4 (- (vector-ref c 4) 1))
(semaphore-post (vector-ref c 0))
(debug "counter:chan- 3")
(vector-ref v 0)))
(def-class
(this (plugin:counter))
(supers)
(private
(define create-tables
(lambda ()
(let ((sqli (sqli-provider)))
(while (eq? sqli #f)
(begin
(debug "plugin:counter:waiting for sqli provider")
(sleep 5)
(set! sqli (sqli-provider))))
(sqli-query sqli "create table access(page varchar,context varchar,ip varchar,accepted_languages varchar,time timestamp)")
(sqli-query sqli "create table pages(page varchar,context varchar,count integer,primary key (page,context))")
(sqli-closer sqli))))
(define (inserter entry)
(create-tables)
(set! create-tables (lambda () #t))
(debug "plugin:counter, next entry: " entry)
(let ((sqli (sqli-provider)))
(if (eq? sqli #f)
(error "plugin:counter needs a database connection to work"))
(hlog (format "sqli: after connect to database: ~a" (sqli-error-message sqli)))
(debug "plugin:counter:begin of transaction")
(sqli-begin sqli)
(sqli-query sqli "insert into access(page,context,ip,accepted_languages,time) values($1,$2,$3,$4,$5)"
(-> entry page)
(-> entry context)
(-> entry ip)
(-> entry accepted-languages)
(-> entry time))
(sqli-commit sqli)
(debug "plugin:counter:select page-count in pages")
(let ((c (begin
(sqli-query sqli "select count(*) from pages where page=$1 and context=$2"
(-> entry page) (-> entry context))
(string->number (car (sqli-fetchrow sqli))))))
(sqli-begin sqli)
(debug "plugin:counter:update pagecount for page")
(if (= c 0)
(sqli-query sqli "insert into pages(page,context,count) values($1,$2,$3)" (-> entry page) (-> entry context) 1)
(sqli-query sqli "update pages set count=count+1 where page=$1 and context=$2" (-> entry page) (-> entry context)))
(sqli-commit sqli)
)
(debug "close sqli")
(sqli-closer sqli)
(debug "plugin:counter:end of transaction")
))
(define (count page context)
(let ((row (let ((_sqli (sqli-provider)))
(display (format "select pages~%"))
(sqli-begin _sqli)
(sqli-query _sqli "select count from pages where page=$1 and context=$2" page (-> context context))
(let ((R (sqli-fetchrow _sqli)))
(sqli-commit _sqli)
(sqli-closer _sqli)
R))))
(if (eq? row #f)
0
(car row))))
)
(public
(define (counter context)
(debug "plugin:counter:adding entry to fifo of context " (-> context context))
(thread (lambda () (inserter (entry (-> context page-name)
(-> context context)
(-> context accepted-languages)
(-> context from-ip)))))
"")
(define (display-counter context)
(counter context)
(let ((P (page context))
(part (-> context current-part)))
(let ((S (if (-> P has-contents? part)
(-> P contents part)
(_ "page hits: ~a"))))
(format S (count (-> context page-name) context)))))
)
(constructor)
)
(define COUNTER (plugin:counter))
(define (register-plugin-counter)
(register-plugin 'plugin:counter (->> COUNTER counter))
(register-plugin 'plugin:display-counter (->> COUNTER display-counter))
)
(register-plugin-counter)
)