GithubHelp home page GithubHelp logo

elm-socketio's Introduction

Socket.io for Elm

This library has not and will not be updated for recent versions of Elm.

This library provides Elm code with realtime push-based two-way communication with a server using socket.io. It works quite well for the most common use case, a stable connection to a server that you wrote in Node.js.

That said, error handling is limited to setting options up front and reading the connection status. Joining rooms, an inherently impure action, is not supported. If you need to dynamically connect and disconnect, or interface with an API you don't control, use JavaScript.

Note that vanilla websockets (i.e. servers other than Socket.io) are not supported. You should use ports and the JS Websocket API.

For documentation, see src/SocketIO.elm. Supports Elm 0.16 and Socket.io 1.4.4. If this version is causing problems, open an issue to bump to the latest version.

Examples

For each example, a working Elm client and Node server are provided. You will need to cd examples to start. This first time you do this, you will also need to npm install to get socket.io for the server. Then in separate terminals, run node <example-name>/server.js and elm reactor, then open your browser and navigate to the example as you normally would with the reactor.

Numbers

In this example, client and server exchange a number, incrementing it each time. The server sees odd numbers and the client sees even numbers.

This example is big enough to show all the useful features of the library, but no bigger. There is also a version using The Elm Architecture and elm-effects (with the same server).

Chat

The main example: a realtime chat program. You can test it out yourself with multiple browser tabs.

Chat is divided into five modules. Protocol most of the knowledge shared with the server and a few other common functions. Login is the login page, Post is the text field and submit button, and View makes the messages look pretty. Finally, ChatClient pulls it all together and does the I/O.

Connected

A very simple example to show that you can obtain a signal about the connection state and use this to render information in the UI.

elm-socketio's People

Contributors

danneu avatar ktorz avatar mgold avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

elm-socketio's Issues

File path is too long on windows

When downloading the package on windows, I get the error message that the file path is too long. The problem is in example/node_modules/socket.io.

It would be nice if you could remove that example or just put it in another package (elm-socketio-example)

Support for elm 0.17

I got the "Unable to find a set of packages that will work with your constraints." error when trying to install this package into an existing 0.17 project.
Just tried to port this package using this guide, but then ran into more difficult porting issues related to native JS code. After some research I found out about the somewhat vague situation about Native code here and here. Being a complete beginner to elm, I'm somewhat scared away now.
Do you see a point in porting this lib to 0.17? What are your thoughts on this?

Work with non-socket.io websocket servers

I'd like to be able to use this library to talk to pre-existing ws/wss servers that do not use socket.io.

I know you've got socket.io right in the name of the library, but I think you've made statements that this library supports standard websockets. If you meant that the client can use the standard websocket API but the server must still be running socket.io then okay, but I don't quite know why anyone would bother.

Using your Example/websocket server against a non socket.io based websocket server results in a continuous stream of attempts at accessing http://localhost:8001/socket.io/?EIO=3&transport=polling&t=1451837114463-40 which does not exist of course.

Here's a websocket server using https://github.com/websockets/ws, derived from one of their examples, that illustrates the problem:

var WebSocketServer = require('ws').Server
  , wss = new WebSocketServer({ port: 8001 });

wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    console.log('received: %s', message);
    ws.send('echoing: ' + message); // this line is not in the elm-socketio provided server.js file
  });

  ws.send('Hello I am a server using Websockets');
});

examples/numbers/Example.elm does not compile

When I tried to compile examples/numbers/Example.elm. I have got this error:

Detected errors in 1 module.

ERRORS in examples/numbers/Example.elm

-- TYPE MISMATCH ---------------------------------- examples/numbers/Example.elm

The 2nd argument to function emit has an unexpected type.

32| SocketIO.emit eventName (i+1)
^^^
As I infer the type of values flowing through your program, I see a conflict
between these two types:

String

number

-- TYPE MISMATCH ---------------------------------- examples/numbers/Example.elm

The 2nd argument to function emit has an unexpected type.

16| SocketIO.emit eventName 0
^
As I infer the type of values flowing through your program, I see a conflict
between these two types:

String

number

emit2, emit3, ..., emitWithCallback,emit2WithCallback

To learn more Elm, today I used elm-socketio to write a chat client that could handle various socket.io chat APIs I've seen or built over the years.

The first thing I needed was more arity options for emit so that I had an analogue for these example signatures:

socket.emit('new_message', text, username);
socket.emit('new_message', text, username, channel);
socket.emit('new_message', text, username, channel, isPrivate);

Seems to me that the Elm way to handle this is to expose emit2, emit3, emit4, etc.


The next thing I needed was the ability to handle the conventional fn(err [, result]) callback that some APIs expect.

socket.emit('new_message', text, function(err) {
  if (err) {
    // message rejected by server
    // err is one of 'USER_IS_MUTED' | 'INTERNAL_ERROR' | 'INVALID_COMMAND' | ...
    return;
  }
  // else message was accepted by server and we are free to clear
  // the input box for user to type their next message
});

I'm new to Elm, but I decided to roll a function emitWithCallback which takes a function after the message arguments that will get passed a (Result Left Right) of the server's response to
the callback.

Here's my implementation, to see what I'm talking about:

// in src/Native/SocketIO.elm
var Result = Elm.Result.make(localRuntime);

function emitWithCallback(eventName, message, cb, socket) {
  return Task.asyncFunction(function(elmback) {
    if (socket.disconnected) return elmback(Task.fail('Socket disconnected'));
    if (eventName === '') {
      socket.send(message);
    } else {
      socket.emit(eventName, message, function(left, right) {
        if (left) {
          return elmback(Task.succeed(cb(Result.Err(left))));
        } else {
          return elmback(Task.succeed(cb(Result.Ok(right))));
        }
      });
    }
  });
}

Here's the signature:

emitWithCallback : String -> String -> (Result a b -> c) -> Socket -> Task.Task x c
emitWithCallback =
  Native.MySocketIO.emitWithCallback

And here's how I used it to return an Effects Action so I could
perceive the result in my update function:

type SubmitMessageError
  = UserIsMuted
  | InternalError
  | Forbidden
  | InvalidCommand
  --
  | UnknownError

sendMessage : ChatInput.Model -> Effects Action
sendMessage text =
  getSocket
  `andThen` (\socket ->
    let
      callback : Result String x -> Result SubmitMessageError ()
      callback result =
        case result of
          Err err ->
            case err of
              "INVALID_COMMAND" ->
                Err InvalidCommand
              "USER_IS_MUTED" ->
                Err UserIsMuted
              "INTERNAL_ERROR" ->
                Err InternalError
              "FORBIDDEN" ->
                Err Forbidden
              _ ->
                Err UnknownError
          Ok _ ->
             Ok ()
    in
      MySocketIO.emitWithCallback "new_message" text callback socket
  )
  |> Effects.task
  |> Effects.map HandleSubmitMessageResponse

Once again, I'm a noob and I'm just trying to demonstrate my use case and
what worked for me.

This sort of callback is common in socket.io APIs I've worked with because
it allows you to do things like easily perceive back-pressure or
explicitly handle a message receipt (like view validation errors like
'USERNAME_TAKEN' or whether the message was persisted to the database).

Though I'm not sure how to make it more general or if it's not general enough.


And then I needed the ability to emit multiple arguments along with a
callback to handle the response.

socket.emit('new_message', text, username, cb);
socket.emit('new_message', text, username, channel, cb);
socket.emit('new_message', text, username, channel, isPrivate, cb);

Where emit2WithCallback, emit3WithCallback, etc. would solve it.


Finally, I needed more arity options for on handlers to mirror emit2, emit3, etc.

For example, support for handlers like:

socket.on('user_muted', username, duration, handler);

What do you think?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.