|
1 | 1 | ;
|
2 | 2 | ; Copyright 2013 Netflix, Inc.
|
3 |
| -; |
| 3 | +; |
4 | 4 | ; Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | ; you may not use this file except in compliance with the License.
|
6 | 6 | ; You may obtain a copy of the License at
|
7 | 7 | ;
|
8 | 8 | ; http://www.apache.org/licenses/LICENSE-2.0
|
9 |
| -; |
| 9 | +; |
10 | 10 | ; Unless required by applicable law or agreed to in writing, software
|
11 | 11 | ; distributed under the License is distributed on an "AS IS" BASIS,
|
12 | 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
58 | 58 | ; Custom Observable
|
59 | 59 | ; --------------------------------------------------
|
60 | 60 |
|
61 |
| -(defn customObservableBlocking [] |
62 |
| - "This example shows a custom Observable that blocks |
63 |
| - when subscribed to (does not spawn an extra thread). |
| 61 | +(defn customObservable |
| 62 | + "This example shows a custom Observable. Note the |
| 63 | + .isUnsubscribed check so that it can be stopped early. |
64 | 64 |
|
65 | 65 | returns Observable<String>"
|
| 66 | + [] |
66 | 67 | (Observable/create
|
67 |
| - (rx/fn [observer] |
68 |
| - (doseq [x (range 50)] (-> observer (.onNext (str "value_" x)))) |
| 68 | + (rx/action [^rx.Subscriber s] |
| 69 | + (loop [x (range 50)] |
| 70 | + (when (and (not (.isUnsubscribed s)) x) |
| 71 | + ; TODO |
| 72 | + (println "HERE " (.isUnsubscribed s) (first x)) |
| 73 | + (-> s (.onNext (str "value_" (first x)))) |
| 74 | + (recur (next x)))) |
69 | 75 | ; after sending all values we complete the sequence
|
70 |
| - (-> observer .onCompleted) |
71 |
| - ; return a NoOpSubsription since this blocks and thus |
72 |
| - ; can't be unsubscribed from |
73 |
| - (Subscriptions/empty)))) |
| 76 | + (-> s .onCompleted)))) |
74 | 77 |
|
75 | 78 | ; To see output
|
76 | 79 | (comment
|
77 |
| - (.subscribe (customObservableBlocking) (rx/action* println))) |
78 |
| - |
79 |
| -(defn customObservableNonBlocking [] |
80 |
| - "This example shows a custom Observable that does not block |
81 |
| - when subscribed to as it spawns a separate thread. |
82 |
| -
|
83 |
| - returns Observable<String>" |
84 |
| - (Observable/create |
85 |
| - (rx/fn [observer] |
86 |
| - (let [f (future |
87 |
| - (doseq [x (range 50)] |
88 |
| - (-> observer (.onNext (str "anotherValue_" x)))) |
89 |
| - ; after sending all values we complete the sequence |
90 |
| - (-> observer .onCompleted))] |
91 |
| - ; return a subscription that cancels the future |
92 |
| - (Subscriptions/create (rx/action [] (future-cancel f))))))) |
93 |
| - |
94 |
| -; To see output |
95 |
| -(comment |
96 |
| - (.subscribe (customObservableNonBlocking) (rx/action* println))) |
97 |
| - |
| 80 | + (.subscribe (customObservable) (rx/action* println))) |
98 | 81 |
|
99 | 82 | ; --------------------------------------------------
|
100 | 83 | ; Composition - Simple
|
101 | 84 | ; --------------------------------------------------
|
102 | 85 |
|
103 |
| -(defn simpleComposition [] |
104 |
| - "Asynchronously calls 'customObservableNonBlocking' and defines |
| 86 | +(defn simpleComposition |
| 87 | + "Calls 'customObservable' and defines |
105 | 88 | a chain of operators to apply to the callback sequence."
|
| 89 | + [] |
106 | 90 | (->
|
107 |
| - (customObservableNonBlocking) |
| 91 | + (customObservable) |
108 | 92 | (.skip 10)
|
109 | 93 | (.take 5)
|
110 | 94 | (.map (rx/fn [v] (str v "_transformed")))
|
|
119 | 103 | ; Composition - Multiple async calls combined
|
120 | 104 | ; --------------------------------------------------
|
121 | 105 |
|
122 |
| -(defn getUser [userId] |
| 106 | +(defn getUser |
123 | 107 | "Asynchronously fetch user data
|
124 | 108 |
|
125 | 109 | return Observable<Map>"
|
| 110 | + [userId] |
126 | 111 | (Observable/create
|
127 |
| - (rx/fn [observer] |
| 112 | + (rx/action [^rx.Subscriber s] |
128 | 113 | (let [f (future
|
129 | 114 | (try
|
130 | 115 | ; simulate fetching user data via network service call with latency
|
131 | 116 | (Thread/sleep 60)
|
132 |
| - (-> observer (.onNext {:user-id userId |
133 |
| - :name "Sam Harris" |
134 |
| - :preferred-language (if (= 0 (rand-int 2)) "en-us" "es-us") })) |
135 |
| - (-> observer .onCompleted) |
136 |
| - (catch Exception e (-> observer (.onError e))))) ] |
| 117 | + (-> s (.onNext {:user-id userId |
| 118 | + :name "Sam Harris" |
| 119 | + :preferred-language (if (= 0 (rand-int 2)) "en-us" "es-us") })) |
| 120 | + (-> s .onCompleted) |
| 121 | + (catch Exception e |
| 122 | + (-> s (.onError e))))) ] |
137 | 123 | ; a subscription that cancels the future if unsubscribed
|
138 |
| - (Subscriptions/create (rx/action [] (future-cancel f))))))) |
| 124 | + (.add s (Subscriptions/create (rx/action [] (future-cancel f)))))))) |
139 | 125 |
|
140 |
| -(defn getVideoBookmark [userId, videoId] |
| 126 | +(defn getVideoBookmark |
141 | 127 | "Asynchronously fetch bookmark for video
|
142 | 128 |
|
143 | 129 | return Observable<Integer>"
|
| 130 | + [userId, videoId] |
144 | 131 | (Observable/create
|
145 |
| - (rx/fn [observer] |
| 132 | + (rx/action [^rx.Subscriber s] |
146 | 133 | (let [f (future
|
147 | 134 | (try
|
148 | 135 | ; simulate fetching user data via network service call with latency
|
149 | 136 | (Thread/sleep 20)
|
150 |
| - (-> observer (.onNext {:video-id videoId |
151 |
| - ; 50/50 chance of giving back position 0 or 0-2500 |
152 |
| - :position (if (= 0 (rand-int 2)) 0 (rand-int 2500))})) |
153 |
| - (-> observer .onCompleted) |
154 |
| - (catch Exception e (-> observer (.onError e)))))] |
| 137 | + (-> s (.onNext {:video-id videoId |
| 138 | + ; 50/50 chance of giving back position 0 or 0-2500 |
| 139 | + :position (if (= 0 (rand-int 2)) 0 (rand-int 2500))})) |
| 140 | + (-> s .onCompleted) |
| 141 | + (catch Exception e |
| 142 | + (-> s (.onError e)))))] |
155 | 143 | ; a subscription that cancels the future if unsubscribed
|
156 |
| - (Subscriptions/create (rx/action [] (future-cancel f))))))) |
| 144 | + (.add s (Subscriptions/create (rx/action [] (future-cancel f)))))))) |
157 | 145 |
|
158 |
| -(defn getVideoMetadata [videoId, preferredLanguage] |
| 146 | +(defn getVideoMetadata |
159 | 147 | "Asynchronously fetch movie metadata for a given language
|
160 | 148 | return Observable<Map>"
|
| 149 | + [videoId, preferredLanguage] |
161 | 150 | (Observable/create
|
162 |
| - (rx/fn [observer] |
| 151 | + (rx/action [^rx.Subscriber s] |
163 | 152 | (let [f (future
|
| 153 | + (println "getVideoMetadata " videoId) |
164 | 154 | (try
|
165 | 155 | ; simulate fetching video data via network service call with latency
|
166 | 156 | (Thread/sleep 50)
|
167 | 157 | ; contrived metadata for en-us or es-us
|
168 | 158 | (if (= "en-us" preferredLanguage)
|
169 |
| - (-> observer (.onNext {:video-id videoId |
| 159 | + (-> s (.onNext {:video-id videoId |
170 | 160 | :title "House of Cards: Episode 1"
|
171 | 161 | :director "David Fincher"
|
172 | 162 | :duration 3365})))
|
173 | 163 | (if (= "es-us" preferredLanguage)
|
174 |
| - (-> observer (.onNext {:video-id videoId |
| 164 | + (-> s (.onNext {:video-id videoId |
175 | 165 | :title "Cámara de Tarjetas: Episodio 1"
|
176 | 166 | :director "David Fincher"
|
177 | 167 | :duration 3365})))
|
178 |
| - (-> observer .onCompleted) |
179 |
| - (catch Exception e (-> observer (.onError e))))) ] |
| 168 | + (-> s .onCompleted) |
| 169 | + (catch Exception e |
| 170 | + (-> s (.onError e))))) ] |
180 | 171 | ; a subscription that cancels the future if unsubscribed
|
181 |
| - (Subscriptions/create (rx/action [] (future-cancel f))))))) |
| 172 | + (.add s (Subscriptions/create (rx/action [] (future-cancel f)))))))) |
182 | 173 |
|
183 | 174 |
|
184 | 175 | (defn getVideoForUser [userId videoId]
|
|
188 | 179 | - user data
|
189 | 180 | return Observable<Map>"
|
190 | 181 | (let [user-observable (-> (getUser userId)
|
191 |
| - (.map (rx/fn [user] {:user-name (:name user) |
192 |
| - :language (:preferred-language user)}))) |
| 182 | + (.map (rx/fn [user] |
| 183 | + {:user-name (:name user) |
| 184 | + :language (:preferred-language user)}))) |
193 | 185 | bookmark-observable (-> (getVideoBookmark userId videoId)
|
194 | 186 | (.map (rx/fn [bookmark] {:viewed-position (:position bookmark)})))
|
195 | 187 | ; getVideoMetadata requires :language from user-observable so nest inside map function
|
|
218 | 210 | ;
|
219 | 211 | (comment
|
220 | 212 | (-> (getVideoForUser 12345 78965)
|
221 |
| - (.subscribe |
222 |
| - (rx/action [x] (println "--- Object ---\n" x)) |
223 |
| - (rx/action [e] (println "--- Error ---\n" e)) |
224 |
| - (rx/action [] (println "--- Completed ---"))))) |
| 213 | + (.toBlockingObservable) |
| 214 | + .single)) |
225 | 215 |
|
0 commit comments