簡體   English   中英

在clojure中處理來自http服務器的消息流

[英]Processing a stream of messages from a http server in clojure

我正在尋找一種慣用的方法來做到以下幾點。 我有一個http服務器,在特定的GET請求上響應消息流。 現在,由於此消息是非終止的,當我使用clj-http / get時,調用會永遠阻塞(我正在使用LightTable)。 我想建立一個回調或core.async樣式的通道來對消息進行一些操作。即使將流寫入文件對我來說也是一個很好的第一步。 有什么指針嗎? 這是電話:

    (require '[clj-http.client :as client])

    (def url "http://hopey.netfonds.no/tradedump.php?date=20150508&paper=AAPL.O&csv_format=txt")

    (client/get url)

日期必須更改為今天的數據流日期。 謝謝!

要將流寫入文件,一個簡單的方法是使用clojure.java.io/copy (它接受輸入流,例如(:body (client/get some-url {:as :stream}))返回的輸入流(:body (client/get some-url {:as :stream}))和輸出流以及從一個到另一個的副本)。 就像是

(ns http-stream
  (:require [clj-http.client :as client]
            [clojure.java.io :as io]))


(with-open [in-stream (:body (client/get "http://hopey.netfonds.no/tradedump.php?date=20150508&paper=AAPL.O&csv_format=txt" {:as :stream}))
            out-stream (->> "streamoutput.txt"
                        io/as-file
                        io/output-stream)]
  (io/copy in-stream out-stream))

這讓我在幾秒鍾內獲得了數千行標簽分隔值。 現在,要在行級別使用core.async處理它們,我們可能希望使用readerline-seq更多地處理流:

(ns http-stream
  (:require [clj-http.client :as client]
            [clojure.core.async :as async]
            [clojure.java.io :as io]
            [clojure.string :as str]))


(defn trades-chan
  "Open the URL as a stream of trades information. Return a channel of the trades, represented as strings."
  [dump-url]
  (let[lines (-> dump-url
                 (client/get {:as :stream})
                 :body
                 io/reader 
                 line-seq) ];;A lazy seq of each line in the stream.
    (async/to-chan lines))) ;;Return a channel which outputs the lines

;;Example: Print the first 250 lines.
(let [a (trades-chan "http://hopey.netfonds.no/tradedump.php?date=20150508&paper=AAPL.O&csv_format=txt")]
  (async/go-loop [takes 250]
                 (when (< 0 takes) 
                   (println (async/<! a))
                   (recur (dec takes)))))

現在,有了這個,你很大程度上已經啟動了,但是我注意到流總是以對列的描述開始

time    price   quantity    board   source  buyer   seller  initiator

你可以用它作為改善一點點的機會。 特別是,這足以為交易建立一個傳感器的信息,可以將交易變成更方便的格式,如地圖。 此外,我們可能想要一種方法來停止使用元素並在某個時候關閉連接。 我自己並不熟悉core.async,但這似乎有效:

(defn trades-chan
  "Open the URL as a tab-separated values stream of trades. 
  Returns a core.async channel of the trades, represented as maps.
  Closes the HTTP stream on channel close!"
  [dump-url]
  (let[stream (-> dump-url
                 (client/get {:as :stream})
                 :body)
       lines  (-> stream
                 io/reader 
                 line-seq) ;;A lazy seq of each line in the stream.
       fields (map keyword (str/split (first lines) #"\t")) ;; (:time :price :quantity ...
       transducer (map (comp #(zipmap fields %) #(str/split % #"\t")))  ;;A transducer that splits strings on tab and makes them into maps with keys from fields
       output-chan (async/chan 50 transducer)]
    (async/go-loop [my-lines (drop 1 lines)]
                   (if (async/>! output-chan (first my-lines))   ;;If we managed to put
                     (recur (rest my-lines))         ;;then the chan is not closed. Recur with the rest of the lines.
                     (.close stream)))               ;;else close the HTTP stream.
    output-chan))

我認為user1571406的答案是合理的,並且給出了將clj-httpcore.async結合起來的一個很好的介紹。 但是,如果您不堅持使用clj-http ,我強烈推薦使用http-kit庫,它更適用於異步響應處理。 使用http-kit ,您可以按如下方式編寫回叫。

user> (require '[clojure.java.io :as io]
               '[org.httpkit.client :as h])
nil

user> (def url "http://hopey.netfonds.no/tradedump.php?date=20150508&paper=AAPL.O&csv_format=txt")
#'user/url

user> (h/get url {:as :stream}
             (fn [{:keys [status body]}]
               (if (= status 200)
                 (with-open [out (io/output-stream "/tmp/output.txt")]
                   (io/copy body out)))))
#<core$promise$reify__6363@373b22df: :pending>

最后一個h/get函數調用立即返回,其回調函數fn異步將響應體寫入文件/tmp/output.txt

(ns asyncfun.core
  (:require [clojure.core.async :as async
             :refer [<! >!! go chan]]
            [clj-http.client :as client]))

(def url "http://hopey.netfonds.no/tradedump.php?date=20150508&paper=AAPL.O&csv_format=txt")

(def out-chan (chan))
(go (println (<! out-chan)))
  (>!! out-chan (client/get url))

我把這段代碼放在一起幾分鍾。 我認為core.async就是你要找的東西。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM