public
Description: An easy way to make web apps (in PLT Scheme)
Homepage: http://blog.leftparen.com
Clone URL: git://github.com/vegashacker/leftparen.git
Click here to lend your support to: leftparen and make a donation at www.pledgie.com !
leftparen / leftparen.scm
100644 276 lines (249 sloc) 6.198 kb
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#lang scheme/base
 
(require scheme/match
         (planet untyped/dispatch:2:=1/dispatch)
         (planet jaymccarthy/with-bindings:1:=2/with-bindings)
         web-server/servlet-env
         web-server/dispatchers/dispatch
         web-server/configuration/responders
         "util.scm"
         "settings.scm"
         "web-export.ss"
         "web-support.scm"
         "record.scm"
         "repository.scm"
         "form.scm"
         "validate.scm"
         "closures.scm"
         "session.scm"
         "js.scm"
         "user.scm"
         "time.scm"
         "page.scm"
         "compute.scm"
         "profiler.scm"
         "log.scm"
         "task-queue.scm"
         "feed.ss"
         "facebook.ss"
         )
 
(provide
 
 ;; the work of others:
 (all-from-out (planet untyped/dispatch:2:=1/dispatch))
 (all-from-out (planet jaymccarthy/with-bindings:1:=2/with-bindings))
 
 ;; built-in PLT tools:
 request-bindings
 
 ;; web server
 serve
 define-app
 load-server-settings
 server-log
 
 ;; core web help
 web-link
 wrap-each-in-list
 raw-str
 img
 xexpr-if
 url+query
 url->string
 get-url
 
 ;; web forms
 form
 validate
 field-validate
 form-id
 form-markup
 grab-user-input
 
 ;; feeds
 atom-feed
 atom-item
 rss-feed
 rss-item
 
 ;; records and the data repository
 rec-prop
 rec-has-prop?
 rec-child-prop
 rec-id
 rec-data
 rec-set-prop!
 rec-set-each-prop!
 rec-remove-prop!
 rec-set-data!
 rec-set-rec-prop!
 rec-rec-prop
 load-rec
 record-id-stored?
 load-where
 load-children
 load-descendants
 contains-child?
 rec-add-child!
 add-child-and-save!
 remove-child-and-save!
 rec-add-list-prop-elt!
 store-rec!
 delete-rec!
 fresh-rec-from-data
 same-rec?
 only-rec-of-type
 if-rec-of-type
 rec-type-is?
 is-descendant?
 find-parent
 find-ancestor
 find-highest-ancestor
 find-incoming-record
 find-incoming-records
 rec?
 sort-recs-by
 define-cache
 define-type-cache
 
 ;; closures
 handle-closure-in-req
 body-as-url
 body-as-closure-key
 num-closures-in-memory
 make-closure-key
 add-closure!
 closure-key->url
 
 ;; sessions
 session-put-val!
 session-get-val
 session-id
 session-get-hash
 session-replace-hash!
 get-session-object
 session-remove-entry!
 sessioned-response
 make-fresh-session
 remove-session
 flash-create!
 flash-get!
 
 ;; response
 cookied-response
 list-response
 
 ;; js
 js-script-invoke
 js-array
 js-hash
 js-quote
 js-call
 js-call-on-load
 
 ;; html, pages, includes, etc
 define-page
 define-session-page
 page
 design
 **
 page-url
 redirect-to-page
 (rename-out (response-promise-to-redirect redirect-to))
 js-inc
 css-inc
 versioned-file-reference
 
 ;; settings
 declare-setting
 setting
 setting-set!
 
 ;; users
 register-form
 welcome-message
 login-form
 register-form
 register-user!
 make-unloginable-user!
 current-user
 user-in
 created-by?
 created-by-xexpr
 created-by-user-rec
 stamp-user-on-rec!
 get-user-rec
 authenticated-login!
 unauthenticated-login!
 if-these-users
 if-login
 when-login
 logout-user!
 
 ;; time
 created-when
 created-when-str
 days-since
 hours-since
 minutes-since
 A_DAY
 AN_HOUR
 THIRTY_DAYS
 seconds->time-string
 
 ;; computation
 sum-recs
 
 ;; profiler
 profile
 define-profile
 
 ;; task queues
 make-threaded-task-queue
 sleep-task-thread-for-at-least
 task-inspector-lock
 task-inspector-num-tasks-thunk
 
 ;; facebook
 facebook-fn
 define-facebook-required-login-page
 facebook-require-login
 facebook-session-key
 facebook-error
 facebook-uid
 facebook-form
 facebook-complex-val
 facebook-create-object
 facebook-strict-error
 
 )
 
(declare-setting *APP_VERSION* 1)
(declare-setting *PAGE_NOT_FOUND_FILE* "page-not-found.html")
(declare-setting *CATCH-EXCEPTION?* (lambda (exn) #t))
(declare-setting *EXCEPTION->XEXPR* (lambda (exn)
                                      (if (exn:dispatcher? exn)
                                          ;; then it really just means that dispatch
                                          ;; failed to find an appropriate URL match, so we
                                          ;; need to look for static files:
                                          (next-dispatcher)
                                          ;; otherwise, it is an actual error...
                                          (begin
                                            ((error-display-handler)
                                             (exn-message exn) exn)
                                            "Error on page."))))
 
(define (serve web-app)
  (populate-caches)
  (server-log "Server is ready at ~A (ctrl-c to stop it)." (setting *WEB_APP_URL*))
  (serve/servlet #:command-line? #t
                 #:launch-browser? #f
                 #:servlet-path "/"
                 #:server-root-path (build-path ".")
                 #:servlet-regexp #rx""
                 #:file-not-found-responder
                 (gen-file-not-found-responder (build-path
                                                "htdocs"
                                                (setting *PAGE_NOT_FOUND_FILE*)))
                 #:listen-ip (setting *LISTEN_IP*)
                 #:port (setting *PORT*)
                 (lambda (req)
                   (let ((catch? (setting *CATCH-EXCEPTION?*))
                         (err (setting *EXCEPTION->XEXPR*)))
                     (with-handlers ((catch? err))
                       (final-prep-of-response
                        (handle-closure-in-req req
                                               (dispatch req web-app))))))))
                 
(define-syntax define-app
  (syntax-rules ()
    ((_ app-name
        (page-name route-syntax)
        ...)
     (begin (provide app-name page-name ...)
            (define-site app-name ((route-syntax page-name) ...))))))
 
;; load appropriate settings file based on command line arg to server script
(define (load-server-settings #:envo (envo #f))
  (load (string-append "settings-"
                       (or envo
                           (let ((args (current-command-line-arguments)))
                             (if (= (vector-length args) 0)
                                 "localhost"
                                 (vector-ref args 0))))
                       ".scm")))