This repository has been archived by the owner on Apr 9, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
core.clj
129 lines (118 loc) · 4.9 KB
/
core.clj
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
(ns naughtmq.core
(:require [taoensso.timbre :as log]
[clojure.java.io :as io])
(:import [naughtmq PrivateLoader]
[org.zeromq EmbeddedLibraryTools]
[java.lang.reflect Field Modifier]))
(def version-for
{"jzmq" "2.2.2"
"zmq" "3.2.4"})
(defn- os
"Returns a string representing the current operating system, one of win,
linux, or mac."
[]
(let [os-arch (. (System/getProperty "os.arch") toLowerCase)
os-name (. (System/getProperty "os.name") toLowerCase)]
(cond (.startsWith os-name "win") "win"
(.startsWith os-name "mac") "mac"
(.startsWith os-name "linux") "linux"
:else
(throw (UnsupportedOperationException.
(str "Unsupported platform: " os-name ", " os-arch))))))
(defn- arch
"Returns a string representing the current architecture, one of x86 or
x86_64."
[]
(let [os-arch (. (System/getProperty "os.arch") toLowerCase)
os-name (. (System/getProperty "os.name") toLowerCase)]
(condp = os-arch
"x86" "x86"
"i386" "x86"
"i686" "x86"
"x86_64" "x86_64"
"amd64" "x86_64"
(throw (UnsupportedOperationException.
(str "Unsupported platform: " os-name ", " os-arch))))))
(defn- os-temp-dir
"Returns an OS-specific temp dir. Mostly needed because java.io.tmpdir yields
nondeterministic results on Mac OS X, which, combined with the rather rigid
way in which Mac OS X resolves dynamic libraries, makes it unreliable."
[lib-name]
(io/file (str (cond (= "mac" (os)) "/tmp/"
:else (System/getProperty "java.io.tmpdir"))
"/naughtmq/" lib-name "/" (version-for lib-name) "/")))
(defn- os-name
"Returns an os-specific name for the given library name. For example, zmq
will become libzmq.dylib on OS X."
[lib-name]
(condp = (os)
"mac" (str "lib" lib-name ".dylib")
"linux" (str "lib" lib-name ".so")
"win" (str lib-name ".dll")))
(defn- save-library
[lib-name]
(let [lib-path (str "native/" (arch) "/" (os) "/" (os-name lib-name))
tmp-dir (os-temp-dir lib-name)
tmp-path (-> (str tmp-dir "/" (os-name lib-name)) io/file)]
(if (not (.exists tmp-dir)) (.mkdirs tmp-dir))
(if (not (.exists tmp-path))
(with-open [in (-> lib-path io/resource io/input-stream)
out (-> tmp-path io/output-stream)]
(io/copy in out)
(log/info (str "Saved lib to: " tmp-path)))
(with-open [in (-> lib-path io/resource io/input-stream)
out (-> tmp-path io/input-stream)]
(let [to-byte-seq (fn [is] (let [os (java.io.ByteArrayOutputStream.)]
(io/copy is os)
(-> os .toByteArray seq)))]
(if (not (= (to-byte-seq in)
(to-byte-seq out)))
(throw
(IllegalStateException.
(str "File "
tmp-path
" already exists but has different content.")))
(log/info (str "Lib was already there: " tmp-path))))))
(.getAbsolutePath tmp-path)))
(defn- load-library
"Loads the given file as a native library. The file must be in the native
folder in the CLASSPATH."
[s]
(let [file_path (save-library s)]
(try (PrivateLoader/load file_path)
(catch java.io.IOException e
(log/error (str "Could not load native file: " s))
(throw e)))))
(defn- load-libraries
"Loads the native libraries."
[]
(let [libs (get {"win" ["msvcr100" "msvcp100" "libzmq" "jzmq"]
"linux" ["zmq" "jzmq"]
"mac" ["zmq" "jzmq"]}
(os))]
(doseq [l libs] (load-library l))))
(defn- disable-jzmq-dynamic-loading
"Prevents jzmq to look for the native library in java.library.path, as the
whole point of this namespace is that the native libraries must already be
loaded when the JVM loads the ZMQ class. This requires setting a final field
of the org.zeromq.EmbeddedLibraryTools class."
[]
(let [f (.getField EmbeddedLibraryTools "LOADED_EMBEDDED_LIBRARY")
modif (.getDeclaredField Field "modifiers")]
(.setAccessible f true)
(.setAccessible modif true)
(.setInt modif f (bit-and (.getModifiers f) (bit-not Modifier/FINAL)))
(.set f nil true)
(.setInt modif f (bit-and (.getModifiers f) Modifier/FINAL))))
(defn load-zmq-native
"Loads all required native libraries for using ZeroMQ on the current
platform. This is done by first extracting the binaries from the JAR, then
copying them to /tmp/naughtmq/ (or the equivalent on Windows), and then
asking the JVM to load the native libraries there. This is done in the
correct order, so that the JVM does not need to look at java.library.path.
Additionally, prevents JZMQ itself from asking the JVM to load the native
libraries."
[]
(load-libraries)
(disable-jzmq-dynamic-loading))
(load-zmq-native)