-
Notifications
You must be signed in to change notification settings - Fork 0
/
ws-chan.coffee
91 lines (70 loc) · 2.14 KB
/
ws-chan.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
websocket = require 'websocket-stream'
backoff = require 'backoff'
Stream = require 'stream'
through = (fn) ->
cls = class extends Stream.Transform
_transform: (chunk, encoding, cb) ->
try
cb(null, if fn? then fn(chunk) else chunk)
catch e
cb(e, null)
new cls(objectMode: true)
class Channel
constructor: (uri, options) ->
this.uri = uri
this.options = options
this.sock = undefined
this.preventBackoff = false
this.backoffState = options.backoff or backoff.exponential(options)
if this.backoffState?
this.backoffState.failAfter(options.failAfter) if options.failAfter?
this.backoffState.on 'backoff', this.onBackoff.bind(this)
this.backoffState.on 'ready', this.onBackoffReady.bind(this)
this.backoffState.on 'fail', this.onBackoffFail.bind(this)
this.in = through()
this.out = through()
start: ->
this.sock = websocket(this.uri)
this.sock.on 'open', this.onOpen.bind(this)
this.sock.on 'end', this.onEnd.bind(this)
this.sock.on 'error', this.onError.bind(this)
this.sock
.pipe(through(JSON.parse))
.pipe(this.in, end: false)
this.out
.pipe(through(JSON.stringify), end: false)
.pipe(this.sock)
stop: ->
this.preventBackoff = true
this.sock.end()
backoff: ->
if this.backoffState? and not this.preventBackoff
this.backoffState.backoff()
resetBackoff: ->
if this.backoffState?
this.backoffState.reset()
cleanup: ->
this.out.unpipe()
log: (msg) ->
console.log "channel: #{msg}"
onOpen: ->
this.log "connection established"
this.resetBackoff()
onEnd: ->
this.log "connection terminated"
this.cleanup()
this.backoff()
onError: (e) ->
this.log "error #{e}"
this.cleanup()
this.backoff()
onBackoff: (number, delay) ->
this.log "next connection attempt in #{delay}ms"
onBackoffReady: ->
this.log "trying to re-establish connection"
this.start()
onBackoffFail: ->
this.log "out of attempts to re-establish connection"
exports = (uri, options) -> new Channel(uri, options)
exports.channel = exports
exports.Channel = Channel