开发者

How can I get the Ganymed SSH library to tail a file (in Clojure)?

The following code never manages to tail a file. It simply hangs waiting for reader input. Has anyone tried anything similar?

(def output     (ref [] ))

(import 'ch.ethz.ssh2.Connection)
(import 'ch.ethz.ssh2.Session)
(import 'ch.ethz.ssh2.StreamGobbler)
(import 'java.lang.开发者_如何学JAVAStringBuilder)
(import 'java.io.InputStream)
(import 'java.io.BufferedReader)
(import 'java.io.InputStreamReader)

(let [connection  (new Connection  "hostname")]
  (. connection connect)
  (let [ok         (. connection authenticateWithPassword "username"  "password" )
        session    (. connection openSession )]

    (. session execCommand "tail -f filename.txt")

    (let [sb      (StringBuilder.)
          stdout  (StreamGobbler. (. session getStdout))
          br      (BufferedReader. (InputStreamReader. stdout))
         ]

      (future (loop [line2 (. br readLine)] 
        (if (= line2 nil)  
          nil 
          (do 
            (dosync (ref-set output (conj @output line2)))
            (recur (. br readLine))))
          )
      )
    )
  )
)


I agree with Arthur. Its not clear to me how this would work in practice since the remote command will never return / finish. Try the following as an example:

> (defn never-returns []
  (while true
    (do (Thread/sleep 2000)
    (println "i'm never going to finish")))
    "done")
> (def x (future (never-returns)))
> (@x)
i'm never going to finish
i'm never going to finish
...

I think a possibly better approach would to take the threading out your client while providing a means to get access to the tail of the file asynchronously. For example, you might consider using netcat to send the output of tail -f to a socket and then periodically read from that socket in your client to get the file output. Something like this on the remote side:

tail -f filename.txt | nc -l 12000

Then in your clojure code:

(import '(java.net ServerSocket Socket))     
(def client (java.net.Socket. "hostname" 12000)) 
(def r (java.io.BufferedReader. (java.io.InputStreamReader. (.getInputStream client)))) 
(println (.readLine r))  ; or capture the output

Something like that. Hope this helps.


I'm not sure a future is the best construct for starting your work thread because it blocks on deref until the work is finished

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜