Created
December 12, 2018 18:30
-
-
Save ccapndave/72381b45f01e6d798049e6375b475297 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
port module WebSocket exposing (listen, send, open) | |
open : String -> Cmd msg | |
open url = | |
wsOpen { url = url } | |
send : String -> String -> Cmd msg | |
send url message = | |
wsSend { url = url, message = message } | |
listen : String -> (String -> msg) -> msg -> msg -> Sub msg | |
listen urlToListenTo onMessageTagger disconnected noop = | |
Sub.batch | |
[ wsOnMessage <| | |
\{ url, message } -> | |
if url == urlToListenTo then | |
onMessageTagger message | |
else | |
noop | |
, wsOnClose <| | |
\{ url } -> | |
if url == urlToListenTo then | |
disconnected | |
else | |
noop | |
] | |
port wsOpen : { url : String } -> Cmd msg | |
port wsSend : { url : String, message : String } -> Cmd msg | |
port wsOnMessage : ({ url : String, message : String } -> msg) -> Sub msg | |
port wsOnClose : ({ url : String } -> msg) -> Sub msg |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface IncomingPort<T> { | |
subscribe: (callback: (value: T) => void) => void; | |
unsubscribe: (callback: (value: T) => void) => void; | |
} | |
interface OutgoingPort<T> { | |
send: (value: T) => void; | |
} | |
interface Ports { | |
wsOpen: IncomingPort<{ url: string }> | |
wsSend: IncomingPort<{ url: string, message: string }> | |
wsOnMessage: OutgoingPort<{ url: string, message: string }> | |
wsOnClose: OutgoingPort<{ url: string }> | |
} | |
export function configureWebsocketClient(ports: Ports) { | |
let webSockets = new Map(); | |
if (ports.wsOpen) { | |
ports.wsOpen.subscribe(({ url }) => { | |
console.log("open ws - " + url); | |
open(url); | |
}); | |
} | |
if (ports.wsSend) { | |
ports.wsSend.subscribe(({ url, message }) => { | |
console.log("send - " + url + ": " + message); | |
open(url) | |
.then(webSocket => webSocket.send(message)) | |
.catch(err => { | |
console.error(err.toString()); | |
}) | |
}); | |
} | |
function open(url: string): Promise<WebSocket> { | |
if (!webSockets.has(url)) { | |
return new Promise((resolve, reject) => { | |
try { | |
const webSocket = new WebSocket(url); | |
webSocket.addEventListener("open", _ => resolve(webSocket)); | |
webSocket.addEventListener("message", ({ data }) => onMessage(url, data)); | |
webSocket.addEventListener("close", _ => onClose(url)); | |
} catch (err) { | |
console.error(err.toString()); | |
reject(err); | |
} | |
}); | |
} else { | |
return Promise.resolve(webSockets.get(url)) | |
} | |
} | |
function onMessage(url: string, data: string) { | |
ports.wsOnMessage.send({ url, message: data }); | |
} | |
function onClose(url: string) { | |
ports.wsOnClose.send({ url }); | |
attemptReconnect(url); | |
} | |
function attemptReconnect(url: string, attempt: number = 0) { | |
let delay = 10 * Math.pow(2, attempt) * 1000; | |
setTimeout(() => { | |
open(url).catch(_ => attemptReconnect(url, attempt + 1)); | |
}, delay) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment