Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions elm.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
"direct": {
"elm/browser": "1.0.0",
"elm/core": "1.0.0",
"elm/html": "1.0.0"
"elm/html": "1.0.0",
"elm/json": "1.0.0"
},
"indirect": {
"elm/json": "1.0.0",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.2"
Expand Down
128 changes: 128 additions & 0 deletions public/WebSocketHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// WebSocket port handler

/* Install it with:

WebSocketHandler.subscribe(cmdPort, subPort)

Supports three messages, through the cmdPort:

{ tag: 'open', args: { key: <string>, message: <url> } }
{ tag: 'close', args: { key: <string> } }
{ tag: 'send', args: { key: <string>, message: <string> } }

The key for the 'open' command may be omitted, and the url will be used as key.

Sends back the following messages:

{ tag: 'error', args: { key: <string>, message: <string> } }
{ tag: 'connected', args: { key: <string>, message: <string> } }
{ tag: 'received', args: { key: <string>, message: <string> } }
{ tag: 'closed', args: { key: <string>, message: <string> } }

*/

var WebSocketHandler = {};

(function() {
var sockets = {};
var send;

WebSocketHandler.subscribe = subscribe;
WebSocketHandler.dispatch = dispatch; // for debugging

function subscribe(cmdPort, subPort) {
if (subPort) {
send = subPort.send;
} else {
// Debugging
send = function(v) { console.log(v); }
}
if (cmdPort) {
cmdPort.subscribe(function(command) {
if (typeof(command) == 'object') {
var tag = command.tag;
var args = command.args;
dispatch(tag, args);
}
});
}
}

function returnObject(tag, key, message) {
send({tag: tag, args: { key: key, message: message} });
}

function returnError(key, err) {
returnObject('error', key, err);
}

function dispatch(tag, args) {
if (tag == 'open') {
doOpen(args.key, args.message);
} else if (tag == 'close') {
doClose(args.key);
} else if (tag == 'send') {
doSend(args.key, args.message);
} else {
returnError('', 'Unknown tag: ' + tag);
}
}

function doOpen(key, url) {
if (!key) key = url;
if (sockets[key]) {
return returnError(key, 'Socket already open.');
}
try {
var socket = new WebSocket(url);
sockets[key] = socket;
}
catch(err) {
// The old code returned BadSecurity if err.name was 'SecurityError'
// or BadArgs otherwise.
return returnError(key, "open: can't create socket for URL: " + url + ', ' + err.name);
}
socket.addEventListener('open', function(event) {
console.log('Socket connected for URL: ' + url);
returnObject('connected', key, 'Socket connected for url: ' + url);
});
socket.addEventListener('message', function(event) {
var message = event.data;
console.log('Received for "' + key + '": ' + message);
returnObject('received', key, message);
});
socket.addEventListener('close', function(event) {
console.log('"' + key + '" closed');
delete sockets[key]; // for open errors
returnObject('closed', key, 'Socket closed unexpectedly.');
});
}

function doSend(key, message) {
var socket = sockets[key];
if (!socket) {
returnError(key, 'send, socket not open.');
}
console.log('Sending message for key: ' + key + ', ' + message);
try {
socket.send(message);
} catch(err) {
returnError(key, 'Send error: ' + err.name);
}
}

function doClose(key) {
var socket = sockets[key];
if (!socket) {
returnError(key, 'close, socket not open.');
}
try {
delete sockets[key];
socket.close();
returnObject('closed', key, 'Socket closed.');
} catch(err) {
returnError(key, 'Close error: ' + err.name);
}
}

})();
4 changes: 3 additions & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Live Polls</title>
<script src="app.js"></script>
<script src="WebSocketHandler.js"></script>
</head>
<body>
<div id="app"></div>
<script>
const app = Elm.Main.init({flags: "The wiring is correct.", node: document.querySelector('#app')})
WebSocketHandler.subscribe(app.ports.cmdPort, app.ports.subPort);
</script>
</body>
</html>
</html>
31 changes: 27 additions & 4 deletions src/Main.elm
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
module Main exposing (main)
port module Main exposing (main)

import Browser
import Html exposing (Html, text)
import Json.Decode as JD exposing (Decoder)
import Json.Encode as JE exposing (Value)



{--The view function takes the model and represents it in virtual dom which
can emit messagfes (This is what "Html Msg" means) --}
can emit messages (This is what "Html Msg" means) --}


view : Model -> Html Msg
Expand Down Expand Up @@ -34,6 +36,8 @@ We can define it in terms of built in types, or just our own key words --}

type Msg
= DidNothing
| Send Value
| Receive Value



Expand Down Expand Up @@ -64,7 +68,16 @@ runtime) that need to be run (Like sending an Http request) --}

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
( initModel "", Cmd.none )
let
cmd =
case msg of
Send value ->
cmdPort value

_ ->
Cmd.none
in
( initModel "", cmd )



Expand All @@ -75,7 +88,7 @@ stuff from Javascript — these can happen during the lifetime of the app --}

subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
subPort Receive



Expand All @@ -92,3 +105,13 @@ main =
, update = update
, subscriptions = subscriptions
}



{--Here are the ports for communicating with the JavaScript in public/WebSocket.js --}


port cmdPort : Value -> Cmd msg


port subPort : (Value -> msg) -> Sub msg