Merge branch 'master' into develop
This commit is contained in:
commit
58258ec40d
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -11,3 +11,6 @@ pom.xml.asc
|
||||||
.hg/
|
.hg/
|
||||||
/resources/*
|
/resources/*
|
||||||
*~
|
*~
|
||||||
|
*.ods
|
||||||
|
|
||||||
|
*.csv
|
||||||
|
|
22
CHANGELOG.md
22
CHANGELOG.md
|
@ -1,24 +1,6 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/).
|
All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/).
|
||||||
|
|
||||||
## [Unreleased]
|
## [0.1.0] - 2018-08-19
|
||||||
### Changed
|
|
||||||
- Add a new arity to `make-widget-async` to provide a different widget shape.
|
|
||||||
|
|
||||||
## [0.1.1] - 2018-08-14
|
Initial release.
|
||||||
### Changed
|
|
||||||
- Documentation on how to make the widgets.
|
|
||||||
|
|
||||||
### Removed
|
|
||||||
- `make-widget-sync` - we're all async, all the time.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Fixed widget maker to keep working when daylight savings switches over.
|
|
||||||
|
|
||||||
## 0.1.0 - 2018-08-14
|
|
||||||
### Added
|
|
||||||
- Files from the new template.
|
|
||||||
- Widget maker public API - `make-widget-sync`.
|
|
||||||
|
|
||||||
[Unreleased]: https://github.com/your-name/mastodonusers/compare/0.1.1...HEAD
|
|
||||||
[0.1.1]: https://github.com/your-name/mastodonusers/compare/0.1.0...0.1.1
|
|
||||||
|
|
|
@ -2,6 +2,14 @@
|
||||||
|
|
||||||
A Clojure app to report and log the current number of users in the fediverse.
|
A Clojure app to report and log the current number of users in the fediverse.
|
||||||
|
|
||||||
|
This app depends on the API provided by [instances.social](https://instances.social/api/);
|
||||||
|
I have not investigatged the methodology by which they assemble their list of instances. In
|
||||||
|
any case it's impossible to tell how many of those accounts represent real individual human
|
||||||
|
users, and I don't currently do anything to establish how many of those accounts are active.
|
||||||
|
|
||||||
|
Please don't use this app to DDoS `instances.social`; it really shouldn't be necessary to run
|
||||||
|
it more than once a day.
|
||||||
|
|
||||||
## Configuring
|
## Configuring
|
||||||
|
|
||||||
You should obtain a key from [instances.social](https://instances.social/api/token) and write it (just the file, nothing else) into `resources/secret.txt`.
|
You should obtain a key from [instances.social](https://instances.social/api/token) and write it (just the file, nothing else) into `resources/secret.txt`.
|
||||||
|
|
11
project.clj
11
project.clj
|
@ -1,10 +1,11 @@
|
||||||
(defproject mastodonusers "0.1.0-SNAPSHOT"
|
(defproject mastodonusers "0.1.0"
|
||||||
:description "FIXME: write description"
|
:description "A Clojure app to report and log the current number of users in the fediverse."
|
||||||
:url "http://example.com/FIXME"
|
:url "https://github.com/simon-brooke/mastodonusers"
|
||||||
:license {:name "Eclipse Public License"
|
:license {:name "GNU General Public License,version 2.0"
|
||||||
:url "http://www.eclipse.org/legal/epl-v10.html"}
|
:url "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html"}
|
||||||
:dependencies [[org.clojure/clojure "1.8.0"]
|
:dependencies [[org.clojure/clojure "1.8.0"]
|
||||||
[org.clojure/data.json "0.2.6"]
|
[org.clojure/data.json "0.2.6"]
|
||||||
|
[org.clojure/tools.cli "0.3.7"]
|
||||||
[clj-http "3.9.1"]
|
[clj-http "3.9.1"]
|
||||||
[clj-time "0.14.4"]]
|
[clj-time "0.14.4"]]
|
||||||
:aot [mastodonusers.core]
|
:aot [mastodonusers.core]
|
||||||
|
|
|
@ -1,25 +1,65 @@
|
||||||
(ns mastodonusers.core
|
(ns mastodonusers.core
|
||||||
(:require [clojure.data.json :as json]
|
(:require [clojure.data.json :as json]
|
||||||
[clojure.pprint :refer :all]
|
[clojure.pprint :refer :all]
|
||||||
|
[clojure.string :as s]
|
||||||
|
[clojure.tools.cli :refer [parse-opts]]
|
||||||
[clojure.walk :refer [keywordize-keys]]
|
[clojure.walk :refer [keywordize-keys]]
|
||||||
[clj-http.client :as h]
|
[clj-http.client :as h]
|
||||||
[clj-time.core :as t]
|
[clj-time.core :as t]
|
||||||
[clj-time.format :as f])
|
[clj-time.format :as f])
|
||||||
(:gen-class))
|
(:gen-class))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;;;
|
||||||
|
;;;; mastodonusers.core
|
||||||
|
;;;;
|
||||||
|
;;;; This program is free software; you can redistribute it and/or
|
||||||
|
;;;; modify it under the terms of the GNU General Public License
|
||||||
|
;;;; as published by the Free Software Foundation; either version 2
|
||||||
|
;;;; of the License, or (at your option) any later version.
|
||||||
|
;;;;
|
||||||
|
;;;; This program is distributed in the hope that it will be useful,
|
||||||
|
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
;;;; GNU General Public License for more details.
|
||||||
|
;;;;
|
||||||
|
;;;; You should have received a copy of the GNU General Public License
|
||||||
|
;;;; along with this program; if not, write to the Free Software
|
||||||
|
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
;;;; USA.
|
||||||
|
;;;;
|
||||||
|
;;;; Copyright (C) 2018 Simon Brooke
|
||||||
|
;;;;
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
;; (def application-id "431276798")
|
(def cli-options
|
||||||
;; (def application-name "mastodonusers")
|
[["-h" "--help" "Show this message"
|
||||||
|
:default false]
|
||||||
|
["-o" "--csv" "output data as comma-separated values"]
|
||||||
|
["-s" "--bearer-secret [SECRET]" "The secret which identifies us to instances.social"]
|
||||||
|
["-v" "--verbosity [LEVEL]" nil "Verbosity level - integer value required"
|
||||||
|
:parse-fn #(Integer/parseInt %)
|
||||||
|
:default 0]
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
(defn usage
|
||||||
|
"Show a usage message. `options` should be options as
|
||||||
|
parsed by [clojure.tools.cli](https://github.com/clojure/tools.cli)"
|
||||||
|
[options]
|
||||||
|
(println (:summary options)))
|
||||||
|
|
||||||
|
|
||||||
(defn fetch-data
|
(defn fetch-data
|
||||||
"Fetch current data from instances.social with our key"
|
"Fetch current data from instances.social with this `secret` key"
|
||||||
[]
|
[secret]
|
||||||
(h/get
|
(h/get
|
||||||
"https://instances.social/api/1.0/instances/list"
|
"https://instances.social/api/1.0/instances/list"
|
||||||
{:headers {:authorization (str
|
{:headers {:authorization (str
|
||||||
"Bearer "
|
"Bearer "
|
||||||
(slurp "resources/secret.txt"))}
|
(or
|
||||||
|
secret
|
||||||
|
(slurp "resources/secret.txt")))}
|
||||||
:query-params {:count 0}
|
:query-params {:count 0}
|
||||||
:accept :json}))
|
:accept :json}))
|
||||||
|
|
||||||
|
@ -61,14 +101,68 @@
|
||||||
c)))))
|
c)))))
|
||||||
|
|
||||||
|
|
||||||
(defn -main [& args]
|
(defn ->csv
|
||||||
|
"Return the contents of this EDN `file`, assumed to contain a map with
|
||||||
|
date/time keys and count values, in CSV format."
|
||||||
|
[file]
|
||||||
|
(let [data (read-string (slurp file))]
|
||||||
|
(s/join
|
||||||
|
"\n"
|
||||||
|
(map
|
||||||
|
#(str % ", " (data %))
|
||||||
|
(sort
|
||||||
|
#(compare
|
||||||
|
(f/parse
|
||||||
|
;; (f/formatters :basic-date-time)
|
||||||
|
%1)
|
||||||
|
(f/parse
|
||||||
|
;; (f/formatters :basic-date-time)
|
||||||
|
%2))
|
||||||
|
(keys data))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn process
|
||||||
|
"Process these parsed `options`."
|
||||||
|
[options]
|
||||||
|
(let [c (count-users
|
||||||
|
(fetch-data
|
||||||
|
(-> options :options :bearer-secret)))
|
||||||
|
args (:arguments options)]
|
||||||
|
(if-not
|
||||||
|
(empty? args)
|
||||||
|
(update-file (first args) c))
|
||||||
|
(if-not
|
||||||
|
(zero? (-> options :options :verbosity))
|
||||||
|
(println "Total #fediverse user accounts: " c))
|
||||||
|
(if
|
||||||
|
(and
|
||||||
|
(not (empty? args))
|
||||||
|
(-> options :options :csv))
|
||||||
|
(println (->csv (first args))))
|
||||||
|
c))
|
||||||
|
|
||||||
|
|
||||||
|
(defn -main
|
||||||
"Print a count of the current number of user accounts in the fediverse.
|
"Print a count of the current number of user accounts in the fediverse.
|
||||||
If an argument is present, it is presumed to be the pathname of
|
If an argument is present, it is presumed to be the pathname of
|
||||||
an EDN formatted file containing a map mapping times to counts, which will
|
an EDN formatted file containing a map mapping times to counts, which will
|
||||||
be updated with the current count."
|
be updated with the current count."
|
||||||
(let [c (count-users (fetch-data))]
|
[& args]
|
||||||
(if-not (empty? args) (update-file (first args) c))
|
(let [options (parse-opts args cli-options)]
|
||||||
(println "Total #fediverse user accounts: " c)
|
(cond
|
||||||
c))
|
(empty? args)
|
||||||
|
(usage options)
|
||||||
|
(seq (:errors options))
|
||||||
|
(do
|
||||||
|
(doall
|
||||||
|
(map
|
||||||
|
println
|
||||||
|
(:errors options)))
|
||||||
|
(usage options))
|
||||||
|
(-> options :options :help)
|
||||||
|
(usage options)
|
||||||
|
true
|
||||||
|
(process options))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue