/sighting-server.rkt

http://github.com/elibarzilay/rudybot · Shell · 115 lines · 107 code · 5 blank · 3 comment · 1 complexity · 7bf3137f1655572b220532e44f25e908 MD5 · raw file

  1. #! /bin/sh
  2. #| Hey Emacs, this is -*-scheme-*- code!
  3. |#
  4. ;; This is a "servlet"
  5. ;; (http://pre.plt-scheme.org/docs/html/web-server/servlet.html) that
  6. ;; displays the sightings database in a simple web page.
  7. ;; for i in sighting-server.ss sighting.ss sightings.db; do ln -s $i
  8. ;; /usr/local/src/plt/collects/web-server/default-web-root/servlets/; done
  9. ;;
  10. ;; http://server:8080/servlets/sighting-server.ss
  11. #lang racket
  12. (require (planet offby1/offby1/zdate)
  13. mzlib/etc
  14. web-server/servlet
  15. net/url)
  16. (provide interface-version timeout start)
  17. (define interface-version 'v1)
  18. (define timeout +inf.0)
  19. ;; a module for the PLT web server. It reads "sightings.db", and
  20. ;; nicely formats the data for display, as a table -- one entry per
  21. ;; row. The table has buttons on top of the "who" and "when" columns;
  22. ;; if you click one of those buttons, it sorts the table by that
  23. ;; column.
  24. (define *sightings-file-path*
  25. (build-path
  26. (this-expression-source-directory)
  27. "sightings.db"))
  28. ;; this might break, if it gets called at the same time as some other
  29. ;; process (namely, the IRC bot) is writing the file.
  30. (define (*sightings*)
  31. (hash-map (with-input-from-file *sightings-file-path* read)
  32. cons))
  33. (define (make-button column-name)
  34. `(th (input ([name "column"]
  35. [value ,(symbol->string column-name)]
  36. [type "submit"])
  37. )))
  38. (define (start initial-request)
  39. (fprintf
  40. (current-error-port)
  41. "~a ~a ~s~%"
  42. (zdate)
  43. (request-client-ip initial-request)
  44. (url->string (request-uri initial-request)))
  45. (let ([requested-sort-column
  46. (let ([datum (cond
  47. [(assq 'column (request-bindings initial-request)) => cdr]
  48. [else 'who])])
  49. (cond
  50. [(string? datum) (string->symbol datum)]
  51. [else datum]))])
  52. (define generate-response
  53. (lambda ()
  54. (let ([s (*sightings*)])
  55. `(html
  56. (body
  57. (h3
  58. ,(format
  59. "~a sightings as of ~a, sorted by ~s"
  60. (length s)
  61. (zdate (file-or-directory-modify-seconds *sightings-file-path*))
  62. requested-sort-column))
  63. (table ([rules "all"])
  64. (tr
  65. (form ([method "get"]
  66. [action ,(url->string (request-uri initial-request))])
  67. ,@(map make-button (list 'who 'where 'when 'what))))
  68. ,@(map
  69. (lambda (p)
  70. `(tr
  71. (td (small (tt ,(format "~a" (car p)))))
  72. (td (small (tt ,(format "~a" (sighting-where (cdr p))))))
  73. (td (small (tt ,(format "~a" (zdate (sighting-when (cdr p)))))))
  74. (td (small (tt ,(format "~a" (string-join
  75. (sighting-words (cdr p)) " ")))))))
  76. (sort
  77. s
  78. (lambda (p1 p2)
  79. (case requested-sort-column
  80. [(who)
  81. (string-ci<? (car p1)
  82. (car p2))]
  83. [(where)
  84. (string-ci<? (sighting-where (cdr p1))
  85. (sighting-where (cdr p2)))]
  86. ;; newest first
  87. [(when)
  88. (> (sighting-when (cdr p1))
  89. (sighting-when (cdr p2)))]
  90. [else
  91. (string-ci<? (string-join
  92. (sighting-words (cdr p1)) " ")
  93. (string-join
  94. (sighting-words (cdr p2)) " "))]))))))))))
  95. (with-errors-to-browser send/finish generate-response))
  96. )