【问题标题】:Elm divide subscription?榆树分订阅?
【发布时间】:2016-12-31 15:35:13
【问题描述】:

我在玩 Elm 和 WebRTC,所以我做了一个监听端口,它从 js 获取一些消息:

type alias Message = 
    { channel : String
    , data : String
    }
port listen : (Message -> msg) -> Sub msg

现在我希望能够将消息划分到我的应用程序的不同部分。例如,聊天使用“聊天”频道,而游戏逻辑使用“游戏”。

是否可以创建一个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 是用于聊天的 Msg,它什么都不做 case msg of Ignore -&gt; (model, Cmd.none)decodeMessage 使用解码器来解码消息 decodeMessage : String -&gt; Result String Message。)

我对此很满意,因为这样所有的聊天逻辑都在 Chat.elm 中。所以 main.elm 不需要知道聊天正在使用哪些频道。聊天只是遵循标准结构(消息、更新、查看、订阅)并主要转发所有内容。

唯一仍然不是很好的是,在 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

所以我想我自己找到了解决方案。除非有人对此有cmets。也许有更清洁/更好/更好的方式来做同样的事情?

【问题讨论】:

    标签: elm


    【解决方案1】:

    假设您有以下Msg 定义:

    type Msg
        = Listen Message
        | GameChannel String
        | ChatChannel String
    

    然后您的update 函数可以作用于channel 值并使用正确的通道再次调用update,忽略除"game""chat" 之外的所有channel 值:

    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
    

    【讨论】:

    • 谢谢,但这就是我正在做的,并不是我真正的意思。我用更多信息更新了我的原始问题。从那以后,我已经将系统更改为我喜欢的东西,但仍然需要帮助来完善它。
    【解决方案2】:

    我自己找到了解决方案,并将其添加到原始问题中。

    为清楚起见,这是简短的版本:

    在我的 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多