{"id":23651523,"url":"https://github.com/athanclark/websockets-rpc","last_synced_at":"2025-10-19T05:08:00.630Z","repository":{"id":56882521,"uuid":"84010262","full_name":"athanclark/websockets-rpc","owner":"athanclark","description":"A simple subscription-esque RPC mechanism using WebSockets","archived":false,"fork":false,"pushed_at":"2018-03-16T01:52:10.000Z","size":36,"stargazers_count":5,"open_issues_count":2,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-03-25T23:43:41.248Z","etag":null,"topics":["haskell","rpc-call","websockets","websockets-rpc"],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/athanclark.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-05T23:27:41.000Z","updated_at":"2023-04-04T17:23:59.000Z","dependencies_parsed_at":"2022-08-20T23:10:58.788Z","dependency_job_id":null,"html_url":"https://github.com/athanclark/websockets-rpc","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/athanclark%2Fwebsockets-rpc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/athanclark%2Fwebsockets-rpc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/athanclark%2Fwebsockets-rpc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/athanclark%2Fwebsockets-rpc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/athanclark","download_url":"https://codeload.github.com/athanclark/websockets-rpc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":231652197,"owners_count":18406092,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["haskell","rpc-call","websockets","websockets-rpc"],"created_at":"2024-12-28T16:38:09.110Z","updated_at":"2025-10-19T05:07:55.583Z","avatar_url":"https://github.com/athanclark.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"websockets-rpc\n===============\n\nA simple message-based streaming RPC mechanism built using WebSockets\n\n## Usage\n\nThe idea is pretty simple:\n\n- A client initiates the RPC call to a server with a `Subscription`\n- the client may send additional data at any time with `Supply`, who can also cancel the RPC call\n- the server may respond incrementally with `Reply`\n- the server finishes the RPC call with a `Complete`\n\n```\nclient                                                         server\n    ------------------------subscribe---------------------------\u003e\n    - - - - - - - - - - - - -supply - - - - - - - - - - - - - - \u003e\n    \u003c - - - - - - - - - - - -reply- - - - - - - - - - - - - - - -\n    \u003c-----------------------complete-----------------------------\n```\n\nif the `supply` and `reply` parts were ommitted, it would be identical to a traditional RPC mechanism.\n\n\n### Example\n\n```haskell\nimport Network.WebSockets.RPC\nimport Data.Aeson\n\n-- subscriptions from client to server\ndata MySubDSL = Foo\n  deriving (FromJSON, ToJSON) -- you should figure this part out :)\n\n-- supplies from client to server\ndata MySupDSL = Bar\n  deriving (FromJSON, ToJSON)\n\n-- replies from server to client\ndata MyRepDSL = Baz\n  deriving (FromJSON, ToJSON)\n\n-- onCompletes from server to client\ndata MyComDSL = Qux\n  deriving (FromJSON, ToJSON)\n```\n\n\nServer:\n\n```haskell\n{-# LANGUAGE NamedFieldPuns, ScopedTypeVariables #-}\n\n\nmyServer :: (MonadIO m, MonadThrow m) =\u003e ServerAppT (WebSocketServerRPCT MySubDSL MySupDSL m)\nmyServer = rpcServer $ \\RPCServerParams{reply,complete} eSubSup -\u003e case eSubSup of\n  Left Foo -\u003e do\n    forM_ [1..5] $ \\_ -\u003e do\n      liftIO $ threadDelay 1000000\n      reply Baz\n    complete Qux\n  Right Bar -\u003e reply Baz\n```\n\nClient:\n\n```haskell\n{-# LANGUAGE NamedFieldPuns #-}\n\n\nmyClient :: (MonadIO m, MonadThrow m) =\u003e ClientAppT (WebSocketClientRPCT MyRepDSL MyComDSL m) ()\nmyClient = rpcClient $ \\dispatch -\u003e\n  -- only going to make one RPC call for this example\n  dispatch RPCClient\n    { subscription = Foo\n    , onReply = \\RPCClientParams{supply,cancel} Baz -\u003e do\n        liftIO $ threadDelay 1000000\n        supply Bar\n        (q :: Bool) \u003c- liftIO getRandom\n        if q then cancel else pure ()\n    , onComplete = \\Qux -\u003e liftIO $ putStrLn \"finished\"\n    }\n```\n\n\u003e the `threadDelay` calls are just to exemplify the asynchronisity of the system, nothing to do with avoiding race conditions \u003e.\u003e\n\n\nTo turn the `ServerAppT` and `ClientAppT` into natural [WebSockets](https://hackage.haskell.org/package/websockets)\ntypes, use the morphisms from [Wai-Transformers](https://hackage.haskell.org/package/wai-trasformers).\n\n\n## Contributing\n\nthis is my swamp\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fathanclark%2Fwebsockets-rpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fathanclark%2Fwebsockets-rpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fathanclark%2Fwebsockets-rpc/lists"}