7
5

More than 5 years have passed since last update.

ElmでWebSocketを試してみた(Sub)

Last updated at Posted at 2017-12-20

 Elmは自分でできない汚れ仕事をElm Realtimeに下請けさせますが、その時のインターフェースとしてCmd/Subを使います。Subのexampleとして公式サイトに載っているWebSocketのプログラムを試しましたのでその記録です。
https://guide.elm-lang.org/architecture/effects/web_sockets.html

1.開発環境

 最後にリストしますが、index.htmlとMyWebSocket.elmのファイルを用意します。開発の流れは以下の記事に従います。
Elm開発環境について - Qiita

以下のコマンドを実行します。

mkdir websocket
elm-package install elm-lang/websocket

 index.htmlとMyWebSocket.elmをwebsocketディレクトリにおいてコンパイルします。elm-reactorを実行するとブラウザからアクセスできます。

elm-make MyWebSocket.elm --output elm.js
elm-reactor -a=www.xxxxx.jp -p=3030

2.index.html

 コンパイル結果のelm.jsを読み込んで、そこからimportしたMyWebSocketモジュールを使って、Elm.MyWebSocket.embedでアプリを走らせています。

index.html
<!doctype html>
<html>
    <head>
    </head>
    <body>
        <div id="elm-area"></div>
        <script src="elm.js"></script>
        <script>
            Elm.MyWebSocket.embed(document.getElementById("elm-area"));
        </script>
    </body>
</html>

3.MyWebSocket.elm

 Elmプログラムの全てですが、大変シンプルなことに驚きます。以下に多少の説明を加えたいと思います。

MyWebSocket.elm
module MyWebSocket exposing (..)

import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import WebSocket

main =
  Html.program
    { init = init
    , view = view
    , update = update
    , subscriptions = subscriptions
    }

-- MODEL
type alias Model =
  { input : String
  , messages : List String
  }


init : (Model, Cmd Msg)
init = (Model "" [], Cmd.none)


-- UPDATE
type Msg
  = Input String
  | Send
  | NewMessage String


update : Msg -> Model -> (Model, Cmd Msg)
update msg {input, messages} =
  case msg of
    Input newInput ->
      (Model newInput messages, Cmd.none)

    Send ->
      (Model "" messages, WebSocket.send "ws://echo.websocket.org" input)

    NewMessage str ->
      (Model input (str :: messages), Cmd.none)

-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
  WebSocket.listen "ws://echo.websocket.org" NewMessage

-- VIEW
view : Model -> Html Msg
view model =
  div []
    [ div [] (List.map viewMessage model.messages)
    , input [onInput Input] []
    , button [onClick Send] [text "Send"]
    ]

viewMessage : String -> Html msg
viewMessage msg =
  div [] [ text msg ]

 index.htmlで使われるのでプログラムのモジュール名を宣言しておく必要があります。

モジュール名宣言
module MyWebSocket exposing (..)

 まずWebSocketの関連部分は以下のとおりです。これはelm-lang/websocketモジュールで提供される機能です。

elmのWebSocket関連部分
WebSocket.send "ws://echo.websocket.org" input
WebSocket.listen "ws://echo.websocket.org" NewMessage

 ws プロトコルは、WebSocket サーバとリソース名を識別する。exampleですので、ここではecho.websocket.orgという既存のエコーサーバが使われています。ちなみに通信がTLS により保護されることが必要なときはwssが使われます。
https://triple-underscore.github.io/RFC6455-ja.html#section-11.1.1

 それぞれの型を以下に挙げると、使われ方もはっきりすると思われます。WebSocket.send はupdateの返り値のCmd部分に使われます。WebSocket.listenはsubscriptionsの定義に使われます。

WebSocket関数の型
WebSocket.send : String -> String -> Cmd msg
WebSocket.listen : String -> (String -> msg) -> Sub msg

 subscriptions関数はイベントのリスナーのようなものを設置するためのものです。今回はWebSocketサーバ(echo.websocket.org)からの通信をリッスンします。通信を受け取るとNewMessage strという型でupdate関数が呼ばれます。NewMessageはlisten関数の第2引数で、strが通信内容ですね。

subscriptions関数
subscriptions : Model -> Sub Msg
subscriptions model =
  WebSocket.listen "ws://echo.websocket.org" NewMessage

 以上ですが、WebSocket モジュールがうまくCmd/Subのアーキテクチャにはまって、全体的にシンプルなプログラムになっていると思います。

7
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5