úÎ;Å8(      !"#$%&'None[XA wrapped bytestring that represents a properly escaped and quoted PostgreSQL identifier(3Given a PgIdentifier returns the wrapped bytestringEGiven a bytestring returns a properly quoted and escaped PgIdentifierRGiven a Hasql Pool, a channel and a message sends a notify command to the databaseXGiven a Hasql Connection, a channel and a message sends a notify command to the databaseMGiven a Hasql Connection and a channel sends a listen command to the database OGiven a Hasql Connection and a channel sends a unlisten command to the database ¬Given a function that handles notifications and a Hasql connection forks a thread that listens on the database connection and calls the handler everytime a message arrives.VThe message handler passed as first argument needs two parameters channel and payload. )*+(    )*+( None[,0Possible situations encountered with client JWTs  Given a secret, a token and a timestamp it validates the claims and returns either an error message or a triple containing channel, mode and claims hashmap.-RReceives the JWT secret (from config) and a JWT and returns a map of JWT claims..NInternal helper used to turn JWT ClaimSet into something easier to work with/žInternal helper to generate HMAC-SHA256. When the jwt key in the config file is a simple string rather than a JWK object, we'll apply this function to it. ,01234 -./5  ,01234 -./5None[Open a multiplexer's channelClose a multiplexer's channelTOpens a thread that relays messages from the producer thread to the channels foreverjReads the messages from the producer and relays them to the active listeners in their respective channels.ÿ_Adds a listener to a certain multiplexer's channel. The listener must be a function that takes a 'TChan Message' and perform any IO action. All listeners run in their own thread. The first listener will open the channel, when a listener dies it will check if there acquire any others and close the channel when that's the case.6789:;<=>? 6789:;<=>?None[!ØReturns a multiplexer from a connection URI, keeps trying to connect in case there is any error. This function also spawns a thread that keeps relaying the messages from the database to the multiplexer's listeners"ÈReturns a multiplexer from a connection URI or an error message on the left case This function also spawns a thread that keeps relaying the messages from the database to the multiplexer's listeners@Returns a multiplexer from an IO Connection, listen for different database notification channels using the connection produced.tThis function also spawns a thread that keeps relaying the messages from the database to the multiplexer's listenersTo listen on channels *chat* ± import Protolude import PostgresWebsockets.HasqlBroadcast import PostgresWebsockets.Broadcast import Hasql.Connection main = do conOrError <- H.acquire "postgres:/ localhostÌtest_database" let con = either (panic . show) id conOrError :: Connection multi <- newHasqlBroadcaster con onMessage multi "chat" (ch -> forever $ fmap print (atomically $ readTChan ch) !"A@B!"!"!"A@BNone5[#xGiven a secret, a function to fetch the system time, a Hasql Pool and a Multiplexer this will give you a WAI middleware.CDEF#GH$!"##!"CDEF#GH$I  !"#$%&'()*+,-.*)/0123456789:;<==>?@ABCDEFGHIJK2postgres-websockets-0.4.2.1-LZxkI1znq4L9LSPUhqPqHl!PostgresWebsockets.HasqlBroadcastPostgresWebsockets.BroadcastPostgresWebsockets.DatabasePostgresWebsockets.ClaimsPostgresWebsockets"hasql-1.1.1-ASqAUpeK2Od91rxqzQJqOOHasql.Private.Connectionacquire"stm-2.4.4.1-JQn4hNPyYjP5m9AcbI88VeControl.Concurrent.STM.TChan readTChanControl.Concurrent.STM.TQueue readTQueue writeTQueue PgIdentifiertoPgIdentifier notifyPoolnotifylistenunlistenwaitForNotifications$fShowPgIdentifiervalidateClaims$fEqJWTAttempt MultiplexersrcMessagechannelpayloadSourceCommandsOpenCloseopenChannelProducercloseChannelProducerrelayMessagesForever relayMessagesnewMultiplexer onMessage$fShowMultiplexer$fShowSourceCommands $fEqMessage $fShowMessagenewHasqlBroadcasternewHasqlBroadcasterOrErrorpostgresWsMiddleware$fToJSONMessage$fGenericMessagefromPgIdentifierError NotifyError JWTAttempt jwtClaims claims2maphs256jwk JWTInvalidJWTMissingSecret JWTClaimsConnectionInfoClaimsparseJWKChannel broadcast listenersclosechannelscommandsmessages openChannel newHasqlBroadcasterForConnectiontryUntilConnectedputErrLnclaimswsApp notifySession