1 ! Copyright (C) 2008 Doug Coleman, Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: assocs kernel math.intervals math.parser namespaces
4 random accessors quotations hashtables sequences continuations
5 fry calendar combinators destructors alarms
7 http http.server http.server.dispatchers http.server.filters
8 html.elements furnace ;
11 TUPLE: session id expires uid namespace changed? ;
13 : <session> ( id -- session )
19 { "id" "ID" +random-id+ system-random-generator }
20 { "expires" "EXPIRES" TIMESTAMP +not-null+ }
21 { "uid" "UID" { VARCHAR 255 } }
22 { "namespace" "NAMESPACE" FACTOR-BLOB }
25 : get-session ( id -- session )
26 dup [ <session> select-tuple ] when ;
28 : init-sessions-table ( -- ) session ensure-table ;
30 : start-expiring-sessions ( db seq -- )
34 -1.0/0.0 now [a,b] >>expires
37 ] 5 minutes every drop ;
39 GENERIC: init-session* ( responder -- )
41 M: object init-session* drop ;
43 M: dispatcher init-session* default>> init-session* ;
45 M: filter-responder init-session* responder>> init-session* ;
47 TUPLE: sessions < filter-responder timeout domain ;
49 : <sessions> ( responder -- responder' )
52 20 minutes >>timeout ;
54 : (session-changed) ( session -- )
57 : session-changed ( -- )
58 session get (session-changed) ;
60 : sget ( key -- value )
61 session get namespace>> at ;
63 : sset ( value key -- )
65 [ namespace>> set-at ] [ (session-changed) ] bi ;
67 : schange ( key quot -- )
69 [ namespace>> swap change-at ] keep
70 (session-changed) ; inline
76 session get [ (>>uid) ] [ (session-changed) ] bi ;
78 : init-session ( session -- )
79 session [ sessions get init-session* ] with-variable ;
81 : cutoff-time ( -- time )
82 sessions get timeout>> from-now ;
84 : touch-session ( session -- )
85 cutoff-time >>expires drop ;
87 : empty-session ( -- session )
89 H{ } clone >>namespace
92 : begin-session ( -- session )
93 empty-session [ init-session ] [ insert-tuple ] [ ] tri ;
96 TUPLE: session-saver session ;
98 C: <session-saver> session-saver
100 M: session-saver dispose
101 session>> dup changed?>> [
102 [ touch-session ] [ update-tuple ] bi
105 : save-session-after ( session -- )
106 <session-saver> &dispose drop ;
108 : existing-session ( path session -- response )
109 [ session set ] [ save-session-after ] bi
110 sessions get responder>> call-responder ;
112 : session-id-key "__s" ;
114 : cookie-session-id ( request -- id/f )
115 session-id-key get-cookie
116 dup [ value>> string>number ] when ;
118 : post-session-id ( request -- id/f )
119 session-id-key swap request-params at string>number ;
121 : request-session-id ( -- id/f )
122 request get dup method>> {
123 { "GET" [ cookie-session-id ] }
124 { "HEAD" [ cookie-session-id ] }
125 { "POST" [ post-session-id ] }
128 : request-session ( -- session/f )
129 request-session-id get-session ;
131 : <session-cookie> ( id -- cookie )
132 session-id-key <cookie>
133 "$sessions" resolve-base-path >>path
134 sessions get timeout>> from-now >>expires
135 sessions get domain>> >>domain ;
137 : put-session-cookie ( response -- response' )
138 session get id>> number>string <session-cookie> put-cookie ;
140 M: sessions modify-form ( responder -- )
141 drop session get id>> session-id-key hidden-form-field ;
143 M: sessions call-responder* ( path responder -- response )
145 request-session [ begin-session ] unless*
146 existing-session put-session-cookie ;
148 : logout-all-sessions ( uid -- )
149 session new swap >>uid delete-tuples ;