Skip to content

Commit

Permalink
self update (work in progress)
Browse files Browse the repository at this point in the history
  • Loading branch information
BrunoBonacci committed Sep 21, 2015
1 parent 6905c4c commit 75cad73
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 19 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ You can also use the convenience functions which use the global `*provider*`.

The provider is initialized with
[Stuart Sierra's Component](https://github.com/stuartsierra/component)
library, therefore if you want you can include the provider component in your system map:
library, therefore if you want you can include the provider component
in your system map:

```Clojure
(defn your-system [config-options]
Expand Down
3 changes: 2 additions & 1 deletion project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
[com.maxmind.geoip2/geoip2 "2.3.1"]
[clj-http "1.1.2"]
[pandect "0.5.2"]
[com.stuartsierra/component "0.2.3"]]
[com.stuartsierra/component "0.2.3"]
[com.brunobonacci/safely "0.1.0-SNAPSHOT"]]

:deploy-repositories [["clojars" {:url "https://clojars.org/repo/"
:sign-releases false}]])
148 changes: 131 additions & 17 deletions src/ip_geoloc/maxmind.clj
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
(ns ip-geoloc.maxmind
(:require [clojure.java.io :as io])
(:require [clojure.java.io :as io]
[safely.core :refer [safely sleep]])
(:require [pandect.algo.md5 :as hash])
(:require [clj-http.client :as http])
(:import com.maxmind.geoip2.DatabaseReader$Builder
Expand Down Expand Up @@ -118,7 +119,10 @@
"get a concise geo IP lookup")

(coordinates [this ip]
"get only coordinates info."))
"get only coordinates info.")

(database-location [this]
"Returns the path of the current database"))


(defmacro if-ip-exists [& body]
Expand All @@ -133,14 +137,16 @@
GeoIpProvider

(init [this]
(let [db (if (.endsWith db-path ".gz")
(let [db-path (if (string? db-path) db-path (.getAbsolutePath db-path))
db (if (.endsWith db-path ".gz")
(java.util.zip.GZIPInputStream.
(io/input-stream db-path))
(io/input-stream db-path))]
(MaxMind2. db-path (.build (DatabaseReader$Builder. db)))))

(close [this]
(.close db)
(when db
(.close db))
nil)

(full-geo-lookup [this ip]
Expand All @@ -166,7 +172,10 @@
(coordinates [this ip]
(if-ip-exists
(->clojure
(.getLocation (.city db (java.net.InetAddress/getByName ip)))))))
(.getLocation (.city db (java.net.InetAddress/getByName ip))))))

(database-location [this]
db-path))


(defn- gunzip-file [in out]
Expand All @@ -187,8 +196,13 @@
(io/file to)))


(defn check-db [md5 file]
(= md5 (hash/md5-file file)))
(defn check-db [md5 afile]
(when afile
(= md5
(safely
(hash/md5-file afile)
:on-error
:default nil))))


(defn fetch-db-md5 [url]
Expand All @@ -197,21 +211,121 @@

(defn update-db [{:keys [database-url database-md5-url database-folder]}]
(let [dbgz (io/file database-folder "GeoLite2-City.mmdb.gz")
db (io/file database-folder "GeoLite2-City.mmdb")]
db (io/file database-folder
(str "GeoLite2-City.mmdb." (System/currentTimeMillis)))]
(download-db database-url dbgz)
(gunzip-file dbgz db)
(check-db (fetch-db-md5 database-md5-url) db)))
(if (check-db (fetch-db-md5 database-md5-url) db)
(do
(let [newdb (io/file (str (.getAbsolutePath db) ".ok"))]
(.renameTo db newdb)
newdb))
(safely (.delete db) :on-error :ignore true))))


(defn find-last-available-db [{:keys [database-folder]}]
(->> (io/file database-folder)
(.list)
(filter #(re-matches #"GeoLite2-City\.mmdb\.\d+\.ok" %))
(sort)
(last)))


(defn update-db-if-needed [current-db-file
{:keys [database-url database-md5-url
database-folder] :as cfg}]
(when-not (check-db (fetch-db-md5 database-md5-url) current-db-file)
(update-db cfg)))


(comment
{:database-file nil
:database-folder "/tmp/maxmind"
:auto-update true
:auto-update-check-time (* 3 60 60 1000) ;; every 3 hours
:provider (atom nil)
:update-thread (atom nil)})


(defn update-db! [{:keys [provider] :as config}]
(safely
(let [old-provider @provider
current-db-file (when old-provider (database-location old-provider))
newdb (update-db-if-needed current-db-file config)]
(when newdb
(println "A new ip-geoloc db has been found:" newdb)
(let [new-provider (init (MaxMind2. newdb nil))]
(if (compare-and-set! provider old-provider new-provider)
(do
(when old-provider (close old-provider))
(println "new db successfully installed."))
(do
(when new-provider (close new-provider))
(println "WARN the new db couldn't be loaded."))))))

:on-error
:ignore true))


(defn start-update-db-background-thread!
[{:keys [auto-update-check-time] :as config}]
(let [thread
(Thread.
(fn []
(loop []
(println "background thread to update ip-geoloc db started!")

(update-db! config)

(sleep auto-update-check-time :+/- 0.20)

;; if the thread is interrupted then exit
(when-not (.isInterrupted (Thread/currentThread))
(recur))

(println "background thread to update ip-geoloc db stopped!")))
"ip-geoloc update thread")]
(.start thread)
(fn [] (.interrupt thread))))

(comment

(download-db *database-url* "/tmp/GeoLite2-City.mmdb.gz")
(gunzip-file "/tmp/GeoLite2-City.mmdb.gz" "/tmp/GeoLite2-City.mmdb")
(def lastdb
(update-db {:database-url *database-url*
:database-md5-url *database-md5-url*
:database-folder "/tmp/dir2"}))

(update-db-if-needed lastdb
{:database-url *database-url*
:database-md5-url *database-md5-url*
:database-folder "/tmp/dir2"})


(def cfg {:database-file nil
:database-folder "/tmp/maxmind"
:auto-update true
:auto-update-check-time (* 3 1000) ;; every 3 hours
:provider (atom nil)
:update-thread (atom nil)
:database-url *database-url*
:database-md5-url *database-md5-url*
})


(update-db! cfg)

(database-location @(:provider cfg))

(def t (start-update-db-background-thread! cfg))

(t)

(update-db-if-needed nil
cfg)

(check-db
(fetch-db-md5 *database-md5-url*)
"/tmp/GeoLite2-City.mmdb")

(update-db {:database-url *database-url*
:database-md5-url *database-md5-url*
:database-folder "/tmp/dir2"})
(def p (MaxMind2. "/tmp/maxmind/GeoLite2-City.mmdb.1442851935955.ok" nil))
(def p (init p))
(close p)
(database-location nil)
)

0 comments on commit 75cad73

Please sign in to comment.