aboutsummaryrefslogtreecommitdiff
path: root/examples/server_demo/src/demo/socket.gleam
blob: bc4396292fd9832806af3c498143cc979d456ae4 (plain)
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
// IMPORTS ---------------------------------------------------------------------

import demo/app
import gleam/bit_array
import gleam/erlang/process.{type Subject}
import gleam/function.{identity}
import gleam/http/request.{type Request as HttpRequest}
import gleam/http/response.{type Response as HttpResponse}
import gleam/json
import gleam/option.{Some}
import gleam/otp/actor
import gleam/result
import lustre.{type Action, type ServerComponent}
import lustre/element.{type Patch}
import lustre/server
import mist.{
  type Connection, type ResponseData, type WebsocketConnection,
  type WebsocketMessage,
}

// 

pub fn handle(req: HttpRequest(Connection)) -> HttpResponse(ResponseData) {
  mist.websocket(req, update, init, function.constant(Nil))
}

type Model(flags, model, msg) {
  Model(self: Subject(Patch(msg)), app: Subject(Action(ServerComponent, msg)))
}

fn init(_) {
  let assert Ok(app) =
    lustre.component(app.init, app.update, app.view, app.on_attribute_change())
    |> lustre.start_actor(0)
  let self = process.new_subject()
  let model = Model(self, app)
  let selector = process.selecting(process.new_selector(), self, identity)

  actor.send(app, lustre.add_renderer(process.self(), process.send(self, _)))
  #(model, Some(selector))
}

fn update(
  model: Model(flags, model, msg),
  conn: WebsocketConnection,
  msg: WebsocketMessage(Patch(a)),
) {
  case msg {
    mist.Text(bits) -> {
      let _ = {
        use dyn <- json.decode_bits(bits)
        use action <- result.try(server.decode_action(dyn))

        actor.send(model.app, action)
        Ok(Nil)
      }

      actor.continue(model)
    }
    mist.Binary(_) -> actor.continue(model)
    mist.Closed -> {
      actor.send(model.app, lustre.remove_renderer(process.self()))
      actor.continue(model)
    }
    mist.Shutdown -> {
      actor.send(model.app, lustre.shutdown())
      actor.Stop(process.Normal)
    }
    mist.Custom(patch) -> {
      element.encode_patch(patch)
      |> json.to_string
      |> bit_array.from_string
      |> mist.send_text_frame(conn, _)

      actor.continue(model)
    }
  }
}