<commit_before>(ns puppetlabs.trapperkeeper.services.status.status-core
  (:require [schema.core :as schema]
            [compojure.core :as compojure]
            [ring.middleware.json :as ring-json]
            [puppetlabs.kitchensink.core :as ks]))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Schemas

(def ServiceInfo
  {:service-version schema/Str
   :service-status-version schema/Int
   :status-fn (schema/make-fn-schema schema/Any schema/Any)})

(def ServicesInfo
  {schema/Str [ServiceInfo]})

(def ServiceStatus
  {:service-version schema/Str
   :service-status-version schema/Int
   :status schema/Any})

(def ServicesStatus
  {schema/Str ServiceStatus})

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Public

(schema/defn service-status-map :- ServiceInfo
  [svc-version status-version status-fn]
  {:service-version svc-version
   :service-status-version status-version
   :status-fn status-fn})

(defn update-status-context
  "Update the :status-fns atom in the service context."
  [status-fns-atom svc-name svc-version status-version status-fn]
  (let [status-map (service-status-map svc-version status-version status-fn)]
    (swap! status-fns-atom update-in [svc-name] conj status-map)))

(schema/defn call-latest-status-fn-for-service :- ServiceStatus
  "Given a list of maps containing service information and a status function,
  find the latest version, and return a map with the service's version, the
  version of the service's status, and the results of calling this status
  function."
  [service :- [ServiceInfo]]
  (let [latest-status (last (sort-by :service-status-version service))]
    {:service-version (:service-version latest-status)
     :service-status-version (:service-status-version latest-status)
     :status ((:status-fn latest-status))}))

(schema/defn call-status-fns :- ServicesStatus
  [context]
  "Call the latest status function for each service in the service context,
  and return a map of service to service status."
  (ks/mapvals call-latest-status-fn-for-service (deref (:status-fns context))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Compojure App

(defn build-routes [context]
  (compojure/routes
    (compojure/context "/v1" []
      (compojure/GET "/services" []
        (let [statuses (call-status-fns context)]
          {:status 200
           :body {"services" statuses}})))))

(defn build-handler [context]
  (-> (build-routes context)
      ring-json/wrap-json-response))
<commit_msg>(TK-171) Add TODO for input/output specification in status-fn schema<commit_after>(ns puppetlabs.trapperkeeper.services.status.status-core
  (:require [schema.core :as schema]
            [compojure.core :as compojure]
            [ring.middleware.json :as ring-json]
            [puppetlabs.kitchensink.core :as ks]))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Schemas

(def ServiceInfo
  {:service-version schema/Str
   :service-status-version schema/Int
   ;; TODO: actually specify inputs/outputs of callback function in this
   ;; schema
   :status-fn (schema/make-fn-schema schema/Any schema/Any)})

(def ServicesInfo
  {schema/Str [ServiceInfo]})

(def ServiceStatus
  {:service-version schema/Str
   :service-status-version schema/Int
   :status schema/Any})

(def ServicesStatus
  {schema/Str ServiceStatus})

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Public

(schema/defn service-status-map :- ServiceInfo
  [svc-version status-version status-fn]
  {:service-version svc-version
   :service-status-version status-version
   :status-fn status-fn})

(defn update-status-context
  "Update the :status-fns atom in the service context."
  [status-fns-atom svc-name svc-version status-version status-fn]
  (let [status-map (service-status-map svc-version status-version status-fn)]
    (swap! status-fns-atom update-in [svc-name] conj status-map)))

(schema/defn call-latest-status-fn-for-service :- ServiceStatus
  "Given a list of maps containing service information and a status function,
  find the latest version, and return a map with the service's version, the
  version of the service's status, and the results of calling this status
  function."
  [service :- [ServiceInfo]]
  (let [latest-status (last (sort-by :service-status-version service))]
    {:service-version (:service-version latest-status)
     :service-status-version (:service-status-version latest-status)
     :status ((:status-fn latest-status))}))

(schema/defn call-status-fns :- ServicesStatus
  [context]
  "Call the latest status function for each service in the service context,
  and return a map of service to service status."
  (ks/mapvals call-latest-status-fn-for-service (deref (:status-fns context))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Compojure App

(defn build-routes [context]
  (compojure/routes
    (compojure/context "/v1" []
      (compojure/GET "/services" []
        (let [statuses (call-status-fns context)]
          {:status 200
           :body {"services" statuses}})))))

(defn build-handler [context]
  (-> (build-routes context)
      ring-json/wrap-json-response))

{'fraction_non_alphanumeric': 0.18066653673747807, 'fraction_numerical': 0.0021438316117715845, 'mean_word_length': 3.997078870496592, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7588200', 'n_tokens_mistral': 1701, 'n_tokens_neox': 1578, 'n_words': 408}