Hello, I'm trying to write an WebSocket endpoint for an API using servant and wai-websockets. Wai-websockets provides websocketsOr :: ConnectionOptions -> ServerApp -> Application -> Application which can be used to to create an Application that can then be plugged in to a Raw endpoint. So far, this works great: newtype SessionChannel = SessionChannel (SessionId, (TChan SessionMessage)) type SessionChannelDB = IxSet SessionChannel type WebsocketsAPI = Capture "session_id" SessionId :> "questions" :> Raw websocketsAPI :: Proxy WebsocketsAPI websocketsAPI = Proxy websocketsServer :: AcidState App -> TVar SessionChannelDB -> Server WebsocketsAPI websocketsServer app sessionChannelDB = \ req -> websocketsOr defaultConnectionOptions (websocketsApp app sessionChannelDB req) (backupApp app) websocketsApp app sessionChannelDB sessionId pending = do conn <- acceptRequest pending sendTextData conn ("Hello, Client" :: Text) I can successfully establish a websocket connection and send the message "Hello, Client" through it. You'll notice the IxSet where a TChan broadcasting SessionMessage's is keyed on a SessionId, and there's a Capture for a SessionId in the path. I'd like to be able to look up the appropriate SessionChannel by its SessionId when a client requests this endpoint. However, I don't get that value as a Capture like I would with a normal Verb. Instead I only get the raw WAI Request. I've experimented with adding a new WebSocket endpoint and using that instead of Raw, modifying the HasServer instance for Raw until I get what I want, but I get lost trying to figure out how the Capture's would flow through and still keep Server WebsocketsAPI = Application (or SessionId -> Application). I've also looked at the servant-subscriber package, but it seems to make too many assumptions about how I'd use and construct these websockets and doesn't quite fit my needs. Does anyone have any suggestions on how to proceed? I'd like to make use of the existing servant machinery for parsing request paths as much as possible. Thanks! |
Hi,
On Mon, Aug 15, 2016 at 07:45:17PM -0700, [hidden email] wrote: > Hello, > > I'm trying to write an WebSocket endpoint for an API using servant and > wai-websockets. Wai-websockets provides websocketsOr :: ConnectionOptions > -> ServerApp -> Application -> Application which can be used to to create > an Application that can then be plugged in to a Raw endpoint. So far, this > works great: > > newtype SessionChannel = SessionChannel (SessionId, (TChan SessionMessage)) > type SessionChannelDB = IxSet SessionChannel > > type WebsocketsAPI = Capture "session_id" SessionId :> "questions" :> Raw > > websocketsAPI :: Proxy WebsocketsAPI > websocketsAPI = Proxy > > websocketsServer :: > AcidState App -> > TVar SessionChannelDB -> > Server WebsocketsAPI > websocketsServer app sessionChannelDB = \ req -> > websocketsOr > defaultConnectionOptions > (websocketsApp app sessionChannelDB req) > (backupApp app) websocketsApp :: AcidState App -> TVar SessionChannelDB -> SessionId -> PendingConnection -> IO () So that in turn the 'req' lambda binding in websocketsServer above is of type 'SessionId'. Indeed, I'm pretty sure 'Server WebsocketsAPI' is equal to 'SessionId -> Application'. Just to be sure (because the binding 'req' seems strangely named) - are you not confusing the 'Request' from the 'Application' type synonym with 'SessionId"? 'sessionId' isn't used anywhere in the body of 'websocketsApp', so you wouldn't get a type error. > > websocketsApp app sessionChannelDB sessionId pending = do > conn <- acceptRequest pending > sendTextData conn ("Hello, Client" :: Text) > > I can successfully establish a websocket connection and send the message > "Hello, Client" through it. You'll notice the IxSet where a TChan > broadcasting SessionMessage's is keyed on a SessionId, and there's a Capture > for a SessionId in the path. I'd like to be able to look up the appropriate > SessionChannel by its SessionId when a client requests this endpoint. > However, I don't get that value as a Capture like I would with a normal Verb. > Instead I only get the raw WAI Request. I've experimented with adding a new > WebSocket endpoint and using that instead of Raw, modifying the HasServer > instance for Raw until I get what I want, but I get lost trying to figure > out how the Capture's would flow through and still keep Server > WebsocketsAPI = Application (or SessionId -> Application). I've also looked > at the servant-subscriber package, but it seems to make too many > assumptions about how I'd use and construct these websockets and doesn't > quite fit my needs. Does anyone have any suggestions on how to proceed? I'd > like to make use of the existing servant machinery for parsing request > paths as much as possible. > > Thanks! > > -- > > > > > -- Julian K. Arni Haskell Consultant, Turing Jump https://turingjump.com -- |
Thanks Julian. I think you're right in that I was confusing the type of req. I remember seeing GHC infer it as a raw WAI Request at some point, but I'm seeing it as a SessionId right now. It seems like everything is working smoothly now. Thanks for your help.
-- On Tuesday, 16 August 2016 12:46:14 UTC-4, Julian Arni wrote: Hi, |
Free forum by Nabble | Edit this page |