forked from cadence/breezewiki
		
	Add homepage, architecture changes
* Create homepage * Page data is automatically reloaded (except when compiling) * Entrypoint is breezewiki.rkt for running and dist.rkt for compiling * Include stack trace when sending error messages
This commit is contained in:
		
							parent
							
								
									db4691f56c
								
							
						
					
					
						commit
						301636d597
					
				
					 10 changed files with 486 additions and 13 deletions
				
			
		
							
								
								
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -10,6 +10,9 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Compiled
 | 
					# Compiled
 | 
				
			||||||
compiled
 | 
					compiled
 | 
				
			||||||
 | 
					/breezewiki
 | 
				
			||||||
 | 
					/dist
 | 
				
			||||||
 | 
					/breezewiki-dist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Personal
 | 
					# Personal
 | 
				
			||||||
/config.ini
 | 
					/config.ini
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,23 +10,33 @@
 | 
				
			||||||
         (prefix-in filter: web-server/dispatchers/dispatch-filter)
 | 
					         (prefix-in filter: web-server/dispatchers/dispatch-filter)
 | 
				
			||||||
         (prefix-in files: web-server/dispatchers/dispatch-files)
 | 
					         (prefix-in files: web-server/dispatchers/dispatch-files)
 | 
				
			||||||
         "src/config.rkt"
 | 
					         "src/config.rkt"
 | 
				
			||||||
         "src/page-category.rkt"
 | 
					         "src/reloadable.rkt"
 | 
				
			||||||
         "src/page-not-found.rkt"
 | 
					         "src/server-utils.rkt")
 | 
				
			||||||
         "src/page-proxy.rkt"
 | 
					
 | 
				
			||||||
         "src/page-wiki.rkt"
 | 
					(define-syntax-rule (require-reloadable filename varname)
 | 
				
			||||||
         "src/page-search.rkt")
 | 
					  (define varname
 | 
				
			||||||
 | 
					    (reloadable-entry-point->procedure
 | 
				
			||||||
 | 
					     (make-reloadable-entry-point (quote varname) filename))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(require-reloadable "src/page-category.rkt" page-category)
 | 
				
			||||||
 | 
					(require-reloadable "src/page-home.rkt" page-home)
 | 
				
			||||||
 | 
					(require-reloadable "src/page-not-found.rkt" page-not-found)
 | 
				
			||||||
 | 
					(require-reloadable "src/page-proxy.rkt" page-proxy)
 | 
				
			||||||
 | 
					(require-reloadable "src/page-search.rkt" page-search)
 | 
				
			||||||
 | 
					(require-reloadable "src/page-wiki.rkt" page-wiki)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(when (not (config-true? 'debug))
 | 
				
			||||||
 | 
					  (set-reload-poll-interval! #f))
 | 
				
			||||||
 | 
					(reload!)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(define-runtime-path path-static "static")
 | 
					(define-runtime-path path-static "static")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(define mime-types
 | 
					 | 
				
			||||||
  (hash #".css" #"text/css"
 | 
					 | 
				
			||||||
        #".svg" #"image/svg+xml"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(serve/launch/wait
 | 
					(serve/launch/wait
 | 
				
			||||||
 #:listen-ip (if (config-true? 'debug) "127.0.0.1" #f)
 | 
					 #:listen-ip (if (config-true? 'debug) "127.0.0.1" #f)
 | 
				
			||||||
 #:port (string->number (config-get 'port))
 | 
					 #:port (string->number (config-get 'port))
 | 
				
			||||||
 (λ (quit)
 | 
					 (λ (quit)
 | 
				
			||||||
   (sequencer:make
 | 
					   (sequencer:make
 | 
				
			||||||
 | 
					    (pathprocedure:make "/" page-home)
 | 
				
			||||||
    (pathprocedure:make "/proxy" page-proxy)
 | 
					    (pathprocedure:make "/proxy" page-proxy)
 | 
				
			||||||
    (filter:make #rx"^/[a-z-]+/wiki/Category:.+$" (lift:make page-category))
 | 
					    (filter:make #rx"^/[a-z-]+/wiki/Category:.+$" (lift:make page-category))
 | 
				
			||||||
    (filter:make #rx"^/[a-z-]+/wiki/.+$" (lift:make page-wiki))
 | 
					    (filter:make #rx"^/[a-z-]+/wiki/.+$" (lift:make page-wiki))
 | 
				
			||||||
| 
						 | 
					@ -38,6 +48,6 @@
 | 
				
			||||||
                                    (struct-copy url u [path (cdr (url-path u))])))
 | 
					                                    (struct-copy url u [path (cdr (url-path u))])))
 | 
				
			||||||
                                 #:path->mime-type
 | 
					                                 #:path->mime-type
 | 
				
			||||||
                                 (lambda (u)
 | 
					                                 (lambda (u)
 | 
				
			||||||
                                   (hash-ref mime-types (path-get-extension u)))
 | 
					                                   (ext->mime-type (path-get-extension u)))
 | 
				
			||||||
                                 #:cache-no-cache (config-true? 'debug) #;"browser applies heuristics if unset"))
 | 
					                                 #:cache-no-cache (config-true? 'debug) #;"browser applies heuristics if unset"))
 | 
				
			||||||
    (lift:make page-not-found))))
 | 
					    (lift:make page-not-found))))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										43
									
								
								dist.rkt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								dist.rkt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,43 @@
 | 
				
			||||||
 | 
					#lang racket/base
 | 
				
			||||||
 | 
					(require racket/path
 | 
				
			||||||
 | 
					         racket/runtime-path
 | 
				
			||||||
 | 
					         net/url
 | 
				
			||||||
 | 
					         web-server/servlet-dispatch
 | 
				
			||||||
 | 
					         web-server/dispatchers/filesystem-map
 | 
				
			||||||
 | 
					         (prefix-in pathprocedure: web-server/dispatchers/dispatch-pathprocedure)
 | 
				
			||||||
 | 
					         (prefix-in sequencer: web-server/dispatchers/dispatch-sequencer)
 | 
				
			||||||
 | 
					         (prefix-in lift: web-server/dispatchers/dispatch-lift)
 | 
				
			||||||
 | 
					         (prefix-in filter: web-server/dispatchers/dispatch-filter)
 | 
				
			||||||
 | 
					         (prefix-in files: web-server/dispatchers/dispatch-files)
 | 
				
			||||||
 | 
					         "src/config.rkt"
 | 
				
			||||||
 | 
					         "src/server-utils.rkt")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(require (only-in "src/page-category.rkt" page-category))
 | 
				
			||||||
 | 
					(require (only-in "src/page-home.rkt" page-home))
 | 
				
			||||||
 | 
					(require (only-in "src/page-not-found.rkt" page-not-found))
 | 
				
			||||||
 | 
					(require (only-in "src/page-proxy.rkt" page-proxy))
 | 
				
			||||||
 | 
					(require (only-in "src/page-search.rkt" page-search))
 | 
				
			||||||
 | 
					(require (only-in "src/page-wiki.rkt" page-wiki))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define-runtime-path path-static "static")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(serve/launch/wait
 | 
				
			||||||
 | 
					 #:listen-ip (if (config-true? 'debug) "127.0.0.1" #f)
 | 
				
			||||||
 | 
					 #:port (string->number (config-get 'port))
 | 
				
			||||||
 | 
					 (λ (quit)
 | 
				
			||||||
 | 
					   (sequencer:make
 | 
				
			||||||
 | 
					    (pathprocedure:make "/" page-home)
 | 
				
			||||||
 | 
					    (pathprocedure:make "/proxy" page-proxy)
 | 
				
			||||||
 | 
					    (filter:make #rx"^/[a-z-]+/wiki/Category:.+$" (lift:make page-category))
 | 
				
			||||||
 | 
					    (filter:make #rx"^/[a-z-]+/wiki/.+$" (lift:make page-wiki))
 | 
				
			||||||
 | 
					    (filter:make #rx"^/[a-z-]+/search$" (lift:make page-search))
 | 
				
			||||||
 | 
					    (filter:make #rx"^/static/" (files:make
 | 
				
			||||||
 | 
					                                 #:url->path
 | 
				
			||||||
 | 
					                                 (lambda (u)
 | 
				
			||||||
 | 
					                                   ((make-url->path path-static)
 | 
				
			||||||
 | 
					                                    (struct-copy url u [path (cdr (url-path u))])))
 | 
				
			||||||
 | 
					                                 #:path->mime-type
 | 
				
			||||||
 | 
					                                 (lambda (u)
 | 
				
			||||||
 | 
					                                   (ext->mime-type (path-get-extension u)))
 | 
				
			||||||
 | 
					                                 #:cache-no-cache (config-true? 'debug) #;"browser applies heuristics if unset"))
 | 
				
			||||||
 | 
					    (lift:make page-not-found))))
 | 
				
			||||||
							
								
								
									
										77
									
								
								src/page-home.rkt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/page-home.rkt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,77 @@
 | 
				
			||||||
 | 
					#lang racket/base
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(require html-writing
 | 
				
			||||||
 | 
					         web-server/http
 | 
				
			||||||
 | 
					         "xexpr-utils.rkt"
 | 
				
			||||||
 | 
					         "config.rkt")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(provide
 | 
				
			||||||
 | 
					 page-home)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(module+ test
 | 
				
			||||||
 | 
					  (require rackunit))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define examples
 | 
				
			||||||
 | 
					  '(("crosscode" "CrossCode_Wiki")
 | 
				
			||||||
 | 
					    ("minecraft" "Bricks")
 | 
				
			||||||
 | 
					    ("undertale" "Hot_Dog...%3F")
 | 
				
			||||||
 | 
					    ("tardis" "Eleanor_Blake")
 | 
				
			||||||
 | 
					    ("fireemblem" "God-Shattering_Star")
 | 
				
			||||||
 | 
					    ("fallout" "Pip-Boy_3000")))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define content
 | 
				
			||||||
 | 
					  `((h2 "BreezeWiki makes wiki pages on Fandom readable")
 | 
				
			||||||
 | 
					    (p "It removes ads, videos, and suggested content, leaving you with a clean page that doesn't consume all your data.")
 | 
				
			||||||
 | 
					    (p "If you're looking for an \"alternative\" to Fandom for writing pages, you should look elsewhere. BreezeWiki only lets you read existing pages.")
 | 
				
			||||||
 | 
					    (p "BreezeWiki can also be called an \"alternative frontend for Fandom\".")
 | 
				
			||||||
 | 
					    (h2 "Example pages")
 | 
				
			||||||
 | 
					    (ul
 | 
				
			||||||
 | 
					     ,@(map (λ (x)
 | 
				
			||||||
 | 
					              `(li (a (@ (href ,(apply format "/~a/wiki/~a" x)))
 | 
				
			||||||
 | 
					                      ,(apply format "~a: ~a" x))))
 | 
				
			||||||
 | 
					            examples))
 | 
				
			||||||
 | 
					    (h2 "How to use")
 | 
				
			||||||
 | 
					    (p "While browsing any page on Fandom, you can replace \"fandom.com\" in the address bar with \"breezewiki.com\" to see the BreezeWiki version of that page.")
 | 
				
			||||||
 | 
					    (p "After that, you can click the links to navigate around the pages.")
 | 
				
			||||||
 | 
					    (p "To get back to Fandom, click the link that's at the bottom of the page.")))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define body
 | 
				
			||||||
 | 
					  `(html
 | 
				
			||||||
 | 
					    (head
 | 
				
			||||||
 | 
					     (meta (@ (name ")viewport") (content "width=device-width, initial-scale=1")))
 | 
				
			||||||
 | 
					     (title "About | BreezeWiki")
 | 
				
			||||||
 | 
					     (link (@ (rel "stylesheet") (type "text/css") (href "/static/internal.css")))
 | 
				
			||||||
 | 
					     (link (@ (rel "stylesheet") (type "text/css") (href "/static/main.css"))))
 | 
				
			||||||
 | 
					    (body (@ (class "skin-fandomdesktop theme-fandomdesktop-light internal"))
 | 
				
			||||||
 | 
					          (div (@ (class "main-container"))
 | 
				
			||||||
 | 
					               (div (@ (class "fandom-community-header__background tileBoth header")))
 | 
				
			||||||
 | 
					               (div (@ (class "page"))
 | 
				
			||||||
 | 
					                    (main (@ (class "page__main"))
 | 
				
			||||||
 | 
					                          (div (@ (class "custom-top"))
 | 
				
			||||||
 | 
					                               (h1 (@ (class "page-title"))
 | 
				
			||||||
 | 
					                                   "About BreezeWiki"))
 | 
				
			||||||
 | 
					                          (div (@ (id "content") #;(class "page-content"))
 | 
				
			||||||
 | 
					                               (div (@ (id "mw-content-text"))
 | 
				
			||||||
 | 
					                                    ,@content))
 | 
				
			||||||
 | 
					                          (footer (@ (class "custom-footer"))
 | 
				
			||||||
 | 
					                                  (div (@ (class "internal-footer"))
 | 
				
			||||||
 | 
					                                       (img (@ (class "my-logo") (src "/static/breezewiki.svg")))
 | 
				
			||||||
 | 
					                                       ,(if (config-get 'instance-is-official)
 | 
				
			||||||
 | 
					                                            `(p ,(format "This instance is run by the ~a developer, " (config-get 'application-name))
 | 
				
			||||||
 | 
					                                                (a (@ (href "https://cadence.moe/contact"))
 | 
				
			||||||
 | 
					                                                   "Cadence."))
 | 
				
			||||||
 | 
					                                            `(p
 | 
				
			||||||
 | 
					                                              ,(format "This unofficial instance is based off the ~a source code, but is not controlled by the code developer." (config-get 'application-name))))
 | 
				
			||||||
 | 
					                                       (p "Text content on wikis run by Fandom is available under the Creative Commons Attribution-Share Alike License 3.0 (Unported), "
 | 
				
			||||||
 | 
					                                          (a (@ (href "https://www.fandom.com/licensing")) "see license info.")
 | 
				
			||||||
 | 
					                                          " Media files and official Fandom documents have different copying restrictions.")
 | 
				
			||||||
 | 
					                                       (p ,(format "Fandom is a trademark of Fandom, Inc. ~a is not affiliated with Fandom." (config-get 'application-name)))))))))))
 | 
				
			||||||
 | 
					(module+ test
 | 
				
			||||||
 | 
					  (check-not-false (xexp->html body)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define (page-home req)
 | 
				
			||||||
 | 
					  (response/output
 | 
				
			||||||
 | 
					   #:code 200
 | 
				
			||||||
 | 
					   (λ (out)
 | 
				
			||||||
 | 
					     (write-html body out))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,7 +69,7 @@
 | 
				
			||||||
   (define data (easy:response-json dest-res))
 | 
					   (define data (easy:response-json dest-res))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   (define body (generate-results-page dest-url wikiname query data))
 | 
					   (define body (generate-results-page dest-url wikiname query data))
 | 
				
			||||||
   (when (config-get 'debug)
 | 
					   (when (config-true? 'debug)
 | 
				
			||||||
     ; used for its side effects
 | 
					     ; used for its side effects
 | 
				
			||||||
     ; convert to string with error checking, error will be raised if xexp is invalid
 | 
					     ; convert to string with error checking, error will be raised if xexp is invalid
 | 
				
			||||||
     (xexp->html body))
 | 
					     (xexp->html body))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										150
									
								
								src/reloadable.rkt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								src/reloadable.rkt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,150 @@
 | 
				
			||||||
 | 
					#lang racket/base
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					;;; Source: https://github.com/tonyg/racket-reloadable/blob/master/reloadable/main.rkt
 | 
				
			||||||
 | 
					;;; Source commit: cae2a14 from 24 May 2015
 | 
				
			||||||
 | 
					;;; Source license: LGPL 3 or later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(provide (struct-out reloadable-entry-point)
 | 
				
			||||||
 | 
					         reload-poll-interval
 | 
				
			||||||
 | 
					         set-reload-poll-interval!
 | 
				
			||||||
 | 
					         reload-failure-retry-delay
 | 
				
			||||||
 | 
					         reload!
 | 
				
			||||||
 | 
					         make-reloadable-entry-point
 | 
				
			||||||
 | 
					         lookup-reloadable-entry-point
 | 
				
			||||||
 | 
					         reloadable-entry-point->procedure
 | 
				
			||||||
 | 
					         make-persistent-state)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(require racket/set)
 | 
				
			||||||
 | 
					(require racket/string)
 | 
				
			||||||
 | 
					(require racket/match)
 | 
				
			||||||
 | 
					(require racket/rerequire)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define reload-poll-interval 0.5) ;; seconds
 | 
				
			||||||
 | 
					(define reload-failure-retry-delay (make-parameter 5)) ;; seconds
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(struct reloadable-entry-point (name
 | 
				
			||||||
 | 
					                                module-path
 | 
				
			||||||
 | 
					                                identifier-symbol
 | 
				
			||||||
 | 
					                                on-absent
 | 
				
			||||||
 | 
					                                [value #:mutable])
 | 
				
			||||||
 | 
					        #:prefab)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define reloadable-entry-points (make-hash))
 | 
				
			||||||
 | 
					(define persistent-state (make-hash))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define (set-reload-poll-interval! v)
 | 
				
			||||||
 | 
					  (set! reload-poll-interval v))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define (reloader-main)
 | 
				
			||||||
 | 
					  (let loop ()
 | 
				
			||||||
 | 
					    (match (sync (handle-evt (thread-receive-evt)
 | 
				
			||||||
 | 
					                             (lambda (_) (thread-receive)))
 | 
				
			||||||
 | 
					                 (if reload-poll-interval
 | 
				
			||||||
 | 
					                     (handle-evt (alarm-evt (+ (current-inexact-milliseconds)
 | 
				
			||||||
 | 
					                                               (* reload-poll-interval 1000)))
 | 
				
			||||||
 | 
					                                 (lambda (_) (list #f 'reload)))
 | 
				
			||||||
 | 
					                     never-evt))
 | 
				
			||||||
 | 
					      [(list ch 'reload)
 | 
				
			||||||
 | 
					       (define result (do-reload!))
 | 
				
			||||||
 | 
					       (when (not result) (sleep (reload-failure-retry-delay)))
 | 
				
			||||||
 | 
					       (when ch (channel-put ch result))])
 | 
				
			||||||
 | 
					    (loop)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define reloader-thread (thread reloader-main))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define (reloader-rpc . request)
 | 
				
			||||||
 | 
					  (define ch (make-channel))
 | 
				
			||||||
 | 
					  (thread-send reloader-thread (cons ch request))
 | 
				
			||||||
 | 
					  (channel-get ch))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define (reload!) (reloader-rpc 'reload))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define first-load? #t)
 | 
				
			||||||
 | 
					(define (say-loading-once! port)
 | 
				
			||||||
 | 
					  (when first-load?
 | 
				
			||||||
 | 
					    (display "loading support files" port)
 | 
				
			||||||
 | 
					    (set! first-load? #f)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define (handle-loader-output)
 | 
				
			||||||
 | 
					  (define i (thread-receive))
 | 
				
			||||||
 | 
					  (define real-error-port (thread-receive))
 | 
				
			||||||
 | 
					  (say-loading-once! real-error-port)
 | 
				
			||||||
 | 
					  (let loop ()
 | 
				
			||||||
 | 
					    (let ([line (read-line i)])
 | 
				
			||||||
 | 
					      (cond
 | 
				
			||||||
 | 
					        [(eof-object? line)
 | 
				
			||||||
 | 
					         (void)]
 | 
				
			||||||
 | 
					        [(string-contains? line "[load")
 | 
				
			||||||
 | 
					         (display "." real-error-port)
 | 
				
			||||||
 | 
					         (loop)]
 | 
				
			||||||
 | 
					        [#t
 | 
				
			||||||
 | 
					         (displayln line real-error-port)
 | 
				
			||||||
 | 
					         (loop)]))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					;; Only to be called from reloader-main
 | 
				
			||||||
 | 
					(define (do-reload!)
 | 
				
			||||||
 | 
					  (define module-paths (for/set ((e (in-hash-values reloadable-entry-points)))
 | 
				
			||||||
 | 
					                         (reloadable-entry-point-module-path e)))
 | 
				
			||||||
 | 
					  (with-handlers ((exn:fail?
 | 
				
			||||||
 | 
					                   (lambda (e)
 | 
				
			||||||
 | 
					                     (log-error "*** WHILE RELOADING CODE***\n~a"
 | 
				
			||||||
 | 
					                                (parameterize ([current-error-port (open-output-string)])
 | 
				
			||||||
 | 
					                                  ((error-display-handler) (exn-message e) e)
 | 
				
			||||||
 | 
					                                  (get-output-string (current-error-port))))
 | 
				
			||||||
 | 
					                     #f)))
 | 
				
			||||||
 | 
					    (for ((module-path (in-set module-paths)))
 | 
				
			||||||
 | 
					      (let ([real-error-port (current-error-port)])
 | 
				
			||||||
 | 
					        (define-values (i o) (make-pipe))
 | 
				
			||||||
 | 
					        (parameterize ([current-error-port o])
 | 
				
			||||||
 | 
					          (define new-thread (thread handle-loader-output))
 | 
				
			||||||
 | 
					          (thread-send new-thread i)
 | 
				
			||||||
 | 
					          (thread-send new-thread real-error-port)
 | 
				
			||||||
 | 
					          (dynamic-rerequire module-path #:verbosity 'all))))
 | 
				
			||||||
 | 
					    (for ((e (in-hash-values reloadable-entry-points)))
 | 
				
			||||||
 | 
					      (match-define (reloadable-entry-point _ module-path identifier-symbol on-absent _) e)
 | 
				
			||||||
 | 
					      (define new-value (if on-absent
 | 
				
			||||||
 | 
					                            (dynamic-require module-path identifier-symbol on-absent)
 | 
				
			||||||
 | 
					                            (dynamic-require module-path identifier-symbol)))
 | 
				
			||||||
 | 
					      (set-reloadable-entry-point-value! e new-value))
 | 
				
			||||||
 | 
					    #t))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define (make-reloadable-entry-point name module-path [identifier-symbol name]
 | 
				
			||||||
 | 
					                                     #:on-absent [on-absent #f])
 | 
				
			||||||
 | 
					  (define key (list module-path name))
 | 
				
			||||||
 | 
					  (hash-ref reloadable-entry-points
 | 
				
			||||||
 | 
					            key
 | 
				
			||||||
 | 
					            (lambda ()
 | 
				
			||||||
 | 
					              (define e (reloadable-entry-point name module-path identifier-symbol on-absent #f))
 | 
				
			||||||
 | 
					              (hash-set! reloadable-entry-points key e)
 | 
				
			||||||
 | 
					              e)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define (lookup-reloadable-entry-point name module-path)
 | 
				
			||||||
 | 
					  (hash-ref reloadable-entry-points
 | 
				
			||||||
 | 
					            (list module-path name)
 | 
				
			||||||
 | 
					            (lambda ()
 | 
				
			||||||
 | 
					              (error 'lookup-reloadable-entry-point
 | 
				
			||||||
 | 
					                     "Reloadable-entry-point ~a not found in module ~a"
 | 
				
			||||||
 | 
					                     name
 | 
				
			||||||
 | 
					                     module-path))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define (reloadable-entry-point->procedure e)
 | 
				
			||||||
 | 
					  (make-keyword-procedure
 | 
				
			||||||
 | 
					   (lambda (keywords keyword-values . positionals)
 | 
				
			||||||
 | 
					     (keyword-apply (reloadable-entry-point-value e)
 | 
				
			||||||
 | 
					                    keywords
 | 
				
			||||||
 | 
					                    keyword-values
 | 
				
			||||||
 | 
					                    positionals))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define (make-persistent-state name initial-value-thunk)
 | 
				
			||||||
 | 
					  (hash-ref persistent-state
 | 
				
			||||||
 | 
					            name
 | 
				
			||||||
 | 
					            (lambda ()
 | 
				
			||||||
 | 
					              (define value (initial-value-thunk))
 | 
				
			||||||
 | 
					              (define handler
 | 
				
			||||||
 | 
					                (case-lambda
 | 
				
			||||||
 | 
					                  [() value]
 | 
				
			||||||
 | 
					                  [(new-value)
 | 
				
			||||||
 | 
					                   (set! value new-value)
 | 
				
			||||||
 | 
					                   value]))
 | 
				
			||||||
 | 
					              (hash-set! persistent-state name handler)
 | 
				
			||||||
 | 
					              handler)))
 | 
				
			||||||
							
								
								
									
										16
									
								
								src/server-utils.rkt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/server-utils.rkt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,16 @@
 | 
				
			||||||
 | 
					#lang racket/base
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(provide
 | 
				
			||||||
 | 
					 ext->mime-type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(module+ test
 | 
				
			||||||
 | 
					  (require rackunit))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define hash-ext-mime-type
 | 
				
			||||||
 | 
					  (hash #".css" #"text/css"
 | 
				
			||||||
 | 
					        #".svg" #"image/svg+xml"
 | 
				
			||||||
 | 
					        #".png" #"image/png"))
 | 
				
			||||||
 | 
					(define (ext->mime-type ext)
 | 
				
			||||||
 | 
					  (hash-ref hash-ext-mime-type ext))
 | 
				
			||||||
 | 
					(module+ test
 | 
				
			||||||
 | 
					  (check-equal? (ext->mime-type #".png") #"image/png"))
 | 
				
			||||||
| 
						 | 
					@ -195,6 +195,7 @@
 | 
				
			||||||
                                #:mime-type #"text/plain"
 | 
					                                #:mime-type #"text/plain"
 | 
				
			||||||
                                (λ (out)
 | 
					                                (λ (out)
 | 
				
			||||||
                                  (for ([port (list (current-output-port) out)])
 | 
					                                  (for ([port (list (current-output-port) out)])
 | 
				
			||||||
                                    (displayln "Exception raised in Racket code at response generation time:" port)
 | 
					                                    (parameterize ([current-error-port out])
 | 
				
			||||||
                                    (displayln (exn-message e) port)))))])
 | 
					                                      (displayln "Exception raised in Racket code at response generation time:" (current-error-port))
 | 
				
			||||||
 | 
					                                      ((error-display-handler) (exn-message e) e))))))])
 | 
				
			||||||
    body ...))
 | 
					    body ...))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								static/internal-background.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								static/internal-background.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 1.5 KiB  | 
							
								
								
									
										173
									
								
								static/internal.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								static/internal.css
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,173 @@
 | 
				
			||||||
 | 
					:root {
 | 
				
			||||||
 | 
					    --theme-body-dynamic-color-1: #fff;
 | 
				
			||||||
 | 
					    --theme-body-dynamic-color-1--rgb: 255,255,255;
 | 
				
			||||||
 | 
					    --theme-body-dynamic-color-2: #e6e6e6;
 | 
				
			||||||
 | 
					    --theme-body-dynamic-color-2--rgb: 230,230,230;
 | 
				
			||||||
 | 
					    --theme-page-dynamic-color-1: #000;
 | 
				
			||||||
 | 
					    --theme-page-dynamic-color-1--rgb: 0,0,0;
 | 
				
			||||||
 | 
					    --theme-page-dynamic-color-1--inverted: #fff;
 | 
				
			||||||
 | 
					    --theme-page-dynamic-color-1--inverted--rgb: 255,255,255;
 | 
				
			||||||
 | 
					    --theme-page-dynamic-color-2: #3a3a3a;
 | 
				
			||||||
 | 
					    --theme-page-dynamic-color-2--rgb: 58,58,58;
 | 
				
			||||||
 | 
					    --theme-sticky-nav-dynamic-color-1: #000;
 | 
				
			||||||
 | 
					    --theme-sticky-nav-dynamic-color-1--rgb: 0,0,0;
 | 
				
			||||||
 | 
					    --theme-sticky-nav-dynamic-color-2: #3a3a3a;
 | 
				
			||||||
 | 
					    --theme-sticky-nav-dynamic-color-2--rgb: 58,58,58;
 | 
				
			||||||
 | 
					    --theme-link-dynamic-color-1: #000;
 | 
				
			||||||
 | 
					    --theme-link-dynamic-color-1--rgb: 0,0,0;
 | 
				
			||||||
 | 
					    --theme-link-dynamic-color-2: #3a3a3a;
 | 
				
			||||||
 | 
					    --theme-link-dynamic-color-2--rgb: 58,58,58;
 | 
				
			||||||
 | 
					    --theme-accent-dynamic-color-1: #fff;
 | 
				
			||||||
 | 
					    --theme-accent-dynamic-color-1--rgb: 255,255,255;
 | 
				
			||||||
 | 
					    --theme-accent-dynamic-color-2: #e6e6e6;
 | 
				
			||||||
 | 
					    --theme-accent-dynamic-color-2--rgb: 230,230,230;
 | 
				
			||||||
 | 
					    --theme-body-background-color: #286cab;
 | 
				
			||||||
 | 
					    --theme-body-background-color--rgb: 40,108,171;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    --theme-body-text-color: #fff;
 | 
				
			||||||
 | 
					    --theme-body-text-color--rgb: 255,255,255;
 | 
				
			||||||
 | 
					    --theme-body-text-color--hover: #cccccc;
 | 
				
			||||||
 | 
					    --theme-sticky-nav-background-color: #ffffff;
 | 
				
			||||||
 | 
					    --theme-sticky-nav-background-color--rgb: 255,255,255;
 | 
				
			||||||
 | 
					    --theme-sticky-nav-text-color: #000;
 | 
				
			||||||
 | 
					    --theme-sticky-nav-text-color--hover: #333333;
 | 
				
			||||||
 | 
					    --theme-page-background-color: #ffffff;
 | 
				
			||||||
 | 
					    --theme-page-background-color--rgb: 255,255,255;
 | 
				
			||||||
 | 
					    --theme-page-background-color--secondary: #f2f2f2;
 | 
				
			||||||
 | 
					    --theme-page-background-color--secondary--rgb: 242,242,242;
 | 
				
			||||||
 | 
					    --theme-page-text-color: #3a3a3a;
 | 
				
			||||||
 | 
					    --theme-page-text-color--rgb: 58,58,58;
 | 
				
			||||||
 | 
					    --theme-page-text-color--hover: #6d6d6d;
 | 
				
			||||||
 | 
					    --theme-page-text-mix-color: #9d9d9d;
 | 
				
			||||||
 | 
					    --theme-page-text-mix-color-95: #f5f5f5;
 | 
				
			||||||
 | 
					    --theme-page-accent-mix-color: #b6b6b6;
 | 
				
			||||||
 | 
					    --theme-page-headings-font: 'Rubik';
 | 
				
			||||||
 | 
					    --theme-link-color: #8a8a8a;
 | 
				
			||||||
 | 
					    --theme-link-color--rgb: 138,138,138;
 | 
				
			||||||
 | 
					    --theme-link-color--hover: #565656;
 | 
				
			||||||
 | 
					    --theme-link-label-color: #000;
 | 
				
			||||||
 | 
					    --theme-accent-color: #6c6c6c;
 | 
				
			||||||
 | 
					    --theme-accent-color--rgb: 108,108,108;
 | 
				
			||||||
 | 
					    --theme-accent-color--hover: #9f9f9f;
 | 
				
			||||||
 | 
					    --theme-accent-label-color: #fff;
 | 
				
			||||||
 | 
					    --theme-border-color: #cecece;
 | 
				
			||||||
 | 
					    --theme-border-color--rgb: 206,206,206;
 | 
				
			||||||
 | 
					    --theme-alert-color: #bf0017;
 | 
				
			||||||
 | 
					    --theme-alert-color--rgb: 191,0,23;
 | 
				
			||||||
 | 
					    --theme-alert-color--hover: #59000a;
 | 
				
			||||||
 | 
					    --theme-alert-color--secondary: #bf0017;
 | 
				
			||||||
 | 
					    --theme-alert-label: #fff;
 | 
				
			||||||
 | 
					    --theme-warning-color: #cf721c;
 | 
				
			||||||
 | 
					    --theme-warning-color--rgb: 207,114,28;
 | 
				
			||||||
 | 
					    --theme-warning-color--secondary: #ce711b;
 | 
				
			||||||
 | 
					    --theme-warning-label: #000;
 | 
				
			||||||
 | 
					    --theme-success-color: #0c742f;
 | 
				
			||||||
 | 
					    --theme-success-color--rgb: 12,116,47;
 | 
				
			||||||
 | 
					    --theme-success-color--secondary: #0c742f;
 | 
				
			||||||
 | 
					    --theme-success-label: #fff;
 | 
				
			||||||
 | 
					    --theme-message-color: #753369;
 | 
				
			||||||
 | 
					    --theme-message-label: #fff;
 | 
				
			||||||
 | 
					    --theme-community-header-color: #000000;
 | 
				
			||||||
 | 
					    --theme-community-header-color--hover: #333333;
 | 
				
			||||||
 | 
					    --theme-background-image-opacity: 100%;
 | 
				
			||||||
 | 
					    --theme-page-text-opacity-factor: 0.85;
 | 
				
			||||||
 | 
					    --theme-body-text-opacity-factor: 0.7;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.skin-fandomdesktop .CodeMirror{
 | 
				
			||||||
 | 
					    --codemirror-yellow: #a88d00;
 | 
				
			||||||
 | 
					    --codemirror-light-blue: #0096fb;
 | 
				
			||||||
 | 
					    --codemirror-blue: #08f;
 | 
				
			||||||
 | 
					    --codemirror-green: #290;
 | 
				
			||||||
 | 
					    --codemirror-red: #f50;
 | 
				
			||||||
 | 
					    --codemirror-dark-red: #a11;
 | 
				
			||||||
 | 
					    --codemirror-purple: #80c;
 | 
				
			||||||
 | 
					    --codemirror-pink: #e0e;
 | 
				
			||||||
 | 
					    --codemirror-light-gray: #929292;
 | 
				
			||||||
 | 
					    --codemirror-gray: #789797;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.mw-highlight {
 | 
				
			||||||
 | 
					    --pygments-background: #f4f3f4;
 | 
				
			||||||
 | 
					    --pygments-err: #f00;
 | 
				
			||||||
 | 
					    --pygments-c: #408080;
 | 
				
			||||||
 | 
					    --pygments-k: #008000;
 | 
				
			||||||
 | 
					    --pygments-o: #666;
 | 
				
			||||||
 | 
					    --pygments-ch: #408080;
 | 
				
			||||||
 | 
					    --pygments-cm: #408080;
 | 
				
			||||||
 | 
					    --pygments-cp: #b17300;
 | 
				
			||||||
 | 
					    --pygments-cpf: #408080;
 | 
				
			||||||
 | 
					    --pygments-c1: #408080;
 | 
				
			||||||
 | 
					    --pygments-cs: #408080;
 | 
				
			||||||
 | 
					    --pygments-gd: #a00000;
 | 
				
			||||||
 | 
					    --pygments-gr: #f00;
 | 
				
			||||||
 | 
					    --pygments-gh: #000080;
 | 
				
			||||||
 | 
					    --pygments-gi: #009500;
 | 
				
			||||||
 | 
					    --pygments-go: #808080;
 | 
				
			||||||
 | 
					    --pygments-gp: #000080;
 | 
				
			||||||
 | 
					    --pygments-gu: #800080;
 | 
				
			||||||
 | 
					    --pygments-gt: #04d;
 | 
				
			||||||
 | 
					    --pygments-kc: #008000;
 | 
				
			||||||
 | 
					    --pygments-kd: #008000;
 | 
				
			||||||
 | 
					    --pygments-kn: #008000;
 | 
				
			||||||
 | 
					    --pygments-kp: #008000;
 | 
				
			||||||
 | 
					    --pygments-kr: #008000;
 | 
				
			||||||
 | 
					    --pygments-kt: #b00040;
 | 
				
			||||||
 | 
					    --pygments-m: #666;
 | 
				
			||||||
 | 
					    --pygments-s: #ba2121;
 | 
				
			||||||
 | 
					    --pygments-na: #768826;
 | 
				
			||||||
 | 
					    --pygments-nb: #008000;
 | 
				
			||||||
 | 
					    --pygments-nc: #00f;
 | 
				
			||||||
 | 
					    --pygments-no: #800;
 | 
				
			||||||
 | 
					    --pygments-nd: #a2f;
 | 
				
			||||||
 | 
					    --pygments-ni: #7f7f7f;
 | 
				
			||||||
 | 
					    --pygments-ne: #d2413a;
 | 
				
			||||||
 | 
					    --pygments-nf: #00f;
 | 
				
			||||||
 | 
					    --pygments-nl: #818100;
 | 
				
			||||||
 | 
					    --pygments-nn: #00f;
 | 
				
			||||||
 | 
					    --pygments-nt: #008000;
 | 
				
			||||||
 | 
					    --pygments-nv: #19177c;
 | 
				
			||||||
 | 
					    --pygments-ow: #a2f;
 | 
				
			||||||
 | 
					    --pygments-w: #808080;
 | 
				
			||||||
 | 
					    --pygments-mb: #666;
 | 
				
			||||||
 | 
					    --pygments-mf: #666;
 | 
				
			||||||
 | 
					    --pygments-mh: #666;
 | 
				
			||||||
 | 
					    --pygments-mi: #666;
 | 
				
			||||||
 | 
					    --pygments-mo: #666;
 | 
				
			||||||
 | 
					    --pygments-sa: #ba2121;
 | 
				
			||||||
 | 
					    --pygments-sb: #ba2121;
 | 
				
			||||||
 | 
					    --pygments-sc: #ba2121;
 | 
				
			||||||
 | 
					    --pygments-dl: #ba2121;
 | 
				
			||||||
 | 
					    --pygments-sd: #ba2121;
 | 
				
			||||||
 | 
					    --pygments-s2: #ba2121;
 | 
				
			||||||
 | 
					    --pygments-se: #b62;
 | 
				
			||||||
 | 
					    --pygments-sh: #ba2121;
 | 
				
			||||||
 | 
					    --pygments-si: #b68;
 | 
				
			||||||
 | 
					    --pygments-sx: #008000;
 | 
				
			||||||
 | 
					    --pygments-sr: #b68;
 | 
				
			||||||
 | 
					    --pygments-s1: #ba2121;
 | 
				
			||||||
 | 
					    --pygments-ss: #19177c;
 | 
				
			||||||
 | 
					    --pygments-bp: #008000;
 | 
				
			||||||
 | 
					    --pygments-fm: #00f;
 | 
				
			||||||
 | 
					    --pygments-vc: #19177c;
 | 
				
			||||||
 | 
					    --pygments-vg: #19177c;
 | 
				
			||||||
 | 
					    --pygments-vi: #19177c;
 | 
				
			||||||
 | 
					    --pygments-vm: #19177c;
 | 
				
			||||||
 | 
					    --pygments-il: #666;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					body {
 | 
				
			||||||
 | 
					    background: linear-gradient(to bottom, rgba(225, 133, 155, 0) 15%, rgba(225, 133, 155, 0.8)), url(/static/internal-background.png);
 | 
				
			||||||
 | 
					    min-height: 100vh;
 | 
				
			||||||
 | 
					    padding: 4px;
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.page__main {
 | 
				
			||||||
 | 
					    border-radius: 3px;
 | 
				
			||||||
 | 
					    padding: 24px 36px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.internal-footer {
 | 
				
			||||||
 | 
					    max-width: 700px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue