简体   繁体   English

core.async 重新连接 websocket

[英]core.async reconnecting websocket

core.async noob here, but trying to learn by building an automatically reconnecting websocket. core.async noob here,但尝试通过构建自动重新连接的 websocket 来学习。 The idea is that the socket is abstracted away so that anyone using it does not need to worry about whether or not it's connected and can just put messages on a channel.这个想法是将套接字抽象出来,这样任何使用它的人都不必担心它是否已连接,只需将消息放在通道上即可。 If the socket is connected, the messages are read from the channel immediately and sent.如果套接字已连接,则立即从通道读取消息并发送。 If the socket is not currently connected, it repeatedly tries to reconnect and waits to send all pending messages once a connection has been established.如果套接字当前未连接,则它会反复尝试重新连接,并在建立连接后等待发送所有挂起的消息。

This is what I have so far:这是我到目前为止:

(ns frontend.socket
  (:require-macros [cljs.core.async.macros :as asyncm :refer [go]])
  (:require [cljs.core.async :as async :refer [<! >! chan timeout]]))

(def endpoint "ws://localhost:8080")
(def socket (atom nil))
(def open (chan))
(def in (chan))
(def out (chan))
(def error (chan))
(def close (chan))

(defn open? []
  (= (.-readyState @socket) (.-OPEN @socket)))

(defn event>chan
  "Given a core.async channel, returns a
  function which takes an event and feeds
  it into the formerly given channel."
  [channel]
  (fn [e]
    (go (>! channel e))))

(defn connect
  "Opens a websocket, stores it in the socket
  atom, and feeds the socket's events into
  the corresponding channels."
  []
  (let [s (js/WebSocket. endpoint)]
    (reset! socket s)
    (set! s.onopen    (event>chan open))
    (set! s.onmessage (event>chan in))
    (set! s.onerror   (event>chan error))
    (set! s.onclose   (event>chan close))))

(defn init
  "This is the entry point from outside this
  namespace. Eagerly connects and then, if
  ever disconnected, attempts to reconnect
  every second. Also takes messages from
  the out channel and sends them through
  the socket."
  []
  (go
    (while true
      (connect)
      (<! close)
      (<! (timeout 1000))))
  (go
    (while true
      (let [m (<! out)]
        (when (or (open?) (<! open))
          (.send @socket m))))))

The reconnect logic seems to work fine, but I'm running into an issue trying to send messages after a socket has closed.重新连接逻辑似乎工作正常,但我遇到了一个问题,试图在套接字关闭后发送消息。 In the last few lines, I check that before sending a message, the socket is open or wait for it to open.在最后几行中,我在发送消息之前检查套接字是否打开或等待它打开。 The problem is that if no message was sent while a socket was previously open, then closed, and then a message is sent, there is still something sitting on the open channel, and so the message will get sent regardless.问题是,如果在套接字先前打开时没有发送消息,然后关闭,然后发送一条消息,那么仍然有一些东西坐在开放的通道上,因此无论如何都会发送消息。 So the open channel can get "stale", as it were.因此,开放渠道可能会变得“陈旧”,就像它一样。

I thought about taking from the open channel whenever the socket closes, but that just reverses the problem: then the open channel may miss values when I do need them, and messages are not sent upon reconnect.我想过每当套接字关闭时从开放通道中获取,但这只是扭转了问题:然后开放通道可能会在我确实需要它们时丢失值,并且在重新连接时不会发送消息。

What am I doing wrong here?我在这里做错了什么?

This was the wrong approach because channels will wait to be consumed.这是错误的方法,因为通道将等待被使用。 I needed to use pub/sub instead: https://github.com/clojure/core.async/wiki/Pub-Sub/549da1843c7bbe6009e9904eed49f91000d8ce2c我需要使用 pub/sub 代替: https : //github.com/clojure/core.async/wiki/Pub-Sub/549da1843c7bbe6009e9904eed49f91000d8ce2c

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM