5

我有一个 f# 聊天应用程序,该应用程序需要暴露其余 api 以及用于实时消息传递的 websockets。我正在使用 Suave 框架。

我有一个前端,它有一个“聊天”按钮,点击时运行 javascript。javascript 触发为 websocket url (/websocket) 创建一个 web socket,并为实时聊天建立连接。但是,我有另一个按钮“FetchUsers”用于获取系统中的所有用户。但为此,我需要一条不同的路径(/people)。我不认为我可以使用 (/websocket) 路径,因为在后端,只有一个函数可以为特定路径定义。

为了实现这一点,我提出了可以公开 2 个不同端口的想法:一个用于其余 api,一个用于 Web 套接字。我的 rest api (localhost:8082/people) 用于获取系统中的所有用户,而 web sockets (localhost:8080/websocket) 用于向系统中的所有用户发送聊天消息

对于如何实现聊天应用程序,我愿意接受任何其他建议。

程序.fs

let app : WebPart = 
  choose [
    path "/websocket" >=> handShake ws
    path "/websocketWithSubprotocol" >=> handShakeWithSubprotocol (chooseSubprotocol "test") ws
    path "/websocketWithError" >=> handShake wsWithErrorHandling
    GET >=> choose [ path "/" >=> file "index.html"; browseHome ]
    NOT_FOUND "Found no handlers." ]

let myCfg =
  { defaultConfig with
      bindings = [                        
                   HttpBinding.createSimple HTTP "127.0.0.1" 8080
                   HttpBinding.createSimple HTTP "127.0.0.1" 8082 
                  ]
    }
[<EntryPoint>]
let main _ =
  let personWebPart = rest "people" {
        GetAll = Db.getPeople
        Create = Db.createPerson
    }
  startWebServer myCfg personWebPart
  startWebServer myCfg app

宁静的.fs

module RestFul =
    open Suave.Web
    open Suave.Successful
    open Newtonsoft.Json    
    open Suave
    open Suave.Operators
    open Suave.Filters        
    open Suave.Files
    open Suave.RequestErrors
    
    open Newtonsoft.Json.Serialization
    type RestResource<'a> = {
        GetAll : unit -> 'a seq
        Create : 'a -> 'a            
    }

    let fromJson<'a> json =
        JsonConvert.DeserializeObject(json, typeof<'a>) :?> 'a

    let getResourceFromReq<'a> (req : HttpRequest) =
        let getString (rawForm: byte[]) =
            System.Text.Encoding.UTF8.GetString(rawForm)
        req.rawForm |> getString |> fromJson<'a>

    let JSON v =
        let jsonSerializerSettings = JsonSerializerSettings()
        jsonSerializerSettings.ContractResolver <- CamelCasePropertyNamesContractResolver()

        JsonConvert.SerializeObject(v, jsonSerializerSettings)
        |> OK
        >=> Writers.setMimeType "application/json; charset=utf-8"

    let rest resourceName resource =
        let resourcePath = "/" + resourceName
        let getAll = warbler (fun _ -> resource.GetAll () |> JSON)
        
        path resourcePath >=> choose [
            GET >=> getAll
            POST >=> request (getResourceFromReq >> resource.Create >> JSON)
        ]

如何将 websocket 分配到端口 8080 并将 api 分配到端口 8082?我现在正在这样做。服务器在端口上启动,但我只能访问其余的 url,即 localhost:8080/people

startWebServer myCfg personWebPart
startWebServer myCfg app

重申我之前的观点,我想知道关于如何实现聊天应用程序的任何其他方法。

4

1 回答 1

2

我使用 Suave 已经有一段时间了,但如果我记得它使用自定义“套接字”计算表达式支持 WebSocket。您在表达式中循环,等待消息,然后处理它。请注意,等待 Websocket 本身就是一个异步操作,每个客户端都有自己的循环。

示例在他们的 Github 上: https ://github.com/SuaveIO/suave/blob/master/examples/WebSocket/Program.fs

于 2020-12-14T00:27:31.500 回答