Skip to content

Instantly share code, notes, and snippets.

@mtnygard
Created March 9, 2017 14:46
Show Gist options
  • Save mtnygard/586f4681b0850adb3be0923c54f74bc4 to your computer and use it in GitHub Desktop.
Save mtnygard/586f4681b0850adb3be0923c54f74bc4 to your computer and use it in GitHub Desktop.
Access CLJSJS assets via a Pedestal Interceptor
(ns overt.cljsjs
(:require [clojure.java.io :as io]
[io.pedestal.interceptor :as i]
[io.pedestal.log :as log])
(:import java.net.URL
java.util.Date
java.util.jar.JarFile))
(def ^:private default-base "cljsjs")
(defn- asset-headers
[asset-info]
{"Content-Length" (str (:content-length asset-info))})
(defn- last-modified
[cxn]
(let [ts (.getLastModified cxn)]
(when-not (zero? ts)
(Date. ts))))
(defn- asset-info
[path]
(when-let [url (io/resource path)]
(when-let [cxn (.openConnection url)]
{:contents (.getInputStream cxn)
:content-length (.getContentLength cxn)
:last-modified (last-modified cxn)})))
(defn- serve-asset
[ctx path]
(if-let [info (asset-info path)]
(assoc ctx :response
{:status 200
:body (:contents info)
:headers (asset-headers info)})
ctx))
(defn resources-containing
[fragment]
(enumeration-seq
(.. (Thread/currentThread) getContextClassLoader (getResources fragment))))
(defn jar?
[^URL url]
(= "jar" (.getProtocol url)))
(defn expand-entries
[jar-url]
(let [[_ jar] (re-find #"^file:(.*\.jar)\!.*$" (.getPath jar-url))]
(enumeration-seq (.entries (JarFile. (io/file jar))))))
(defn directory?
[jar-entry]
(.isDirectory jar-entry))
(defn cljsjs-asset?
[jar-entry]
(.startsWith (.getName jar-entry) "cljsjs"))
(defn entry-name
[jar-entry]
(.getName jar-entry))
(def jar-entry-names
(comp
(filter jar?)
(mapcat expand-entries)
(remove directory?)
(filter cljsjs-asset?)
(map entry-name)))
(defn index-assets
[base]
(into #{}
jar-entry-names
(resources-containing base)))
(defn assets
([]
(assets default-base))
([base]
(let [index (index-assets base)]
{:name ::assets
:enter
(fn [ctx]
(log/info :cljsjs/assets true)
(let [request-path (subs (-> ctx :request :path-info) 1)]
(log/info :request-path request-path :in-index? (contains? index request-path))
(if (contains? index request-path)
(serve-asset ctx request-path)
ctx)))})))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment