{"id":20059565,"url":"https://github.com/monix/monix-nio","last_synced_at":"2025-05-05T15:31:47.249Z","repository":{"id":46420922,"uuid":"77034504","full_name":"monix/monix-nio","owner":"monix","description":"Java NIO utilities for usage with Monix","archived":false,"fork":false,"pushed_at":"2021-10-14T21:59:00.000Z","size":301,"stargazers_count":52,"open_issues_count":4,"forks_count":11,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-03-26T14:28:55.939Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Scala","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/monix.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-12-21T08:49:58.000Z","updated_at":"2024-03-26T14:28:55.940Z","dependencies_parsed_at":"2022-09-13T05:51:35.152Z","dependency_job_id":null,"html_url":"https://github.com/monix/monix-nio","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monix%2Fmonix-nio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monix%2Fmonix-nio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monix%2Fmonix-nio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monix%2Fmonix-nio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/monix","download_url":"https://codeload.github.com/monix/monix-nio/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224452805,"owners_count":17313668,"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":[],"created_at":"2024-11-13T13:08:23.354Z","updated_at":"2024-11-13T13:08:24.124Z","avatar_url":"https://github.com/monix.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# monix-nio\n\nJava NIO utilities for usage with Monix\n\n[![Build Status](https://travis-ci.org/monix/monix-nio.svg?branch=master)](https://travis-ci.org/monix/monix-nio)\n[![Coverage Status](https://codecov.io/gh/monix/monix-nio/coverage.svg?branch=master)](https://codecov.io/gh/monix/monix-nio?branch=master)\n\n\nJoin chat:\n[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/monix/monix?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\n## Overview\nMonix-nio can be used to have the power of Monix combined with underlying Java-nio libraries.\nFor the moment the following support has been added:\n\n- Read/Write async to a file (combined with utf8 encoding/decoding if necessary)\n- Read/Write async to TCP\n- File system watcher\n\n## Benchmarks\n\n```text\nBenchmark                                          Mode  Cnt     Score    Error  Units\nReadWriteFileBenchmark.read50MiB                     ss   40   191.350 ± 27.611  ms/op\nReadWriteFileBenchmark.read50MiBJavaNio              ss   40    59.288 ±  5.068  ms/op\nReadWriteFileBenchmark.read50MiBWith100KiBChunks     ss   40    44.501 ±  3.135  ms/op\nReadWriteFileBenchmark.read50MiBWith1KiBChunks       ss   40  1066.369 ± 43.585  ms/op\nReadWriteFileBenchmark.read50MiBWith1MiBChunks       ss   40    48.777 ±  3.725  ms/op\nReadWriteFileBenchmark.write50MiB                    ss   40   259.731 ± 10.388  ms/op\nReadWriteFileBenchmark.write50MiBJavaNio             ss   40   304.585 ± 15.283  ms/op\nReadWriteFileBenchmark.write50MiBWith100KiBChunks    ss   40   258.719 ± 20.431  ms/op\nReadWriteFileBenchmark.write50MiBWith1KiBChunks      ss   40  2414.812 ± 23.128  ms/op\nReadWriteFileBenchmark.write50MiBWith1MiBChunks      ss   40   255.028 ±  9.261  ms/op\n```\n- lower is better\n\n## Usage\n\n**WARNING:** Can break backwards compatibility!\n\n### Adding dependency to SBT\n\n```scala\nlibraryDependencies += \"io.monix\" %% \"monix-nio\" % \"0.1.0\"\n```\n\n### Read from a text file\n\n```scala\nimport monix.nio.text.UTF8Codec._\nimport monix.nio.file._\n  \nimplicit val ctx = monix.execution.Scheduler.Implicits.global\nval from = java.nio.file.Paths.get(\"/myFile.txt\")\n  \nreadAsync(from, 30)\n  .pipeThrough(utf8Decode) // decode utf8, If you need Array[Byte] just skip the decoding\n  .foreach(Console.print)  // print each char\n```\n\n### Write to a file\n\n```scala\nimport monix.reactive.Observable\nimport monix.nio.file._\n  \nimplicit val ctx = monix.execution.Scheduler.Implicits.global\nval to = java.nio.file.Paths.get(\"/out.txt\")\nval bytes = \"Hello world!\".getBytes.grouped(3)\n  \nObservable\n  .fromIterator(bytes)\n  .consumeWith(writeAsync(to))\n  .runAsync\n```\n\n### Copy a file (text with decode and encode utf8)\n\n```scala\nimport monix.eval.Callback\nimport monix.nio.text.UTF8Codec._\nimport monix.nio.file._\n  \nval from = java.nio.file.Paths.get(\"from.txt\")\nval to = java.nio.file.Paths.get(\"to.txt\")\n  \nval consumer = writeAsync(to)\n  \nval callback = new Callback[Long] {\n  override def onSuccess(value: Long): Unit = println(s\"Copied $value bytes.\")\n  override def onError(ex: Throwable): Unit = println(ex)\n}\nreadAsync(from, 3)\n  .pipeThrough(utf8Decode)\n  .map { str =\u003e\n    Console.println(str) // do something with it\n    str\n  }\n  .pipeThrough(utf8Encode)\n  .consumeWith(consumer)\n  .runAsync(callback)\n```\n\n### File system watcher\n```scala\nimport java.nio.file.{ Paths, WatchEvent }\nimport monix.nio.file._\n  \nimplicit val ctx = monix.execution.Scheduler.Implicits.global\n  \nval path = Paths.get(\"/tmp\")\n  \ndef printEvent(event: WatchEvent[_]): Unit = {\n  val name = event.context().toString\n  val fullPath = path.resolve(name)\n  println(s\"${event.kind().name()} - $fullPath\")\n}\n  \nwatchAsync(path)\n  .foreach(p =\u003e p.foreach(printEvent))\n```\n\n### Read from TCP\n```commandline\n$ echo 'monix-tcp' | nc -l -k 9000\n```\n```scala\nimport monix.reactive.Consumer\nimport monix.nio.tcp._\n  \nimplicit val ctx = monix.execution.Scheduler.Implicits.global\n  \nval callback = new monix.eval.Callback[Unit] {\n  override def onSuccess(value: Unit): Unit = println(\"Completed\")\n  override def onError(ex: Throwable): Unit = println(ex)\n}\nreadAsync(\"localhost\", 9000)\n  .consumeWith(Consumer.foreach(c =\u003e Console.out.print(new String(c))))\n  .runAsync(callback)\n```\n\n### Write to TCP\n```commandline\n$ nc -l -k 9000\n```\n```scala\nimport monix.reactive.Observable\nimport monix.nio.tcp._\n  \nimplicit val ctx = monix.execution.Scheduler.Implicits.global\n  \nval tcpConsumer = writeAsync(\"localhost\", 9000)\nval chunkSize = 2\n  \nval callback = new monix.eval.Callback[Long] {\n  override def onSuccess(value: Long): Unit = println(s\"Sent $value bytes.\")\n  override def onError(ex: Throwable): Unit = println(ex)\n}\nObservable\n  .fromIterator(\"Hello world!\".getBytes.grouped(chunkSize))\n  .consumeWith(tcpConsumer)\n  .runAsync(callback)\n```\n\n### Create a TCP server and/or client (TCP server-client echo example)\n```scala\nimport monix.reactive.Observable\nimport monix.eval. { Callback, Task }\nimport monix.execution.Ack.Continue\nimport monix.nio.tcp._\n  \nimplicit val ctx = monix.execution.Scheduler.Implicits.global\n  \nval serverProgramT = for {\n  server \u003c- asyncServer(java.net.InetAddress.getByName(null).getHostName, 9001)\n  socket \u003c- server.accept()\n  \n  conn \u003c- Task.now(readWriteAsync(socket))\n  reader \u003c- conn.tcpObservable\n  writer \u003c- conn.tcpConsumer\n  \n  echoedLen \u003c- reader.doOnTerminateEval(_ =\u003e conn.stopWriting()).consumeWith(writer)\n  _ \u003c- conn.close()\n  _ \u003c- server.close()\n} yield {\n  echoedLen\n}\n  \nval client = readWriteAsync(\"localhost\", 9001, 256 * 1024)\nval clientProgramT = for {\n  writer \u003c- client.tcpConsumer\n  _ \u003c- Observable.fromIterable(Array(\"Hello world!\".getBytes())).consumeWith(writer)\n  _ \u003c- client.stopWriting()\n  reader \u003c- client.tcpObservable\n  _ \u003c- Task.now(reader\n    .doOnTerminateEval(_ =\u003e client.close())\n    .subscribe(\n      bytes =\u003e { \n        println(new String(bytes))\n        Continue \n      },\n      err =\u003e println(err),\n      () =\u003e println(\"Echo received.\")\n    ))\n} yield {}\n  \nserverProgramT.runAsync(new Callback[Long] {\n  override def onSuccess(value: Long): Unit = println(s\"Echoed $value bytes.\")\n  override def onError(ex: Throwable): Unit = println(ex)\n})\nclientProgramT.runAsync\n```\n\n### Make a raw HTTP request\n```scala\nimport monix.reactive.Observable\nimport monix.eval.Callback\nimport monix.nio.tcp._\n  \nimplicit val ctx = monix.execution.Scheduler.Implicits.global\n  \nval asyncTcpClient = readWriteAsync(\"httpbin.org\", 80, 256 * 1024)\nval request = \n  \"GET /get?tcp=monix HTTP/1.1\\r\\nHost: httpbin.org\\r\\nConnection: keep-alive\\r\\n\\r\\n\"\n   \nval callbackR = new Callback[Unit] {\n  override def onSuccess(value: Unit): Unit = println(\"OK\")\n  override def onError(ex: Throwable): Unit = println(ex)\n}\nasyncTcpClient\n  .tcpObservable\n  .map { reader =\u003e\n    reader\n    .doOnTerminateEval(_ =\u003e asyncTcpClient.close()) // clean\n    .subscribe(\n      (bytes: Array[Byte]) =\u003e {\n        println(new String(bytes, \"UTF-8\"))\n        monix.execution.Ack.Stop \n      },\n      err =\u003e println(err),\n      () =\u003e println(\"Completed\")\n    )\n    ()\n  }\n  .runAsync(callbackR)\n  \nval callbackW = new Callback[Long] {\n  override def onSuccess(value: Long): Unit = println(s\"Sent $value bytes\")\n  override def onError(ex: Throwable): Unit = println(ex)\n}   \nasyncTcpClient\n  .tcpConsumer\n  .flatMap { writer =\u003e\n    val data = request.getBytes(\"UTF-8\").grouped(256 * 1024).toArray\n    Observable\n      .fromIterable(data)\n      .consumeWith(writer)\n  }\n  .runAsync(callbackW)\n```\n\n## Maintainers\n\nThe current maintainers (people who can help you) are:\n\n- Sorin Chiprian ([@creyer](https://github.com/creyer))\n- Alexandru Nedelcu ([@alexandru](https://github.com/alexandru))\n- Radu Gancea ([@radusw](https://github.com/radusw))\n\n## Contributing\n\nThe Monix project welcomes contributions from anybody wishing to\nparticipate.  All code or documentation that is provided must be\nlicensed with the same license that Monix is licensed with (Apache\n2.0, see LICENSE.txt).\n\nPeople are expected to follow the\n[Typelevel Code of Conduct](http://typelevel.org/conduct.html) when\ndiscussing Monix on the Github page, Gitter channel, or other venues.\n\nFeel free to open an issue if you notice a bug, have an idea for a\nfeature, or have a question about the code. Pull requests are also\ngladly accepted. For more information, check out the\n[contributor guide](CONTRIBUTING.md).\n\n## License\n\nAll code in this repository is licensed under the Apache License,\nVersion 2.0.  See [LICENCE.txt](./LICENSE.txt).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonix%2Fmonix-nio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmonix%2Fmonix-nio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonix%2Fmonix-nio/lists"}