{"id":47983992,"url":"https://github.com/boranseckin/chord","last_synced_at":"2026-04-04T11:25:27.897Z","repository":{"id":51379106,"uuid":"362368907","full_name":"boranseckin/chord","owner":"boranseckin","description":"An implementation of Chord network using TypeScript","archived":false,"fork":false,"pushed_at":"2022-10-31T15:58:20.000Z","size":527,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-11T15:34:07.595Z","etag":null,"topics":["chord","docker","lookup-service","network","p2p","scalable","udp-sockets"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/boranseckin.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":"2021-04-28T06:57:27.000Z","updated_at":"2024-10-30T17:35:05.000Z","dependencies_parsed_at":"2023-01-20T14:33:19.037Z","dependency_job_id":null,"html_url":"https://github.com/boranseckin/chord","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/boranseckin/chord","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boranseckin%2Fchord","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boranseckin%2Fchord/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boranseckin%2Fchord/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boranseckin%2Fchord/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/boranseckin","download_url":"https://codeload.github.com/boranseckin/chord/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boranseckin%2Fchord/sbom","scorecard":{"id":248222,"data":{"date":"2025-08-11","repo":{"name":"github.com/boranseckin/chord","commit":"5f5672e972446901f5ad933eb41ad57556ff8d9d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.6,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/23 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":"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":"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":"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":"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":"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":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: containerImage not pinned by hash: Dockerfile:1","Warn: containerImage not pinned by hash: Dockerfile:10: pin your Docker image by updating node:current-alpine to node:current-alpine@sha256:e8e882c692a08878d55ec8ff6c5a4a71b3edca25eda0af4406e2a160d8a93cf2","Warn: npmCommand not pinned by hash: Dockerfile:5","Info:   0 out of   2 containerImage dependencies pinned","Info:   0 out of   1 npmCommand dependencies pinned"],"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":"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 9 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":"11 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-pfrx-2q88-qq97","Warn: Project is vulnerable to: GHSA-rc47-6667-2j5j","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7"],"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-17T07:58:41.664Z","repository_id":51379106,"created_at":"2025-08-17T07:58:41.665Z","updated_at":"2025-08-17T07:58:41.665Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31397615,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["chord","docker","lookup-service","network","p2p","scalable","udp-sockets"],"created_at":"2026-04-04T11:25:27.491Z","updated_at":"2026-04-04T11:25:27.877Z","avatar_url":"https://github.com/boranseckin.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# chord\n[![npm (scoped)](https://img.shields.io/npm/v/@boranseckin/chord?style=for-the-badge)](https://www.npmjs.com/package/@boranseckin/chord)\n![Dependencies](https://img.shields.io/badge/Dependencies-0-brightgreen?style=for-the-badge)\n[![Travis (.com)](https://img.shields.io/travis/com/boranseckin/chord?style=for-the-badge)](https://travis-ci.com/github/boranseckin/chord)\n[![Codecov](https://img.shields.io/codecov/c/github/boranseckin/chord?style=for-the-badge\u0026token=wq26EbilpW)](https://codecov.io/gh/boranseckin/chord)\n\nA Scalable Peer-to-peer Lookup Service for Internet Applications\n\nThis is an implementation of Chord network explained in this [paper](https://pdos.csail.mit.edu/papers/chord:sigcomm01/chord_sigcomm.pdf) using TypeScript. All the communication between nodes is handled using UDP sockets and the code is written asynchronously using promises to facilitate the high traffic of requests. This project only uses pure NodeJS and is dependency-free.\n\n#### [Demo Video](https://youtu.be/tf_3W5z0N-E)\n\n## Network\nIn the network, nodes constantly communicate with each other to make sure that their version of the network is up to date. Moreover, Chord network requires nodes to execute functions for other nodes remotely. This remote execution is essential for the network since every node only knows a few other nodes and they require other nodes to perform actions like lookups where they cannot reach.\n\nEvery node uses an IPv4 address and a port number to communicate with other nodes. All the messages are serialized and sent over UDP sockets. When a node sends a new message, it wraps it into a promise and passes a `promise id` that corresponds to the resolve/reject functions of the promise with the message. The receiver then can respond to this message using the supplied `promise id` and whether the response is positive or negative, the promise can be resolved or rejected. With this method, the network module never gets blocked and multiple messages can be sent to different nodes without waiting for a response.\n\nMost of the functions are written to handle both local and remote execution. If a function was called with a remote executer argument, the function gets forwarded to that executer and a promise is returned instead. Once the remote node finishes the execution, it sends the return value back to the original node and the promise gets resolved (or rejected) with that value.\n\n## Visualizer\nTo see the network clearly and admire its dynamic structure, a different module is built called [@boranseckin/chord-visualizer](https://github.com/boranseckin/chord-visualizer). Visualizer class inherits the node class to seamlessly send/receive messages. It is not a part of the network and it only uses the `getInfo` command to gather information about nodes.\n\nCollected data is shown as a graph on a simple web page that is periodically updated to reflect the changes on the network. The visualizer requires an anchor node to start crawling a network. If the anchor node is lost, it will try to use a previously-found node to replace its place.\n\n## Docker\nAfter a long struggle, this project is fully dockerized. Both [boranseckin/chord](https://hub.docker.com/r/boranseckin/chord) and [boranseckin/chord-visualizer](https://hub.docker.com/r/boranseckin/chord-visualizer) can be run as standalone containers. Additionally, [docker-compose](docker-compose.yml) file can be used to create and scale a fully functional Chord network (including a visualizer). When scaling, only make copies of the `node` service. There must be at most one `flare` and one `visualizer` services active at all times since they are staticly binded to specific ports.\n\n\n### Problems and Solutions\n\u003eTo create the network, a node must first enter and act as a flare to the rest.\n\nUsing the [boranseckin/chord](https://hub.docker.com/r/boranseckin/chord) image create two different services. The first one (`flare`) uses a static configuration and becomes the flare. The second one (`node`) depends on the first one and scales the network using the configuration of the `flare`.\n\n\u003eWhen adding a new node (automatically scaling), its IPv4 address is not known yet. So it can't be supplied as an environmental variable.\n\nDo not specifiy the address and let the node find figure it out instead using `os` module. This is a workaround and only works if the interface is called `eth0` like it is in docker containers.\n\n\u003eNodeJS `dgram` module does not like Dynamic DNS as an address.\n\nIn a custom network, containers can use their names as DDNS to communicate with each other. Since `dgram` module requires IPv4 addresses, use `dns` module to lookup IPv4 equivalent of the DDNS.\n\n\u003eEach node requires a **unique** ID but used IDs are not known during scaling.\n\nWhen using `docker-compose` each new container is assigned a unique id as an extension to its name. However, for some reason, these names are not easily accessible from inside the container. To get container information, [Docker Engine API](https://docs.docker.com/engine/api/) must be exposed to each node. During startup, a [shell script](docker-start.sh) is run to digest the data and export an ID for the node. Exposing the API is sub-optimal but a necessity in this case.\n\n## References\n- [Sigcomm Paper](https://pdos.csail.mit.edu/papers/chord:sigcomm01/chord_sigcomm.pdf) by Ion Stoica, Robert Morris, David Karger, M. Frans Kaashoek and Hari Balakrishna\n- [Wikipedia Page](https://en.wikipedia.org/wiki/Chord_(peer-to-peer))\n- [chord-gRPC](https://github.com/bushidocodes/chord-grpc) by bushidocodes\n- [Presentation](https://www.kth.se/social/upload/51647996f276545db53654c0/3-chord.pdf) by Amir H. Payberah and Jim Dowling\n\n## Author\n- Boran Seckin\n\n## License\nThis project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboranseckin%2Fchord","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fboranseckin%2Fchord","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboranseckin%2Fchord/lists"}