aboutsummaryrefslogtreecommitdiff
path: root/examples/server_demo/src/demo/socket.gleam
diff options
context:
space:
mode:
authorHayleigh Thompson <me@hayleigh.dev>2024-01-23 00:09:45 +0000
committerGitHub <noreply@github.com>2024-01-23 00:09:45 +0000
commit24f6962aa457d32319756f6217aafde7b0a9c752 (patch)
tree42119d9b073f56eabe9dda4ae2065ef4b2086e6a /examples/server_demo/src/demo/socket.gleam
parent45e671ac32de95ae1a0a9f9e98da8645d01af3cf (diff)
downloadlustre-24f6962aa457d32319756f6217aafde7b0a9c752.tar.gz
lustre-24f6962aa457d32319756f6217aafde7b0a9c752.zip
✨ Add universal components that can run on the server (#39)
* :heavy_plus_sign: Add gleam_erlang gleam_otp and gleam_json dependencies. * :sparkles: Add json encoders for elememnts and attributes. * :sparkles: Add the ability to perform an effect with a custom dispatch function. * :construction: Experiment with a server-side component runtime. * :construction: Expose special server click events. * :construction: Experiment with a server-side component runtime. * :construction: Experiment with a server-side component runtime. * :construction: Experiment with a server-side component runtime. * :construction: Create a basic server component client bundle. * :construction: Create a basic server component demo. * :bug: Fixed a bug where the runtime stopped performing patches. * :refactor: Roll back introduction of shadow dom. * :recycle: Refactor to Custom Element-based approach to encapsulating server components. * :truck: Move some things around. * :sparkles: Add a minified version of the server component runtime. * :wrench: Add lustre/server/* to internal modules. * :recycle: on_attribute_change and on_client_event handlers are now functions not dicts. * :recycle: Refactor server component event handling to no longer need explicit tags. * :fire: Remove unnecessary attempt to stringify events. * :memo: Start documeint lustre/server functions. * :construction: Experiment with a js implementation of the server component backend runtime. * :recycle: Experiment with an API that makes heavier use of conditional complilation. * :recycle: Big refactor to unify server components, client components, and client apps. * :bug: Fixed some bugs with client runtimes. * :recycle: Update examples to new lustre api/ * :truck: Move server demo into examples/ folder/ * :wrench: Add lustre/runtime to internal modules. * :construction: Experiment with a diffing implementation. * :wrench: Hide internal modules from docs. * :heavy_plus_sign: Update deps to latest versions. * :recycle: Move diffing and vdom code into separate internal modules. * :sparkles: Bring server components to feature parity with client components. * :recycle: Update server component demo. * :bug: Fix bug where attribute changes weren't properly broadcast. * :fire: Remove unused 'Patch' type. * :recycle: Stub out empty js implementations so we can build for js. * :memo: Docs for the docs gods. * :recycle: Rename lustre.server_component to lustre.component.
Diffstat (limited to 'examples/server_demo/src/demo/socket.gleam')
-rw-r--r--examples/server_demo/src/demo/socket.gleam78
1 files changed, 78 insertions, 0 deletions
diff --git a/examples/server_demo/src/demo/socket.gleam b/examples/server_demo/src/demo/socket.gleam
new file mode 100644
index 0000000..bc43962
--- /dev/null
+++ b/examples/server_demo/src/demo/socket.gleam
@@ -0,0 +1,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)
+ }
+ }
+}