forked from cadence/breezewiki
Replace thread-let with thread-utils
This commit is contained in:
parent
5fa6e2fb9e
commit
501dcaa3fc
9 changed files with 255 additions and 215 deletions
|
@ -4,8 +4,6 @@
|
||||||
(provide
|
(provide
|
||||||
; help make a nested if. if/in will gain the same false form of its containing if/out.
|
; help make a nested if. if/in will gain the same false form of its containing if/out.
|
||||||
if/out
|
if/out
|
||||||
; let, but the value for each variable is evaluated within a thread
|
|
||||||
thread-let
|
|
||||||
; cond, but values can be defined between conditions
|
; cond, but values can be defined between conditions
|
||||||
cond/var
|
cond/var
|
||||||
; wrap sql statements into lambdas so they can be executed during migration
|
; wrap sql statements into lambdas so they can be executed during migration
|
||||||
|
@ -25,7 +23,6 @@
|
||||||
|
|
||||||
(provide
|
(provide
|
||||||
transform-if/out
|
transform-if/out
|
||||||
transform-thread-let
|
|
||||||
transform/out-cond/var)
|
transform/out-cond/var)
|
||||||
|
|
||||||
(define (transform-if/out stx)
|
(define (transform-if/out stx)
|
||||||
|
@ -51,26 +48,6 @@
|
||||||
[#t node])))
|
[#t node])))
|
||||||
(datum->syntax stx (cons 'if result)))
|
(datum->syntax stx (cons 'if result)))
|
||||||
|
|
||||||
(define (transform-thread-let stx)
|
|
||||||
(define tree (cdr (syntax->datum stx)))
|
|
||||||
(define defs (car tree))
|
|
||||||
(define forms (cdr tree))
|
|
||||||
(when (eq? (length forms) 0)
|
|
||||||
(error (format "thread-let: bad syntax (need some forms to execute after the threads)~n forms: ~a" forms)))
|
|
||||||
(define counter (build-list (length defs) values))
|
|
||||||
(datum->syntax
|
|
||||||
stx
|
|
||||||
`(let ([chv (build-vector ,(length defs) (λ (_) (make-channel)))])
|
|
||||||
,@(map (λ (n)
|
|
||||||
(define def (list-ref defs n))
|
|
||||||
`(thread (λ () (channel-put (vector-ref chv ,n) (let _ () ,@(cdr def))))))
|
|
||||||
counter)
|
|
||||||
(let ,(map (λ (n)
|
|
||||||
(define def (list-ref defs n))
|
|
||||||
`(,(car def) (channel-get (vector-ref chv ,n))))
|
|
||||||
counter)
|
|
||||||
,@forms))))
|
|
||||||
|
|
||||||
(define (transform/out-cond/var stx)
|
(define (transform/out-cond/var stx)
|
||||||
(define tree (transform-cond/var (cdr (syntax->datum stx))))
|
(define tree (transform-cond/var (cdr (syntax->datum stx))))
|
||||||
(datum->syntax
|
(datum->syntax
|
||||||
|
@ -119,35 +96,6 @@
|
||||||
(check-equal? (if/out #t (if/in #f 'yes) 'no) 'no)
|
(check-equal? (if/out #t (if/in #f 'yes) 'no) 'no)
|
||||||
(check-equal? (if/out #f (if/in #f 'yes) 'no) 'no))
|
(check-equal? (if/out #f (if/in #f 'yes) 'no) 'no))
|
||||||
|
|
||||||
(define-syntax (thread-let stx)
|
|
||||||
(transform-thread-let stx))
|
|
||||||
(module+ test
|
|
||||||
; check that it is transformed as expected
|
|
||||||
(check-syntax-equal?
|
|
||||||
(transform-thread-let
|
|
||||||
#'(thread-let ([a (hey "this is a")]
|
|
||||||
[b (hey "this is b")])
|
|
||||||
(list a b)))
|
|
||||||
#'(let ([chv (build-vector 2 (λ (_) (make-channel)))])
|
|
||||||
(thread (λ () (channel-put (vector-ref chv 0) (let _ () (hey "this is a")))))
|
|
||||||
(thread (λ () (channel-put (vector-ref chv 1) (let _ () (hey "this is b")))))
|
|
||||||
(let ([a (channel-get (vector-ref chv 0))]
|
|
||||||
[b (channel-get (vector-ref chv 1))])
|
|
||||||
(list a b))))
|
|
||||||
; check that they actually execute concurrently
|
|
||||||
(define ch (make-channel))
|
|
||||||
(check-equal? (thread-let ([a (begin
|
|
||||||
(channel-put ch 'a)
|
|
||||||
(channel-get ch))]
|
|
||||||
[b (begin0
|
|
||||||
(channel-get ch)
|
|
||||||
(channel-put ch 'b))])
|
|
||||||
(list a b))
|
|
||||||
'(b a))
|
|
||||||
; check that it assigns the correct value to the correct variable
|
|
||||||
(check-equal? (thread-let ([a (sleep 0) 'a] [b 'b]) (list a b))
|
|
||||||
'(a b)))
|
|
||||||
|
|
||||||
(define-syntax (cond/var stx)
|
(define-syntax (cond/var stx)
|
||||||
(transform/out-cond/var stx))
|
(transform/out-cond/var stx))
|
||||||
(module+ test
|
(module+ test
|
||||||
|
|
72
lib/thread-utils.rkt
Normal file
72
lib/thread-utils.rkt
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#lang racket/base
|
||||||
|
(require (prefix-in easy: net/http-easy)
|
||||||
|
"../src/data.rkt"
|
||||||
|
"xexpr-utils.rkt")
|
||||||
|
|
||||||
|
(provide
|
||||||
|
thread-values)
|
||||||
|
|
||||||
|
(module+ test
|
||||||
|
(require rackunit))
|
||||||
|
|
||||||
|
(define (thread-values . thunks)
|
||||||
|
(parameterize-break #t
|
||||||
|
(define the-exn (box #f))
|
||||||
|
(define original-thread (current-thread))
|
||||||
|
(define (break e)
|
||||||
|
(when (box-cas! the-exn #f e)
|
||||||
|
(break-thread original-thread))
|
||||||
|
(sleep 0))
|
||||||
|
(define-values (threads channels)
|
||||||
|
(for/fold ([ts null]
|
||||||
|
[chs null]
|
||||||
|
#:result (values (reverse ts) (reverse chs)))
|
||||||
|
([th thunks])
|
||||||
|
(define ch (make-channel))
|
||||||
|
(define t
|
||||||
|
(thread (λ ()
|
||||||
|
(with-handlers ([exn? break])
|
||||||
|
(channel-put ch (th))))))
|
||||||
|
(values (cons t ts) (cons ch chs))))
|
||||||
|
(apply
|
||||||
|
values
|
||||||
|
(with-handlers ([exn:break? (λ (_)
|
||||||
|
(for ([t threads]) (kill-thread t))
|
||||||
|
(if (unbox the-exn)
|
||||||
|
(raise (unbox the-exn))
|
||||||
|
(error 'thread-values "a thread broke, but without reporting its exception")))])
|
||||||
|
(for/list ([ch channels])
|
||||||
|
(channel-get ch))))))
|
||||||
|
|
||||||
|
(module+ test
|
||||||
|
; check that they actually execute concurrently
|
||||||
|
(define ch (make-channel))
|
||||||
|
(check-equal? (let-values ([(a b)
|
||||||
|
(thread-values
|
||||||
|
(λ ()
|
||||||
|
(begin
|
||||||
|
(channel-put ch 'a)
|
||||||
|
(channel-get ch)))
|
||||||
|
(λ ()
|
||||||
|
(begin0
|
||||||
|
(channel-get ch)
|
||||||
|
(channel-put ch 'b))))])
|
||||||
|
(list a b))
|
||||||
|
'(b a))
|
||||||
|
; check that it assigns the correct value to the correct variable
|
||||||
|
(check-equal? (let-values ([(a b)
|
||||||
|
(thread-values
|
||||||
|
(λ () (sleep 0) 'a)
|
||||||
|
(λ () 'b))])
|
||||||
|
(list a b))
|
||||||
|
'(a b))
|
||||||
|
; check that exceptions are passed to the original thread, and other threads are killed
|
||||||
|
;; TODO: if the other thread was making an HTTP request, could it be left stuck open by the kill?
|
||||||
|
(check-equal? (let* ([x "!"]
|
||||||
|
[res
|
||||||
|
(with-handlers ([exn:fail:user? (λ (e) (exn-message e))])
|
||||||
|
(thread-values
|
||||||
|
(λ () (sleep 0) (set! x "?") (println "this side effect should not happen"))
|
||||||
|
(λ () (raise-user-error "catch me"))))])
|
||||||
|
(string-append res x))
|
||||||
|
"catch me!"))
|
|
@ -277,8 +277,8 @@
|
||||||
; check that noscript images are removed
|
; check that noscript images are removed
|
||||||
(check-equal? ((query-selector (λ (t a c) (eq? t 'noscript)) transformed)) #f)
|
(check-equal? ((query-selector (λ (t a c) (eq? t 'noscript)) transformed)) #f)
|
||||||
; benchmark
|
; benchmark
|
||||||
(when (file-exists? "../misc/Frog.html")
|
(when (file-exists? "../storage/Frog.html")
|
||||||
(with-input-from-file "../misc/Frog.html"
|
(with-input-from-file "../storage/Frog.html"
|
||||||
(λ ()
|
(λ ()
|
||||||
(define tree (html->xexp (current-input-port)))
|
(define tree (html->xexp (current-input-port)))
|
||||||
(time (length (update-tree-wiki tree "minecraft")))))))
|
(time (length (update-tree-wiki tree "minecraft")))))))
|
||||||
|
|
|
@ -201,13 +201,16 @@
|
||||||
,(if (config-true? 'instance_is_official)
|
,(if (config-true? 'instance_is_official)
|
||||||
(let ([balloon '(img (@ (src "/static/three-balloons.png") (class "bw-balloon") (title "Image Source: pngimg.com/image/4955 | License: CC BY-NC 4.0 | Modifications: Resized") (width "52") (height "56")))]
|
(let ([balloon '(img (@ (src "/static/three-balloons.png") (class "bw-balloon") (title "Image Source: pngimg.com/image/4955 | License: CC BY-NC 4.0 | Modifications: Resized") (width "52") (height "56")))]
|
||||||
[extension-eligible?
|
[extension-eligible?
|
||||||
(and req (let* ([ua-pair (assq 'user-agent (request-headers req))]
|
(cond/var
|
||||||
[ua (string-downcase (cdr ua-pair))])
|
[(not req) #f]
|
||||||
|
(var ua-pair (assq 'user-agent (request-headers req)))
|
||||||
|
[(not ua-pair) #f]
|
||||||
|
(var ua (string-downcase (cdr ua-pair)))
|
||||||
;; everyone pretends to be chrome, so we do it in reverse
|
;; everyone pretends to be chrome, so we do it in reverse
|
||||||
;; this excludes common browsers that don't support the extension
|
;; this excludes common browsers that don't support the extension
|
||||||
(and (not (string-contains? ua "edge/"))
|
[#t (and (not (string-contains? ua "edge/"))
|
||||||
(not (string-contains? ua "edg/"))
|
(not (string-contains? ua "edg/"))
|
||||||
(not (string-contains? ua "mobile")))))])
|
(not (string-contains? ua "mobile")))])])
|
||||||
`(div (@ (class "bw-top-banner"))
|
`(div (@ (class "bw-top-banner"))
|
||||||
,balloon
|
,balloon
|
||||||
(div
|
(div
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
(hash-set! wikis-hash (symbol->string wikiname) w)))
|
(hash-set! wikis-hash (symbol->string wikiname) w)))
|
||||||
(module+ test
|
(module+ test
|
||||||
(check-equal? (cadr (hash-ref wikis-hash "gallowmere"))
|
(check-equal? (cadr (hash-ref wikis-hash "gallowmere"))
|
||||||
"Gallowmere Historia"))
|
"MediEvil Wiki"))
|
||||||
|
|
||||||
(define (parse-table table)
|
(define (parse-table table)
|
||||||
(define rows (query-selector (λ (t a c) (eq? t 'tr)) table))
|
(define rows (query-selector (λ (t a c) (eq? t 'tr)) table))
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
"data.rkt"
|
"data.rkt"
|
||||||
"page-wiki.rkt"
|
"page-wiki.rkt"
|
||||||
"../lib/syntax.rkt"
|
"../lib/syntax.rkt"
|
||||||
|
"../lib/thread-utils.rkt"
|
||||||
"../lib/url-utils.rkt"
|
"../lib/url-utils.rkt"
|
||||||
"whole-utils.rkt"
|
"whole-utils.rkt"
|
||||||
"../lib/xexpr-utils.rkt")
|
"../lib/xexpr-utils.rkt")
|
||||||
|
@ -69,8 +70,10 @@
|
||||||
(define origin (format "https://~a.fandom.com" wikiname))
|
(define origin (format "https://~a.fandom.com" wikiname))
|
||||||
(define source-url (format "~a/wiki/~a" origin prefixed-category))
|
(define source-url (format "~a/wiki/~a" origin prefixed-category))
|
||||||
|
|
||||||
(thread-let
|
(define-values (members-data page-data siteinfo)
|
||||||
([members-data (define dest-url
|
(thread-values
|
||||||
|
(λ ()
|
||||||
|
(define dest-url
|
||||||
(format "~a/api.php?~a"
|
(format "~a/api.php?~a"
|
||||||
origin
|
origin
|
||||||
(params->query `(("action" . "query")
|
(params->query `(("action" . "query")
|
||||||
|
@ -81,8 +84,9 @@
|
||||||
("format" . "json")))))
|
("format" . "json")))))
|
||||||
(log-outgoing dest-url)
|
(log-outgoing dest-url)
|
||||||
(define dest-res (easy:get dest-url #:timeouts timeouts))
|
(define dest-res (easy:get dest-url #:timeouts timeouts))
|
||||||
(easy:response-json dest-res)]
|
(easy:response-json dest-res))
|
||||||
[page-data (define dest-url
|
(λ ()
|
||||||
|
(define dest-url
|
||||||
(format "~a/api.php?~a"
|
(format "~a/api.php?~a"
|
||||||
origin
|
origin
|
||||||
(params->query `(("action" . "parse")
|
(params->query `(("action" . "parse")
|
||||||
|
@ -92,8 +96,9 @@
|
||||||
("format" . "json")))))
|
("format" . "json")))))
|
||||||
(log-outgoing dest-url)
|
(log-outgoing dest-url)
|
||||||
(define dest-res (easy:get dest-url #:timeouts timeouts))
|
(define dest-res (easy:get dest-url #:timeouts timeouts))
|
||||||
(easy:response-json dest-res)]
|
(easy:response-json dest-res))
|
||||||
[siteinfo (siteinfo-fetch wikiname)])
|
(λ ()
|
||||||
|
(siteinfo-fetch wikiname))))
|
||||||
|
|
||||||
(define title (preprocess-html-wiki (jp "/parse/title" page-data prefixed-category)))
|
(define title (preprocess-html-wiki (jp "/parse/title" page-data prefixed-category)))
|
||||||
(define page-html (preprocess-html-wiki (jp "/parse/text" page-data "")))
|
(define page-html (preprocess-html-wiki (jp "/parse/text" page-data "")))
|
||||||
|
@ -117,7 +122,7 @@
|
||||||
#:code 200
|
#:code 200
|
||||||
#:headers (build-headers always-headers)
|
#:headers (build-headers always-headers)
|
||||||
(λ (out)
|
(λ (out)
|
||||||
(write-html body out))))))
|
(write-html body out)))))
|
||||||
(module+ test
|
(module+ test
|
||||||
(check-not-false ((query-selector (attribute-selector 'href "/test/wiki/Ankle_Monitor")
|
(check-not-false ((query-selector (attribute-selector 'href "/test/wiki/Ankle_Monitor")
|
||||||
(generate-results-page
|
(generate-results-page
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
"data.rkt"
|
"data.rkt"
|
||||||
"page-wiki.rkt"
|
"page-wiki.rkt"
|
||||||
"../lib/syntax.rkt"
|
"../lib/syntax.rkt"
|
||||||
|
"../lib/thread-utils.rkt"
|
||||||
"../lib/url-utils.rkt"
|
"../lib/url-utils.rkt"
|
||||||
"whole-utils.rkt"
|
"whole-utils.rkt"
|
||||||
"../lib/xexpr-utils.rkt")
|
"../lib/xexpr-utils.rkt")
|
||||||
|
@ -108,8 +109,10 @@
|
||||||
(define origin (format "https://~a.fandom.com" wikiname))
|
(define origin (format "https://~a.fandom.com" wikiname))
|
||||||
(define source-url (format "~a/wiki/~a" origin prefixed-title))
|
(define source-url (format "~a/wiki/~a" origin prefixed-title))
|
||||||
|
|
||||||
(thread-let
|
(define-values (media-detail siteinfo)
|
||||||
([media-detail (define dest-url
|
(thread-values
|
||||||
|
(λ ()
|
||||||
|
(define dest-url
|
||||||
(format "~a/wikia.php?~a"
|
(format "~a/wikia.php?~a"
|
||||||
origin
|
origin
|
||||||
(params->query `(("format" . "json") ("controller" . "Lightbox")
|
(params->query `(("format" . "json") ("controller" . "Lightbox")
|
||||||
|
@ -117,8 +120,9 @@
|
||||||
("fileTitle" . ,prefixed-title)))))
|
("fileTitle" . ,prefixed-title)))))
|
||||||
(log-outgoing dest-url)
|
(log-outgoing dest-url)
|
||||||
(define dest-res (easy:get dest-url #:timeouts timeouts))
|
(define dest-res (easy:get dest-url #:timeouts timeouts))
|
||||||
(easy:response-json dest-res)]
|
(easy:response-json dest-res))
|
||||||
[siteinfo (siteinfo-fetch wikiname)])
|
(λ ()
|
||||||
|
(siteinfo-fetch wikiname))))
|
||||||
(if (not (jp "/exists" media-detail #f))
|
(if (not (jp "/exists" media-detail #f))
|
||||||
(next-dispatcher)
|
(next-dispatcher)
|
||||||
(response-handler
|
(response-handler
|
||||||
|
@ -143,7 +147,7 @@
|
||||||
(xexp->html body))
|
(xexp->html body))
|
||||||
(response/output #:code 200
|
(response/output #:code 200
|
||||||
#:headers (build-headers always-headers)
|
#:headers (build-headers always-headers)
|
||||||
(λ (out) (write-html body out))))))))
|
(λ (out) (write-html body out)))))))
|
||||||
(module+ test
|
(module+ test
|
||||||
(parameterize ([(config-parameter 'strict_proxy) "true"])
|
(parameterize ([(config-parameter 'strict_proxy) "true"])
|
||||||
(check-equal? (get-media-html "https://static.wikia.nocookie.net/a" "image/jpeg")
|
(check-equal? (get-media-html "https://static.wikia.nocookie.net/a" "image/jpeg")
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
"config.rkt"
|
"config.rkt"
|
||||||
"data.rkt"
|
"data.rkt"
|
||||||
"../lib/syntax.rkt"
|
"../lib/syntax.rkt"
|
||||||
|
"../lib/thread-utils.rkt"
|
||||||
"../lib/url-utils.rkt"
|
"../lib/url-utils.rkt"
|
||||||
"whole-utils.rkt"
|
"whole-utils.rkt"
|
||||||
"../lib/xexpr-utils.rkt")
|
"../lib/xexpr-utils.rkt")
|
||||||
|
@ -72,10 +73,13 @@
|
||||||
("formatversion" . "2")
|
("formatversion" . "2")
|
||||||
("format" . "json")))))
|
("format" . "json")))))
|
||||||
|
|
||||||
(thread-let
|
(define-values (dest-res siteinfo)
|
||||||
([dest-res (log-outgoing dest-url)
|
(thread-values
|
||||||
(easy:get dest-url #:timeouts timeouts)]
|
(λ ()
|
||||||
[siteinfo (siteinfo-fetch wikiname)])
|
(log-outgoing dest-url)
|
||||||
|
(easy:get dest-url #:timeouts timeouts))
|
||||||
|
(λ ()
|
||||||
|
(siteinfo-fetch wikiname))))
|
||||||
|
|
||||||
(define data (easy:response-json dest-res))
|
(define data (easy:response-json dest-res))
|
||||||
|
|
||||||
|
@ -88,7 +92,7 @@
|
||||||
#:code 200
|
#:code 200
|
||||||
#:headers (build-headers always-headers)
|
#:headers (build-headers always-headers)
|
||||||
(λ (out)
|
(λ (out)
|
||||||
(write-html body out))))))
|
(write-html body out)))))
|
||||||
(module+ test
|
(module+ test
|
||||||
(parameterize ([(config-parameter 'feature_offline::only) "false"])
|
(parameterize ([(config-parameter 'feature_offline::only) "false"])
|
||||||
(check-not-false ((query-selector (attribute-selector 'href "/test/wiki/Gacha_Capsule")
|
(check-not-false ((query-selector (attribute-selector 'href "/test/wiki/Gacha_Capsule")
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
"data.rkt"
|
"data.rkt"
|
||||||
"../lib/pure-utils.rkt"
|
"../lib/pure-utils.rkt"
|
||||||
"../lib/syntax.rkt"
|
"../lib/syntax.rkt"
|
||||||
|
"../lib/thread-utils.rkt"
|
||||||
"../lib/tree-updater.rkt"
|
"../lib/tree-updater.rkt"
|
||||||
"../lib/url-utils.rkt"
|
"../lib/url-utils.rkt"
|
||||||
"whole-utils.rkt"
|
"whole-utils.rkt"
|
||||||
|
@ -41,8 +42,10 @@
|
||||||
(define path (string-join (map path/param-path (cddr (url-path (request-uri req)))) "/"))
|
(define path (string-join (map path/param-path (cddr (url-path (request-uri req)))) "/"))
|
||||||
(define source-url (format "https://~a.fandom.com/wiki/~a" wikiname path))
|
(define source-url (format "https://~a.fandom.com/wiki/~a" wikiname path))
|
||||||
|
|
||||||
(thread-let
|
(define-values (dest-res siteinfo)
|
||||||
([dest-res (define dest-url
|
(thread-values
|
||||||
|
(λ ()
|
||||||
|
(define dest-url
|
||||||
(format "~a/api.php?~a"
|
(format "~a/api.php?~a"
|
||||||
origin
|
origin
|
||||||
(params->query `(("action" . "parse")
|
(params->query `(("action" . "parse")
|
||||||
|
@ -53,8 +56,9 @@
|
||||||
(log-outgoing dest-url)
|
(log-outgoing dest-url)
|
||||||
(easy:get dest-url
|
(easy:get dest-url
|
||||||
#:timeouts timeouts
|
#:timeouts timeouts
|
||||||
#:headers `#hasheq((cookie . ,(format "theme=~a" (user-cookies^-theme user-cookies)))))]
|
#:headers `#hasheq((cookie . ,(format "theme=~a" (user-cookies^-theme user-cookies))))))
|
||||||
[siteinfo (siteinfo-fetch wikiname)])
|
(λ ()
|
||||||
|
(siteinfo-fetch wikiname))))
|
||||||
|
|
||||||
(cond
|
(cond
|
||||||
[(eq? 200 (easy:response-status-code dest-res))
|
[(eq? 200 (easy:response-status-code dest-res))
|
||||||
|
@ -96,4 +100,4 @@
|
||||||
#:code 200
|
#:code 200
|
||||||
#:headers headers
|
#:headers headers
|
||||||
(λ (out)
|
(λ (out)
|
||||||
(write-html body out))))))])))
|
(write-html body out))))))]))
|
||||||
|
|
Loading…
Reference in a new issue