summaryrefslogtreecommitdiff
path: root/src/weepinbell/core.clj
blob: 0cc7bda1eefec916113bbff44c7b705b75979b6f (plain)
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
(ns weepinbell.core
  "Main component that loads resources and start other components."
  (:require [weepinbell.storage.spec]
            [weepinbell.config :refer [load-config]]
            [weepinbell.webhook :as webhook]
            [weepinbell.storage.edn-storage :as edn]
            [weepinbell.storage.h2 :as h2]
            [weepinbell.storage.worker :as worker]
            [clojure.core.async :refer [chan >!! <!!]]
            [taoensso.timbre :as timbre]
            [nrepl.server :as nrepl]
            [weepinbell.migration :as m]
            ;; two main subsystems' facades
            [weepinbell.processor.facade :refer [start-processor]]
            [weepinbell.webserver.facade :refer [start-webserver]])
  (:import (sun.misc Signal SignalHandler))
  (:gen-class))

; Handle startup; Callable from REPL
;; start whole system
(defn start-system
  "Start webmention processor and webserver in the background.
   Returns a function that performs a graceful shutdown."
  [config]
  {:post [fn?]}
  (let [;; webmention channel 
        ;; Receiver puts webmention requests in. 
        ;; Processor takes them out.
        wmc (chan)
        ;; Storage middle layer, a map of data-manipulating functions.
        ;; Supports various storage as long as the map conforms storage.spec.
        data-path (:data-path config)
        bare-store (case (:storage-type config)
                     :edn (edn/use-store data-path)
                     :h2 (h2/use-store data-path))
        [stop-worker async-store] (worker/start bare-store)
        ;; Hooks, a map of callback functions that processor calls 
        ;; on certain events. Can be used for webhooks and more.
        hooks (webhook/make-hooks config)
        ;; start processor and webservers and get stoppers 
        stop-processor (start-processor
                        {:wmc wmc
                         :callbacks hooks
                         :storage async-store
                         :config config})
        stop-webserver (start-webserver
                        {:wmc wmc
                         :store async-store
                         :config config})]
    (fn []
      (stop-webserver) ;; stop receiving webmentions
      (stop-processor) ;; stop processing webmentions
      (stop-worker)    ;; stop writing to storage
      true)))

; Entry point; Terminal user interface
;; start up system and wait for signals to perform graceful shutdown
(defn start-engine []
  (let [config-file (or (System/getenv "WEEPINBELL_CONFIG") "config.edn")
        config (load-config config-file)
        log-level (or (System/getenv "WEEPINBELL_LOGLEVEL") 
                      (:log-level config) :info)
        nrepl-port (:nrepl-port config)]
    (timbre/merge-config! {:min-level log-level})
    
    (let [done-chan (chan 1)
          stop-system (do (timbre/info "starting weepinbell...")
                          (start-system config))
          nrepl-server (when nrepl-port
                         (timbre/info "starting nREPL server on port" nrepl-port)
                         (nrepl/start-server :port nrepl-port))]
      ;; Register signal handlers for SIGINT and SIGTERM
      (doseq [signal ["INT" "TERM"]]
        (Signal/handle (Signal. signal)
                       (reify SignalHandler
                         (handle [_ sig]
                           (stop-system)
                           (when nrepl-server
                             (nrepl/stop-server nrepl-server))
                           (timbre/info "signal" (.getName sig) "received."
                                        "gracefully shut down weepinbell.")
                           (>!! done-chan true)))))
      ;; block til signal received
      (<!! done-chan))))

(defn -main [& args]
  (case (first args)
    "migrate-db" (apply m/edn->h2 (rest args))
    "edn-jf2ify" (apply m/edn-jf2ify (rest args))
    (start-engine)))