榆树划分订阅?
Elm divide subscription?
我正在玩 Elm 和 WebRTC,所以我做了一个监听端口,它从 js 获取一些消息:
type alias Message =
{ channel : String
, data : String
}
port listen : (Message -> msg) -> Sub msg
现在我希望能够将消息划分到我的应用程序的不同部分。例如,聊天使用 "chat" 频道,而游戏逻辑使用 "game".
是否可以创建一个 listenTo String
订阅来过滤掉具有正确通道的消息(仅返回数据)?或者换一种方式?
更新:
我目前拥有的是这样的:
在我的 main.elm 中,我有一个看起来像这样的更新。它可以自己接收消息(来自 rtc),并向它发送聊天消息。 (我稍后也会添加一个 "ForGame")
type Msg = Received WebRTC.Message | ForChat Chat.Msg
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Received message ->
let
_ = Debug.log ("Received message on \"" ++ message.channel ++ "\": " ++ message.data)
in
( model
, Cmd.none
)
ForChat msg ->
let
(chatModel, chatCmd) = Chat.update msg model.chat
in
({ model | chat = chatModel}, Cmd.map ForChat chatCmd)
然后我有结合我所有订阅的订阅:
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.batch
[ WebRTC.listen Received
, Sub.map ForChat <| Chat.subscriptions model.chat
]
在 Chat.elm 我有一个类似的结构,有一个处理它的消息的更新。聊天的订阅会监听来自 WebRTC 的所有消息,但只过滤带有聊天频道的消息:
subscriptions : Model -> Sub Msg
subscriptions model = WebRTC.listen forChatMessages
forChatMessages : WebRTC.Message -> Msg
forChatMessages webrtcMessage =
if webrtcMessage.channel == "chat"
then
let
message = decodeMessage webrtcMessage.data
in
case message of
Ok msg -> Receive msg
Err error -> Debug.log ("Received unreadable message on chat channel \"" ++ toString webrtcMessage.data ++ "\" with error \"" ++ error ++ "\"") Ignore
else
Ignore
(Ignore 是聊天消息,什么都不做case msg of Ignore -> (model, Cmd.none)
。decodeMessage
使用解码器解码消息 decodeMessage : String -> Result String Message
。)
我对此非常满意,因为这样所有聊天逻辑都在 Chat.elm 中。所以 main.elm 不需要知道聊天正在使用什么频道。 Chat 仅遵循标准结构(消息、更新、查看、订阅)并主要转发所有内容。
唯一还不是很好的是,在 Chat.elm 中我有 forChatMessages
功能。用法如:subscriptions model = WebRTC.listen forChatMessages
。我想让它更可重用,所以它会变成这样:
subscriptions model = WebRTC.listen for "chat" decodeMessage Receive Ignore
然后游戏可以重复使用它:
subscriptions model = WebRTC.listen for "game" decodeGameInfo UpdateInfo Ignore
更新 2:
我设法将 forChatMessages
函数概括为:
for : String -> (String -> Result String d) -> (d -> msg) -> msg -> Message -> msg
for channel decoder good bad webrtcMessage =
if
webrtcMessage.channel == channel
then
let
decoded = decoder webrtcMessage.data
in
case decoded of
Ok data -> good data
Err error -> Debug.log ("Failed decoding message on " ++ channel ++ "channel \"" ++ toString webrtcMessage.data ++ "\" with error \"" ++ error ++ "\"") bad
else
bad
所以我想我自己找到了解决方案。除非有人对此发表评论。也许有一种 cleaner/nicer/better 方法可以做到这一点?
假设您有以下 Msg
定义:
type Msg
= Listen Message
| GameChannel String
| ChatChannel String
然后您的 update
函数可以对 channel
值进行操作并使用正确的通道再次调用 update
,忽略除 [=18= 之外的所有 channel
值] 和 "chat"
:
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Listen message ->
case message.channel of
"game" ->
update (GameChannel message.data) model
"chat" ->
update (ChatChannel message.data) model
_ ->
model ! []
GameChannel data ->
...
ChatChannel data ->
...
您的订阅功能将如下所示:
subscriptions : Model -> Sub Msg
subscriptions model =
listen Listen
我自己找到了解决方案,并添加到原问题中。
为清楚起见,这是简短版本:
在我的 main.elm:
type Msg = Received WebRTC.Message | ForChat Chat.Msg
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Received message ->
let
_ = Debug.log ("Received message on \"" ++ message.channel ++ "\": " ++ message.data)
in
( model
, Cmd.none
)
ForChat msg ->
let
(chatModel, chatCmd) = Chat.update msg model.chat
in
({ model | chat = chatModel}, Cmd.map ForChat chatCmd)
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.batch
[ WebRTC.listen Received
, Sub.map ForChat <| Chat.subscriptions model.chat
]
在Chat.elm中:
subscriptions : Model -> Sub Msg
subscriptions model = WebRTC.listen <| for "game" decodeGameInfo UpdateInfo Ignore
在WebRTC.elm中:
type alias Message =
{ channel : String
, data : String
}
port listen : (Message -> msg) -> Sub msg
for : String -> (String -> Result String d) -> (d -> msg) -> msg -> Message -> msg
for channel decoder good bad webrtcMessage =
if
webrtcMessage.channel == channel
then
let
decoded = decoder webrtcMessage.data
in
case decoded of
Ok data -> good data
Err error -> Debug.log ("Failed decoding message on " ++ channel ++ "channel \"" ++ toString webrtcMessage.data ++ "\" with error \"" ++ error ++ "\"") bad
else
bad
我正在玩 Elm 和 WebRTC,所以我做了一个监听端口,它从 js 获取一些消息:
type alias Message =
{ channel : String
, data : String
}
port listen : (Message -> msg) -> Sub msg
现在我希望能够将消息划分到我的应用程序的不同部分。例如,聊天使用 "chat" 频道,而游戏逻辑使用 "game".
是否可以创建一个 listenTo String
订阅来过滤掉具有正确通道的消息(仅返回数据)?或者换一种方式?
更新:
我目前拥有的是这样的:
在我的 main.elm 中,我有一个看起来像这样的更新。它可以自己接收消息(来自 rtc),并向它发送聊天消息。 (我稍后也会添加一个 "ForGame")
type Msg = Received WebRTC.Message | ForChat Chat.Msg
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Received message ->
let
_ = Debug.log ("Received message on \"" ++ message.channel ++ "\": " ++ message.data)
in
( model
, Cmd.none
)
ForChat msg ->
let
(chatModel, chatCmd) = Chat.update msg model.chat
in
({ model | chat = chatModel}, Cmd.map ForChat chatCmd)
然后我有结合我所有订阅的订阅:
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.batch
[ WebRTC.listen Received
, Sub.map ForChat <| Chat.subscriptions model.chat
]
在 Chat.elm 我有一个类似的结构,有一个处理它的消息的更新。聊天的订阅会监听来自 WebRTC 的所有消息,但只过滤带有聊天频道的消息:
subscriptions : Model -> Sub Msg
subscriptions model = WebRTC.listen forChatMessages
forChatMessages : WebRTC.Message -> Msg
forChatMessages webrtcMessage =
if webrtcMessage.channel == "chat"
then
let
message = decodeMessage webrtcMessage.data
in
case message of
Ok msg -> Receive msg
Err error -> Debug.log ("Received unreadable message on chat channel \"" ++ toString webrtcMessage.data ++ "\" with error \"" ++ error ++ "\"") Ignore
else
Ignore
(Ignore 是聊天消息,什么都不做case msg of Ignore -> (model, Cmd.none)
。decodeMessage
使用解码器解码消息 decodeMessage : String -> Result String Message
。)
我对此非常满意,因为这样所有聊天逻辑都在 Chat.elm 中。所以 main.elm 不需要知道聊天正在使用什么频道。 Chat 仅遵循标准结构(消息、更新、查看、订阅)并主要转发所有内容。
唯一还不是很好的是,在 Chat.elm 中我有 forChatMessages
功能。用法如:subscriptions model = WebRTC.listen forChatMessages
。我想让它更可重用,所以它会变成这样:
subscriptions model = WebRTC.listen for "chat" decodeMessage Receive Ignore
然后游戏可以重复使用它:
subscriptions model = WebRTC.listen for "game" decodeGameInfo UpdateInfo Ignore
更新 2:
我设法将 forChatMessages
函数概括为:
for : String -> (String -> Result String d) -> (d -> msg) -> msg -> Message -> msg
for channel decoder good bad webrtcMessage =
if
webrtcMessage.channel == channel
then
let
decoded = decoder webrtcMessage.data
in
case decoded of
Ok data -> good data
Err error -> Debug.log ("Failed decoding message on " ++ channel ++ "channel \"" ++ toString webrtcMessage.data ++ "\" with error \"" ++ error ++ "\"") bad
else
bad
所以我想我自己找到了解决方案。除非有人对此发表评论。也许有一种 cleaner/nicer/better 方法可以做到这一点?
假设您有以下 Msg
定义:
type Msg
= Listen Message
| GameChannel String
| ChatChannel String
然后您的 update
函数可以对 channel
值进行操作并使用正确的通道再次调用 update
,忽略除 [=18= 之外的所有 channel
值] 和 "chat"
:
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Listen message ->
case message.channel of
"game" ->
update (GameChannel message.data) model
"chat" ->
update (ChatChannel message.data) model
_ ->
model ! []
GameChannel data ->
...
ChatChannel data ->
...
您的订阅功能将如下所示:
subscriptions : Model -> Sub Msg
subscriptions model =
listen Listen
我自己找到了解决方案,并添加到原问题中。
为清楚起见,这是简短版本:
在我的 main.elm:
type Msg = Received WebRTC.Message | ForChat Chat.Msg
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Received message ->
let
_ = Debug.log ("Received message on \"" ++ message.channel ++ "\": " ++ message.data)
in
( model
, Cmd.none
)
ForChat msg ->
let
(chatModel, chatCmd) = Chat.update msg model.chat
in
({ model | chat = chatModel}, Cmd.map ForChat chatCmd)
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.batch
[ WebRTC.listen Received
, Sub.map ForChat <| Chat.subscriptions model.chat
]
在Chat.elm中:
subscriptions : Model -> Sub Msg
subscriptions model = WebRTC.listen <| for "game" decodeGameInfo UpdateInfo Ignore
在WebRTC.elm中:
type alias Message =
{ channel : String
, data : String
}
port listen : (Message -> msg) -> Sub msg
for : String -> (String -> Result String d) -> (d -> msg) -> msg -> Message -> msg
for channel decoder good bad webrtcMessage =
if
webrtcMessage.channel == channel
then
let
decoded = decoder webrtcMessage.data
in
case decoded of
Ok data -> good data
Err error -> Debug.log ("Failed decoding message on " ++ channel ++ "channel \"" ++ toString webrtcMessage.data ++ "\" with error \"" ++ error ++ "\"") bad
else
bad