Implement subscriptions

This commit is contained in:
Paul-Henri Froidmont 2025-09-11 17:30:26 +02:00
parent 08036ab5aa
commit 5da0b64c3e
Signed by: phfroidmont
GPG key ID: BE948AFD7E7873BE
7 changed files with 103 additions and 45 deletions

View file

@ -3,6 +3,7 @@ package playground
import scalive.*
import zio.*
import zio.stream.ZStream
import TestView.*
class TestView extends LiveView[Msg, Model]:
@ -29,6 +30,8 @@ class TestView extends LiveView[Msg, Model]:
)
)
def subscriptions(model: Model) = ZStream.empty
object TestView:
enum Msg:

View file

@ -16,6 +16,14 @@ enum Diff:
case Dynamic(key: String, diff: Diff)
case Deleted
extension (diff: Diff)
def isEmpty: Boolean = diff match
case Diff.Tag(static, dynamic) => static.isEmpty && dynamic.isEmpty
case _: Diff.Comprehension => false
case _: Diff.Value => false
case _: Diff.Dynamic => false
case Diff.Deleted => false
object Diff:
given JsonEncoder[Diff] = JsonEncoder[Json].contramap(toJson(_))

View file

@ -1,9 +1,10 @@
package scalive
import zio.*
import zio.stream.*
trait LiveView[Msg, Model]:
def init: Task[Model]
def update(model: Model): Msg => Task[Model]
def view(model: Dyn[Model]): HtmlElement
// def subscriptions(model: Model): ZStream[Any, Nothing, Msg]
def subscriptions(model: Model): ZStream[Any, Nothing, Msg]

View file

@ -11,18 +11,19 @@ final case class WebSocketMessage(
// Live session ID, auto increment defined by the client on join
joinRef: Option[Int],
// Message ID, global auto increment defined by the client on every message
messageRef: Int,
messageRef: Option[Int],
// LiveView instance id
topic: String,
eventType: String,
payload: WebSocketMessage.Payload):
val meta = WebSocketMessage.Meta(joinRef, messageRef, topic)
val meta = WebSocketMessage.Meta(joinRef, messageRef, topic, eventType)
object WebSocketMessage:
final case class Meta(
joinRef: Option[Int],
messageRef: Int,
topic: String)
messageRef: Option[Int],
topic: String,
eventType: String)
given JsonCodec[WebSocketMessage] = JsonCodec[Json].transformOrFail(
{
@ -38,7 +39,7 @@ object WebSocketMessage:
payloadParsed.map(
WebSocketMessage(
joinRef.asString.map(_.toInt),
messageRef.toInt,
Some(messageRef.toInt),
topic,
eventType,
_
@ -49,14 +50,15 @@ object WebSocketMessage:
m =>
Json.Arr(
m.joinRef.map(ref => Json.Str(ref.toString)).getOrElse(Json.Null),
Json.Str(m.messageRef.toString),
m.messageRef.map(ref => Json.Str(ref.toString)).getOrElse(Json.Null),
Json.Str(m.topic),
Json.Str(m.eventType),
m.payload.match
m.payload match
case Payload.Heartbeat => Json.Obj.empty
case p: Payload.Join => p.toJsonAST.getOrElse(throw new IllegalArgumentException())
case p: Payload.Reply => p.toJsonAST.getOrElse(throw new IllegalArgumentException())
case p: Payload.Event => p.toJsonAST.getOrElse(throw new IllegalArgumentException())
case p: Payload.Diff => p.toJsonAST.getOrElse(throw new IllegalArgumentException())
)
)
@ -69,11 +71,16 @@ object WebSocketMessage:
static: Option[String],
sticky: Boolean)
case Reply(status: String, response: LiveResponse)
case Diff(diff: scalive.Diff)
case Event(`type`: Payload.EventType, event: String, value: Map[String, String])
object Payload:
given JsonCodec[Payload.Join] = JsonCodec.derived
given JsonEncoder[Payload.Reply] = JsonEncoder.derived
given JsonCodec[Payload.Event] = JsonCodec.derived
given JsonEncoder[Payload.Diff] = JsonEncoder[scalive.Diff].contramap(_.diff)
def okReply(response: LiveResponse) =
Payload.Reply("ok", response)
enum EventType:
case Click