{"id":20310812,"url":"https://github.com/progrium/duplex","last_synced_at":"2025-10-07T22:49:38.075Z","repository":{"id":4361060,"uuid":"5497369","full_name":"progrium/duplex","owner":"progrium","description":"Full duplex modern RPC","archived":false,"fork":false,"pushed_at":"2021-05-06T17:53:05.000Z","size":821,"stargazers_count":390,"open_issues_count":8,"forks_count":33,"subscribers_count":29,"default_branch":"master","last_synced_at":"2025-09-30T15:06:42.830Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://progrium.viewdocs.io/duplex/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/progrium.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":"2012-08-21T15:57:07.000Z","updated_at":"2025-05-26T16:23:17.000Z","dependencies_parsed_at":"2022-08-28T21:40:27.508Z","dependency_job_id":null,"html_url":"https://github.com/progrium/duplex","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/progrium/duplex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/progrium%2Fduplex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/progrium%2Fduplex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/progrium%2Fduplex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/progrium%2Fduplex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/progrium","download_url":"https://codeload.github.com/progrium/duplex/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/progrium%2Fduplex/sbom","scorecard":{"id":746233,"data":{"date":"2025-08-11","repo":{"name":"github.com/progrium/duplex","commit":"d076a972fc21e19dff1f0a619e29dc6c5b25cc1f"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Code-Review","score":0,"reason":"Found 2/24 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 8 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"13 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-8w4h-3cm3-2pm2","Warn: Project is vulnerable to: GHSA-qh2h-chj9-jffq","Warn: Project is vulnerable to: GHSA-jf85-cpcp-j695","Warn: Project is vulnerable to: GHSA-fvqr-27wr-82fm","Warn: Project is vulnerable to: GHSA-4xc9-xhrj-v574","Warn: Project is vulnerable to: GHSA-x5rq-j2xg-h7qm","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-hxm2-r34f-qmc5","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-cf4h-3jhx-xvhq"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T18:50:23.441Z","repository_id":4361060,"created_at":"2025-08-22T18:50:23.441Z","updated_at":"2025-08-22T18:50:23.441Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278861030,"owners_count":26058632,"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","status":"online","status_checked_at":"2025-10-07T02:00:06.786Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-11-14T17:34:37.258Z","updated_at":"2025-10-07T22:49:38.056Z","avatar_url":"https://github.com/progrium.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# Duplex RPC\n\nModern full-duplex RPC\n\n * Serialization and transport agnostic\n * Client and server combined into Peer object\n * Calls and callbacks in either direction\n * Optional streaming of results and arguments\n * Extensible with middleware (soon)\n * Easy to implement protocol and API\n * Ready-to-go implementations\n   * Go\n   * Python 3\n   * JavaScript (Node.js and browser)\n   * TODO: Ruby?\n\n## Getting Started\n\n * [with Python](http://progrium.viewdocs.io/duplex/getting-started/python)\n * with Go\n * with JavaScript\n\n## Tour\n\n### Language and serialization agnostic\n\nDuplex is an RPC protocol designed for dynamic (and some statically-typed) languages that focuses on advanced RPC semantics and not object or frame serialization. This lets you pick how to marshal objects, whether with JSON, msgpack, protobuf, BERT, BSON, or anything custom.\n\n```javascript\n// rpc setup using json\n```\n\n```golang\n// rpc setup using gob\n```\n\n### API combines client and server into \"peer\"\n\nWhile that alone is somehow already revolutionary for RPC protocols, it also combines client and server into a peer object, letting either side of the connection call or provide invocable service methods. This means you never have to worry about only having a client or only having a server library in your language. It also allows for flexible connection topologies (server calling client functions), callbacks, and plugin architectures.\n\n```python\n# server with methods connects to client\n```\n\n```javascript\n// method gets a callback and calls back to the client\n```\n\n### Bi-directional object streaming\n\nMethods can also stream multiple results *and* accept multiple streaming arguments, letting you use Duplex for bi-directional object streaming. Among other patterns, this lets you implement real-time data synchronization, connection tunneling, and interactive consoles, all with the same mechanism as simple remote method calls.\n\n```golang\n// calls an interactive method, attaches to terminal\n```\n\n```ruby\n# call to subscribe to updates\n```\n\n### Simple, extensible API and protocol\n\nDuplex has a simple protocol spec not much more complex than JSON-RPC. It also has an API guide that can be used for easy and consistent implementations in various languages.\n\nThe protocol and API are also designed to eventually be extensible. Expect a middleware mechanism that lets you add tracing, authentication, policy, transactions, and more. This allows Duplex to remain simple but powerful.\n\n### Transport agnostic, frame interface\n\nThe API design has a simple framed transport interface. This means out of the box you can expect to use any transport that takes care of framing, for example WebSockets, UDP, ZeroMQ, AMQP. Wrapping streaming transports such as raw TCP or STDIO with length-prefix or newline framing lets you use them as well. By focusing on frames and making the API transport agnostic, as well as being serialization agnostic, implementations are very simple with no major dependencies.\n\n\n\n# TODO\n\n * document spec / api\n * demo\n   * cross language, browser\n   * topologies: client-server, server-client, gateway\n   * transports: websocket, tcp, UDP\n   * codecs: json, msgpack, protobuf\n   * streaming: state sync, terminal\n   * callbacks: async reply, events, plugins\n   * gateway: behind firewall, client to client (browser)\n   * patterns: identity, reflection (cli), self docs\n   * implementation: code tour, api guide, protocol spec\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprogrium%2Fduplex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprogrium%2Fduplex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprogrium%2Fduplex/lists"}