Skip to content

Commit 0942825

Browse files
Merge pull request #97 from yetanalytics/pip-81
[PIP 81] - Toggle JSON-Only
2 parents 7984095 + b3a9584 commit 0942825

File tree

11 files changed

+91
-43
lines changed

11 files changed

+91
-43
lines changed

doc/options.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ All options:
4848
-p, --xapi-get-param KEY=VALUE {} xAPI GET Parameters
4949
--source-username USERNAME Source LRS BASIC Auth username
5050
--source-password PASSWORD Source LRS BASIC Auth password
51+
--json-only Only operate in JSON statement mode for data transfer, ignoring Attachments/multipart (for compatibility issues)
5152
--source-auth-uri URI Source LRS OAuth autentication URI
5253
--source-client-id ID Source LRS OAuth client ID
5354
--source-client-secret SECRET Source LRS OAuth client secret

src/cli/com/yetanalytics/xapipe/cli.clj

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@
143143
(log/debugf "Adding shutdown hook for job %s" (:id job))
144144
(.addShutdownHook (Runtime/getRuntime)
145145
(Thread. ^Runnable
146-
(fn []
147-
(force-stop-job! stop states))))
146+
(fn []
147+
(force-stop-job! stop states))))
148148
(let [_ (log/debugf "Waiting for job %s" (:id job))
149149
{{:keys [status]} :state
150150
:as job-result} (-> states
@@ -201,6 +201,7 @@
201201
:get-params [:source :get-params]
202202
:source-username [:source :request-config :username]
203203
:source-password [:source :request-config :password]
204+
:json-only [:source :request-config :json-only]
204205
:source-auth-uri [:source :request-config :oauth-params :auth-uri]
205206
:source-client-id [:source :request-config :oauth-params :client-id]
206207
:source-client-secret [:source :request-config :oauth-params :client-secret]
@@ -393,8 +394,8 @@
393394
(defn list-store-jobs
394395
[store]
395396
(doseq [[page batch] (->> (store/list-jobs store)
396-
(partition-all 100)
397-
(map-indexed vector))]
397+
(partition-all 100)
398+
(map-indexed vector))]
398399
(log/infof "Page %d%s"
399400
page
400401
(with-out-str

src/cli/com/yetanalytics/xapipe/cli/options.clj

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,10 @@
5454
`boolean?
5555
:else
5656
`string?)
57-
arg-spec `#{
58-
~(format "--%s" long-command-name)
57+
arg-spec `#{~(format "--%s" long-command-name)
5958
~@(if short-command
6059
[short-command]
61-
[])
62-
}]
60+
[])}]
6361
`(list
6462
;; actual key spec
6563
(s/def ~spec-kw
@@ -251,7 +249,9 @@
251249
v))
252250
m)))]
253251
[nil "--source-username USERNAME" "Source LRS BASIC Auth username"]
254-
[nil "--source-password PASSWORD" "Source LRS BASIC Auth password"]]
252+
[nil "--source-password PASSWORD" "Source LRS BASIC Auth password"]
253+
[nil "--json-only" "Only operate in JSON statement mode for data transfer, ignoring Attachments/multipart (for compatibility issues)"
254+
:default false]]
255255
(concat
256256
(oauth-opts "source")
257257
(backoff-opts "source"))))

src/cli/com/yetanalytics/xapipe/main.clj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ Delete a Job:
4141
?json-file :json-file
4242
?json-out :json-out
4343
:as options} :options
44-
:keys [summary]} (opts/args->options args)
45-
]
44+
:keys [summary]} (opts/args->options args)]
4645
(if help?
4746
{:status 0
4847
:message (str
@@ -87,7 +86,7 @@ Delete a Job:
8786
job/upgrade-job
8887
(cond->
8988
;; If the user has requested force resume we clear
90-
force-resume?
89+
force-resume?
9190
(-> (update :state state/clear-errors)
9291
(update :state state/set-status :paused)))
9392
(job/reconfigure-job
@@ -146,6 +145,7 @@ Delete a Job:
146145
:message (format "Wrote job %s to %s"
147146
job-id ?json-out)})
148147
:else (do
148+
149149
(log/infof
150150
(if new?
151151
"Starting job %s"

src/lib/com/yetanalytics/xapipe.clj

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,7 @@
293293
target-client-opts]
294294
:or {conn-mgr-opts {}
295295
source-client-opts {}
296-
target-client-opts {}
297-
}} :client-opts
296+
target-client-opts {}}} :client-opts
298297
reporter :reporter
299298
:or {reporter (metrics/->NoopReporter)}}]
300299
(let [{:keys [id]
@@ -410,7 +409,7 @@
410409
{:state (-> state-before
411410
(cond->
412411
;; If a job is paused, re-init
413-
(= :paused (:status state-before))
412+
(= :paused (:status state-before))
414413
(state/set-status :init))
415414
(assoc :updated init-stamp))})
416415
states-chan
@@ -542,9 +541,7 @@
542541
(log/infof "store result: %s" result)))
543542
(def stop-fn stop))
544543

545-
(clojure.pprint/pprint (stop-fn))
546-
547-
)
544+
(clojure.pprint/pprint (stop-fn)))
548545

549546
(comment
550547
;; Same as above, but with redis as a store
@@ -605,8 +602,7 @@
605602
(let [result (a/<! store-result)]
606603
(log/infof "store result: %s" result)))
607604
(def stop-fn stop))
608-
(stop-fn)
609-
)
605+
(stop-fn))
610606

611607
(comment
612608
;; Use OAuth source LRS
@@ -647,6 +643,4 @@
647643
(log/infof "store result: %s" result)))
648644
(def stop-fn stop))
649645

650-
(clojure.pprint/pprint (stop-fn))
651-
652-
)
646+
(clojure.pprint/pprint (stop-fn)))

src/lib/com/yetanalytics/xapipe/client.clj

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
[clojure.spec.gen.alpha :as sgen]
99
[clojure.tools.logging :as log]
1010
[com.yetanalytics.xapipe.client.multipart-mixed :as multipart]
11+
[com.yetanalytics.xapipe.client.json-only :as json-only]
1112
[com.yetanalytics.xapipe.client.oauth :as oauth]
1213
[com.yetanalytics.xapipe.metrics :as metrics]
1314
[com.yetanalytics.xapipe.util :as u]
1415
[xapi-schema.spec :as xs]
15-
[xapi-schema.spec.resources :as xsr]
1616
[com.yetanalytics.xapipe.util.time :as t]
1717
[com.yetanalytics.xapipe.spec.common :as cspec])
1818
(:import [org.apache.http.impl.client CloseableHttpClient]
@@ -28,6 +28,16 @@
2828
status)
2929
(update resp :body slurp))))
3030

31+
;; Add json-only output coercion
32+
(defmethod client/coerce-response-body :json-only
33+
[req {:keys [status] :as resp}]
34+
(if (= 200 status)
35+
(json-only/parse-response req resp)
36+
(do
37+
(log/warnf "Received json response with non-200 status %d"
38+
status)
39+
(update resp :body slurp))))
40+
3141
;; Config needed for all requests
3242
(s/def ::url-base
3343
string?)
@@ -39,6 +49,9 @@
3949
(s/def ::username string?)
4050
(s/def ::password string?)
4151

52+
;; json-only mode support
53+
(s/def ::json-only boolean?)
54+
4255
;; token support
4356
(s/def ::token string?)
4457

@@ -48,6 +61,7 @@
4861
:opt-un [::xapi-prefix
4962
::username
5063
::password
64+
::json-only
5165
::token
5266
::oauth/oauth-params]))
5367

@@ -117,12 +131,12 @@
117131
:related_agents
118132
:format]))
119133

120-
(def get-request-base
134+
(defn get-request-base [json-only?]
121135
{:headers {"x-experience-api-version" "1.0.3"}
122136
:method :get
123-
:as :multipart/mixed
137+
:as (if json-only? :json-only :multipart/mixed)
124138
:query-params {:ascending true
125-
:attachments true}})
139+
:attachments (not json-only?)}})
126140

127141
(s/def ::more string?) ;; more link
128142

@@ -139,19 +153,20 @@
139153
username
140154
password
141155
token
142-
oauth-params]
156+
oauth-params
157+
json-only]
143158
:or {xapi-prefix "/xapi"}}
144159
get-params
145160
& [?more]]
146161
(cond-> (if (not-empty ?more)
147162
;; Using More Link
148-
(-> get-request-base
163+
(-> (get-request-base json-only)
149164
(assoc :url
150165
(format "%s%s"
151166
url-base
152167
?more))
153168
(dissoc :query-params))
154-
(-> get-request-base
169+
(-> (get-request-base json-only)
155170
(assoc :url
156171
(format "%s%s/statements"
157172
url-base
@@ -201,7 +216,7 @@
201216
(format "multipart/mixed; boundary=%s" boundary))
202217
(cond->
203218
;; support token if provided
204-
(not-empty token)
219+
(not-empty token)
205220
(assoc :oauth-token token)
206221
;; support basic auth if provided
207222
(and (not-empty username)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
(ns com.yetanalytics.xapipe.client.json-only
2+
"JSON-only statement response handling. Necessary over default JSON parsing
3+
to shim attachments which will not exist"
4+
(:require [clj-http.client :as http-client]
5+
[clojure.spec.alpha :as s]
6+
[com.yetanalytics.xapipe.client.multipart-mixed :as mm]))
7+
8+
(s/def ::body
9+
(s/keys :req-un
10+
[:xapi.statements.GET.response/statement-result
11+
::mm/attachments]))
12+
13+
(s/fdef parse-response
14+
:args (s/cat :response map?)
15+
:ret (s/keys :req-un [::body]))
16+
17+
(defn parse-response
18+
"Parse + close a json body"
19+
[req resp]
20+
(let [{:keys [body]} (http-client/coerce-json-body req resp false)]
21+
(assoc resp :body {:attachments []
22+
:statement-result
23+
(reduce-kv
24+
(fn [m k v]
25+
(assoc m (keyword k) v))
26+
{}
27+
body)})))

src/lib/com/yetanalytics/xapipe/job.clj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,9 @@
210210
(-> job
211211
(assoc :config config)
212212
(cond->
213-
(and
214-
(:pattern filter-cfg)
215-
(not (:pattern filter-state)))
213+
(and
214+
(:pattern filter-cfg)
215+
(not (:pattern filter-state)))
216216
(assoc-in [:state :filter :pattern] {})))
217217
(-> job
218218
(update :state

src/lib/com/yetanalytics/xapipe/job/config.clj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@
121121
:poll-interval poll-interval)
122122
(assoc-in [:get-params :limit] get-batch-size)
123123
(cond->
124-
?since (update-in [:get-params :since] t/normalize-stamp)
125-
?until (update-in [:get-params :until] t/normalize-stamp)))
124+
?since (update-in [:get-params :since] t/normalize-stamp)
125+
?until (update-in [:get-params :until] t/normalize-stamp)))
126126
:target
127127
(assoc target-config
128128
:batch-size post-batch-size

src/test/com/yetanalytics/xapipe/cli/options_test.clj

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
:source-poll-interval 1000,
5858
:get-params {},
5959
:source-backoff-budget 10000,
60+
:json-only false
6061
:source-backoff-max-attempt 10}
6162
nil
6263

@@ -66,6 +67,7 @@
6667
:source-poll-interval 1000,
6768
:get-params {},
6869
:source-backoff-budget 10000,
70+
:json-only false
6971
:source-backoff-max-attempt 10}
7072
["Failed to validate \"--source-batch-size 0\": Must be a positive integer"]
7173

@@ -80,6 +82,7 @@
8082
:get-params {:since "2021-10-26T17:51:06.530464Z"
8183
:related_agents true},
8284
:source-backoff-budget 10000,
85+
:json-only false
8386
:source-backoff-max-attempt 10}
8487
nil))
8588

@@ -129,6 +132,7 @@
129132
:target-backoff-budget 10000,
130133
:force-resume false,
131134
:redis-prefix "xapipe",
135+
:json-only false
132136
:storage :file,
133137
:get-buffer-size 10,
134138
:target-batch-size 50,
@@ -157,9 +161,10 @@
157161
:cleanup-buffer-size 50,
158162
:source
159163
{:request-config
160-
{:url-base "http://0.0.0.0:8080", :xapi-prefix "/xapi"},
164+
{:url-base "http://0.0.0.0:8080",
165+
:xapi-prefix "/xapi"},
161166
:batch-size 50,
162-
:backoff-opts {:budget 10000, :max-attempt 10},
167+
:backoff-opts {:budget 10000, :max-attempt 10}
163168
:poll-interval 1000,
164169
:get-params {:limit 50}},
165170
:target
@@ -215,6 +220,7 @@
215220
"--xapi-get-param" "format=exact"
216221
"--source-username" "foo"
217222
"--source-password" "bar"
223+
"--json-only"
218224
"--source-backoff-budget" "1"
219225
"--source-backoff-max-attempt" "1"
220226
"--source-backoff-j-range" "1"
@@ -275,6 +281,7 @@
275281
:force-resume true,
276282
:redis-prefix "my-xapipe",
277283
:source-backoff-j-range 1,
284+
:json-only true,
278285
:storage :file,
279286
:get-buffer-size 1,
280287
:target-backoff-initial 1,
@@ -291,15 +298,15 @@
291298
:metrics-reporter "prometheus"
292299
:prometheus-push-gateway "localhost:1234"
293300
:filter-ensure-paths [[["id"]]]
294-
:filter-match-paths [[[["verb"]["id"]]
301+
:filter-match-paths [[[["verb"] ["id"]]
295302
"http://example.com/verb"]
296303
[[["actor"]] {"mbox" "mailto:bob@example.com"
297304
"objectType" "Agent"}]]
298305
:filter-concept-profile-urls ["http://example.org/profile.jsonld"]
299306
:filter-concept-types ["Verb"]
300-
:filter-activity-type-ids [ "http://example.org/profile.jsonld#activity-type"]
307+
:filter-activity-type-ids ["http://example.org/profile.jsonld#activity-type"]
301308
:filter-verb-ids ["http://example.org/profile.jsonld#verb"]
302-
:filter-attachment-usage-types [ "http://example.org/profile.jsonld#aut"]
309+
:filter-attachment-usage-types ["http://example.org/profile.jsonld#aut"]
303310
:cleanup-buffer-size 1}
304311
[])
305312
(testing "no defaults"

0 commit comments

Comments
 (0)