{"id":22549141,"url":"https://github.com/datl4g/klient2klient","last_synced_at":"2026-03-09T17:45:26.971Z","repository":{"id":47899906,"uuid":"465054141","full_name":"DatL4g/Klient2Klient","owner":"DatL4g","description":"Discover devices in your network and create a connection between them to send data","archived":false,"fork":false,"pushed_at":"2024-11-16T18:08:06.000Z","size":145,"stargazers_count":21,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-10T01:59:40.560Z","etag":null,"topics":["java","kotlin","library","multiplatform","p2p"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DatL4g.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"DatL4g","patreon":"datlag","custom":["paypal.me/datlag"]}},"created_at":"2022-03-01T20:57:38.000Z","updated_at":"2024-11-16T18:08:10.000Z","dependencies_parsed_at":"2025-04-10T01:52:57.167Z","dependency_job_id":"30891091-abe2-458a-8b89-9694fdeca031","html_url":"https://github.com/DatL4g/Klient2Klient","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/DatL4g/Klient2Klient","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DatL4g%2FKlient2Klient","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DatL4g%2FKlient2Klient/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DatL4g%2FKlient2Klient/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DatL4g%2FKlient2Klient/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DatL4g","download_url":"https://codeload.github.com/DatL4g/Klient2Klient/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DatL4g%2FKlient2Klient/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30305301,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T17:35:44.120Z","status":"ssl_error","status_checked_at":"2026-03-09T17:35:43.707Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":["java","kotlin","library","multiplatform","p2p"],"created_at":"2024-12-07T16:07:58.428Z","updated_at":"2026-03-09T17:45:26.958Z","avatar_url":"https://github.com/DatL4g.png","language":"Kotlin","funding_links":["https://github.com/sponsors/DatL4g","https://patreon.com/datlag","paypal.me/datlag","https://github.com/sponsors/DATL4G","https://paypal.me/datlag","https://www.patreon.com/datlag"],"categories":[],"sub_categories":[],"readme":"# Klient2Klient\n\n### Kotlin Multiplatform\n\nThis is a Kotlin Multiplatform project, however it is implemented and works ONLY on JVM right now.\nThis means any JVM project/platform can use this library, so Android and Java Desktop/Server applications can run it.\n\n[![Issues](https://img.shields.io/github/issues/DATL4G/Klient2Klient.svg?style=for-the-badge)](https://github.com/DATL4G/Klient2Klient/issues)\n[![Stars](https://img.shields.io/github/stars/DATL4G/Klient2Klient.svg?style=for-the-badge)](https://github.com/DATL4G/Klient2Klient)\n[![Forks](https://img.shields.io/github/forks/DATL4G/Klient2Klient.svg?style=for-the-badge)](https://github.com/DATL4G/Klient2Klient/network/members)\n[![Contributors](https://img.shields.io/github/contributors/DATL4G/Klient2Klient.svg?style=for-the-badge)](https://github.com/DATL4G/Klient2Klient/graphs/contributors)\n[![License](https://img.shields.io/github/license/DATL4G/Klient2Klient.svg?style=for-the-badge)](https://github.com/DATL4G/Klient2Klient/blob/master/LICENSE)\n\n![Kotlin](https://img.shields.io/badge/kotlin-%230095D5.svg?style=for-the-badge\u0026logo=kotlin\u0026logoColor=white)\n![IntelliJ IDEA](https://img.shields.io/badge/IntelliJIDEA-000000.svg?style=for-the-badge\u0026logo=intellij-idea\u0026logoColor=white)\n\n### Discover and create Peer to Peer connections easily\n\n- Discover hosts in the same network\n- Connect and transfer data among clients\n\n### Table of contents\n\n- [Usage](#usage)\n- [Discovery](#discovery)\n  - [Make discoverable](#make-discoverable-can-be-found-by-other-hosts)\n  - [Start discovery](#start-discovery-find-other-hosts)\n  - [Get the found hosts](#get-the-found-hosts)\n- [Connection](#connection)\n  - [Start/Stop Receiving](#startstop-receiving)\n  - [Send/Collect data](#sendcollect-data)\n- [Contributing](#contributing)\n  - [Maintainers](#maintainers)\n- [Support the project](#support-the-project)\n\n## Usage\n\nAdd the JitPack repository to your build file\n\n```gradle\nallprojects {\n  repositories {\n    ...\n    maven { url = uri(\"https://jitpack.io\") }\n  }\n}\n```\n\nAdd the dependency\n\n```gradle\nimplementation(\"com.github.DatL4g:Klient2Klient:$latestVersion\")\n```\n\n## Discovery\n\nThe discovery relies on a builder and provides the following options\n\n- ```setDiscoveryTimeout(milliSecondsOrDuration)``` after which time it stops discovering (searching for other hosts)\n- ```setDiscoveryTimeoutListener{ }``` called in IO dispatcher but is a suspend function, so you can switch context easily\n- ```setDiscoverableTimeout(milliSecondsOrDuration)``` after which time it stops broadcasting to other hosts (cannot be discovered anymore)\n- ```setDiscoverableTimeoutListener{ }``` called in IO dispatcher but is a suspend function, so you can switch context easily\n- ```setPing(milliSecondsOrDuration)``` at which interval it broadcasts to other hosts\n- ```setPuffer(milliSecondsOrDuration)``` tolerance in which time the hosts need to ping again (since it's UDP, packages may be lost or not sent)\n- ```setPort(int)``` on which port to broadcast and listen\n- ```setHostFilter(regex)``` the discovered hosts need to match this (keep empty (and filterMatch in Host) for any or change the regex to \".*\")\n- ```setScope(coroutineScope)``` change the scope in which the discovery jobs are running in\n- ```setHostIsClient(boolean)``` whether the current host should be discovered ass a client too (default off)\n- ```build()``` create an instance of Discovery\n\nThe builder can be called using two different methods.\n\n```kotlin\nval discover = Discovery.Builder(coroutineScope /* optional */)\n  .setPort(1337)\n  .otherBuilderMethods()\n  .build()\n```\n\n```kotlin\nval discover = coroutineScope.discovery {\n  setPort(1337)\n  otherBuilderMethods()\n}\n```\n\n### Make discoverable (can be found by other hosts)\n\nBasically the host holds three parameter\n\n- name: the name of the host\n- filterMatch: the String to match the hostFilter regex\n- optionalInfo: any JsonElement\n\nCall any of the following methods:\n\n```kotlin\ndiscover.makeDiscoverable(Host(\"name\", \"filterMatch\" /* optional */, jsonElement /* optional */))\n```\n\n```kotlin\ndiscover.makeDiscoverable(\"name\", \"filterMatch\" /* optional */, jsonElement /* optional */)\n```\n\n```kotlin\ndiscover.makeDiscoverable(\"name\", \"filterMatch\" /* optional */, \"{jsonString: true}\" /* optional */)\n```\n\nTo stop being discoverable imply call\n\n```kotlin\ndiscover.stopBeingDiscoverable()\n```\n\n### Start discovery (find other hosts)\n\n```kotlin\ndiscover.startDiscovery()\n//or\ndiscover.startDiscovery(hostIsClient)\n```\n\nTo stop discovery simply call\n\n```kotlin\ndiscover.stopDiscovery()\n```\n\n### Get the found hosts\n\nTo get the current list of found hosts synchronously use:\n\n```kotlin\nval setOfHosts = discover.peers\n```\n\nThe host list can be collected to always get the latest items\n\n```kotlin\ndiscover.peersFlow.collect { hosts -\u003e\n  // got new hosts\n}\n```\n\n## Connection\n\nThe connection relies on a builder as well with these options:\n\n- ```fromDiscovery(discover)``` just to pass the peers\n- ```forPeers(setOfHosts)``` pass the peers yourself\n- ```forPeer(host)``` only connect to one host\n- ```setPort(int)``` the port on which the connection will be established\n- ```setScope(coroutineScope)``` change the scope in which the connection jobs are running in\n- ```build()``` create an instance of Connection\n\nThe builder can be used two different ways again:\n\n```kotlin\nval connect = Connection.Builder(coroutineScope /* optional */)\n  .fromDiscovery(discover)\n  .setPort(7331)\n  .build()\n```\n\n```kotlin\nval connect = coroutineScope.connection {\n  fromDiscovery(discover)\n  setPort(7331)\n}\n```\n\n### Start/Stop Receiving\n\nTo start receiving just call, this will allow to get data from another host\n\n```kotlin\n  connect.startReceiving()\n```\n\nStopping is as easy as starting\n\n```kotlin\n  connect.stopReceiving()\n```\n\n### Send/Collect data\n\nTo send data to all connected hosts use\n\n```kotlin\n  connect.send(bytes)\n```\n\nTo send data to one host only use\n\n```kotlin\n  connect.send(bytes, host)\n```\n\nCollecting data can be done using Flows again\n\n```kotlin\n  connect.receiveData.collect { pair: Pair\u003cHost, ByteArray\u003e -\u003e\n    // received data from another host\n  }\n```\n\n## Contributing\n\nWhen you face any bugs or problems please open an [Issue](https://github.com/DATL4G/Klient2Klient/issues/new/choose).\n\nTo add functionality fork the project and create a pull request afterwards. You should know how that works if you are a developer :)\nYou can add yourself to the list below if you want then.\n\n### Maintainers\n\n| Avatar | Contributor |\n|---|:---:|\n| [![](https://avatars3.githubusercontent.com/u/46448715?s=50\u0026v=4)](http://github.com/DatL4g) | [DatLag](http://github.com/DatL4g) |\n\n## Support the project\n\n[![Github-sponsors](https://img.shields.io/badge/sponsor-30363D?style=for-the-badge\u0026logo=GitHub-Sponsors\u0026logoColor=#EA4AAA)](https://github.com/sponsors/DATL4G)\n[![PayPal](https://img.shields.io/badge/PayPal-00457C?style=for-the-badge\u0026logo=paypal\u0026logoColor=white)](https://paypal.me/datlag)\n[![Patreon](https://img.shields.io/badge/Patreon-F96854?style=for-the-badge\u0026logo=patreon\u0026logoColor=white)](https://www.patreon.com/datlag)\n\nSupporting this project helps to keep it up-to-date. You can donate if you want or contribute to the project as well.\nThis shows that the library is used by people and it's worth to maintain.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatl4g%2Fklient2klient","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdatl4g%2Fklient2klient","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatl4g%2Fklient2klient/lists"}