Giter VIP home page Giter VIP logo

zio-nio's Introduction

ZIO-NIO

Project Stage CI Release Snapshot Discord
Project stage CI Release Artifacts Snapshot Artifacts badge-discord

ZIO interface to Java NIO.

Java NIO is unsafe, and can surprise you a lot with e.g. hiding the actual error in IO operation and giving you only true/false values when IO was successful/not successful. ZIO-NIO on the other hand embraces the full power of ZIO effects, environment, error and resource management to provide type-safe, performant, purely-functional, low-level, and unopinionated wrapping of Java NIO functionality.

ZIO-NIO comes in two flavours:

  • zio.nio.core - a small and unopinionated ZIO interface to NIO that just wraps NIO API in ZIO effects,
  • zio.nio - an opinionated interface with deeper ZIO integration that provides more type and resource safety.

Learn more about ZIO-NIO at:

Background

zio-nio's People

Contributors

adamgfraser avatar akaczynski-scalac avatar al333z avatar azanin avatar darkiri avatar denisgarci avatar egorkulbachka avatar ioleo avatar ithinkicancode avatar jczuchnowski avatar jdegoes avatar lukasgasior1 avatar mijicd avatar mschuwalow avatar mtsokol avatar oranda avatar pgabara avatar pierangeloc avatar pshemass avatar quelgar avatar renovate[bot] avatar scala-steward avatar sideeffffect avatar sinoz avatar softinio avatar svroonland avatar toxicafunk avatar vasilmkd avatar xuwei-k avatar ysusuk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

zio-nio's Issues

Mutex for ServerSocketChannel#accept and Channel#write / Channel#read

Per https://docs.oracle.com/javase/7/docs/api/java/nio/channels/AsynchronousSocketChannel.html and related docs all of these are unsafe to read / write from concurrently. Currently we don't assist the user with this, and leave them on their own to respect that part of the api.

An alternative approach would be to embed a semaphores in the managed resources that we return.
This would make sure that only one concurrent read / write ever happens.
This of course will have a slight performance penalty in comparison to the current situation, but I believe it is more in line with our policy to provide functionality that makes it hard to shoot yourself in the foot with.

WDYT?

/cc @iravid @pshemass @mijicd

Add test coverage plugin

This is a one-liner to be added to plugins.sbt:

addSbtPlugin("org.scoverage"                     % "sbt-scoverage"                 % "1.6.1")

I think most ZIO projects have this now. It generates nice reports. To run:

sbt clean coverage test coverageReport

channel.read has side effect without type representation

I talk from zio.nio part of the lib (not core)
If i understand correclty, channel.read

def f(channel: AsynchronousSocketChannel) = {
   val _first3: IO[Exception, Chunk[Byte]] = channel.read(3)
   val _second3: IO[Exception, Chunk[Byte]] = channel.read(3)
}

read 3 first byte of the buffer link to the channel, and if we redo channel.read(3) that read the next 3 byte of the buffer for this channel right ?

From a FP/ZIO point of view is it not a huge issue ?

How can I simply perform for example, an recursive/fold read of the channel with chunk of byte ?
What i mean, i have channel with X bytes, i decide to use 80 byte buffer, to be sure i read all, i need to iterate on my channel until it say me "ok you read all" (equivalent to buffer return -1).

Refactor tests

Most of the tests use assertions of the following form assert(predicate)(isTrue). While this is certainly a possible thing to do, we should consider utilizing the full power of zio-test.

DatagramChannel wrapper

Provide a ZIO-friendly wrapping of the DatagramChannel, at least those parts that could be useful to a ZIO program.

This will let us implement UDP transport in zio-keeper

Use ZManaged for resource management

Many NIO objects require strict lifecycle management using error-prone methods like close and release, it would be great to use ZManaged for these and remove all such close methods.

TODO:

  • AsynchronousByteChannel
  • AsynchronousSocketChannel
  • AsynchronousServerSocketChannel
  • AsynchronousFileChannel
  • FileChannel
  • GatheringByteChannel
  • ScatteringByteChannel
  • SelectableChannel
  • Selector

Upgrade to ZIO 2.0

ZIO is at Milestone 4, with an RC expected in the next few weeks.
https://github.com/zio/zio/releases/tag/v2.The API is nearly stable at this point, so any early migration work against this version should pay off towards the official 2.0 release.

The progress is being tracked here:
zio/zio#5470

The Stream Encoding work in progress is the only area where the API might still change before the RC.

To assist with the migration, follow this guide:
https://zio.dev/howto/migrate/zio-2.x-migration-guide/

We are actively working on a ScalaFix rule that will cover the bulk of the simple API changes:
https://github.com/zio/zio/blob/series/2.x/scalafix/rules/src/main/scala/fix/Zio2Upgrade.scala

If you would like assistance with the migration from myself or other ZIO contributors, please let us know!

Concurrent file write causes content overlap

I have developed an app, which executes a few heavy queries, which yield a lot of data so I decided to write the query results to multiple files concurrently.

I create a FileChannel for each separate query and write the results concurrently.

    def acquireOutputStream(path: Path) = ZIO.acquireRelease(FileChannel.open(path, options: _*)) { stream =>
      stream.flatMapBlocking(_.force(metadata = true)).orDie *>
        stream.close.orDie
    }

    // Writes data to file 
    def writeStream(stream: Stream[Throwable, Result], os: FileChannel) = ???

    def runQuery(query: String, path: Path): RIO[DatabaseProvider, Path] = ZIO.scoped {
        acquireOutputStream(path).flatMap { os =>
            ZIO.fromStreamingDBIO(SQLActionBuilder(query, (_, _) => ()).as[Result]).map(writeStream(_, os)).runDrain
        }
    }

   // Some code
   val concurrentQueries: List[RIO[DatabaseProvider, Path]] = ???

   ZIO.collectAllPar(concurrentQueries)

When I execute the code sequentially, everything works as expected (using ZIO.collectAll), but once I use ZIO.collectAllPar, content from one file can appear in the other.

The question is: even though I do not leak FileChannel anywhere, the content from one file can appear in there other (they will be mixed together as if a few streams use the same FileChannel), how can it be fixed?

Thanks for help in advance!

Split ZIO-NIO into two submodules

Because of the growing desire to improve the NIO API and make it more ZIO-native, the idea appeared to split the project into two submodules:

  • zio-nio-core - an unopinionated wrapper on Java NIO (in line with the original project intention)
  • zio-nio - opinionated improvements on zio-nio-core exploring full potential of ZIO (eg. extensive usage of ZManaged)

Some parts are already opinionated and need to be "downgraded" in zio-nio-core:

  • AsynchronousChannnel
  • AsynchronousChannnelGroup
  • AsynchronousFileChannel
  • DatagramChannel
  • FileChannel
  • SelectableChannel
  • file/ package

Fix failing tests

Currently, the tests are failing with the following error:

[info] Running zio.nio.Main                                                                                                                                          [203/539]
Fiber failed.                                                                                                                                                                 
A checked error was not handled.                                                                                                                                              
java.lang.NullPointerException                                                                                                                                                
        at zio.nio.channels.AsynchronousChannelGroup.$anonfun$awaitTermination$1(AsynchronousChannelGroup.scala:44)                                                           
        at scala.runtime.java8.JFunction0$mcZ$sp.apply(JFunction0$mcZ$sp.java:23)                                                                                             
        at zio.internal.FiberContext.evaluateNow(FiberContext.scala:410)                                                                                                      
        at zio.Runtime.unsafeRunAsync(Runtime.scala:93)                                                                                                                       
        at zio.Runtime.unsafeRunAsync$(Runtime.scala:79)                                                                                                                      
        at zio.nio.AsynchronousChannelGroupSuite$.unsafeRunAsync(AsynchronousChannelGroupSuite.scala:17)                                                                      
        at zio.Runtime.unsafeRunSync(Runtime.scala:68)                                                                                                                        
        at zio.Runtime.unsafeRunSync$(Runtime.scala:65)                                                                                                                       
        at zio.nio.AsynchronousChannelGroupSuite$.unsafeRunSync(AsynchronousChannelGroupSuite.scala:17)                                                                       
        at zio.nio.AsynchronousChannelGroupSuite$.$anonfun$tests$9(AsynchronousChannelGroupSuite.scala:74)                                                                    
        at org.specs2.matcher.Expectable.value$lzycompute(Expectable.scala:21)                                                                                                
        at org.specs2.matcher.Expectable.value(Expectable.scala:21)                                                                                                           
        at org.specs2.matcher.OptionLikeMatcher.$anonfun$apply$7(OptionMatchers.scala:69)                                                                                     
        at org.specs2.matcher.Matcher.result(Matcher.scala:44)                                                                                                                
        at org.specs2.matcher.Matcher.result$(Matcher.scala:43)                                                                                                               
        at org.specs2.matcher.OptionLikeMatcher.result(OptionMatchers.scala:67)                                                                                               
        at org.specs2.matcher.OptionLikeMatcher.apply(OptionMatchers.scala:69)                                                                                                
        at org.specs2.matcher.Expectable.applyMatcher(Expectable.scala:51)                                                                                                    
        at org.specs2.matcher.MustExpectable.must(MustExpectable.scala:16)                                                                                                    
        at zio.nio.AsynchronousChannelGroupSuite$.$anonfun$tests$8(AsynchronousChannelGroupSuite.scala:75)                                                                    
        at org.specs2.matcher.MatchResultImplicits.fromMatchResult(MatchersImplicits.scala:47)                                                                                
        at org.specs2.matcher.MatchResultImplicits.fromMatchResult$(MatchersImplicits.scala:47)                                                                               
        at zio.nio.AsynchronousChannelGroupSuite$.fromMatchResult(AsynchronousChannelGroupSuite.scala:17)
        at zio.nio.AsynchronousChannelGroupSuite$.$anonfun$tests$7(AsynchronousChannelGroupSuite.scala:75)
        at testz.FutureHarness$$anon$3.$anonfun$test$4(stdlib.scala:141)
        at testz.FutureHarness$$anon$3.$anonfun$bracket$4(stdlib.scala:193)
        at scala.concurrent.Future.$anonfun$flatMap$1(Future.scala:307)
        at scala.concurrent.impl.Promise.$anonfun$transformWith$1(Promise.scala:41)
        at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:64)
        at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
        at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
        at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
        at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
        at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157) 

Fiber:816 was supposed to continue to:
  a future continuation at zio.nio.AsynchronousChannelGroupSuite$.tests(AsynchronousChannelGroupSuite.scala:73)

Fiber:816 execution trace:
  at zio.ZIO.refineOrDieWith(ZIO.scala:717) 
  at zio.nio.channels.AsynchronousChannelGroup.awaitTermination(AsynchronousChannelGroup.scala:44)

Fiber:816 was spawned by: <empty trace>
Fiber failed.

To make things a bit worse, CircleCI builds for #6 are green even though the failure is there.

Resource leak in AsynchronousServerSocketChannel()

The recent changes to AsynchronousServerSocketChannel introduced a resource leak.
Just run this test and keep an eye on lsof of the jvm process

import zio._
import zio.test._
import zio.test.Assertion._
import zio.nio.channels.AsynchronousServerSocketChannel
import zio.nio.SocketAddress
import zio.nio.channels.AsynchronousSocketChannel

object Test extends DefaultRunnableSpec(
  testM("leak resources") {
    val server = for {
      addr <- SocketAddress.inetSocketAddress(8080).toManaged_
      channel <- AsynchronousServerSocketChannel()
      _ <- channel.bind(addr).toManaged_
      _ <- AsynchronousSocketChannel().use(channel => channel.connect(addr)).forever.toManaged_.fork
    } yield channel
    val interruptAccept = server.use(_.accept.flatMap(_ => ZIO.interrupt).catchSomeCause{ case Cause.interrupt => ZIO.unit }.repeat(Schedule.recurs(20000)))
    assertM(interruptAccept.run, succeeds(equalTo(20000)))
  }
)

I'll open a pr for a fix later today.

Buffer.byte - `NoSuchMethodError: zio.Chunk.toArray`

Hi,

I've encountered an issue with ZIO-NIO (or ZIO).
I'm using RC-15 for ZIO an 0.2.1 for ZIO-NIO. In my worksheet such code fails:

import zio.DefaultRuntime

val chunk = zio.Chunk.fromArray(Array(1,2,3)).map(_.toByte)

val runtime = new DefaultRuntime {}

val _ = chunk.toArray

runtime.unsafeRun(zio.nio.Buffer.byte(chunk))

The last one line fails with:

Fiber failed.
An unchecked error was produced.
java.lang.NoSuchMethodError: zio.Chunk.toArray()Ljava/lang/Object;
at zio.nio.Buffer$.$anonfun$byte$3(Buffer.scala:108)
at zio.internal.FiberContext.evaluateNow(FiberContext.scala:280)
at zio.Runtime.unsafeRunAsync(Runtime.scala:93)
at zio.Runtime.unsafeRunAsync$(Runtime.scala:79)
...

Then switching ZIO version to RC-13 (so the one that ZIO-NIO is using) the issue does not occur.
Between these versions the signature of toArray has changed a bit.

Should we inspect it on ZIO-NIO side or ZIO's Chunk?

Maybe we should make a release that depends on RC-15 also?

Customizable DNS resolution

The current implementation of name resolution relies on the JVM name resolution implementation and in case of temporary DNS unavailability can't establish a connection to a remote host when the cached DNS record expires. Returning the latest know IP address might not be the right solution for all cases, but for some cases, it could be a reasonable fallback in case of DNS unavailability.

The primary use-case for this is API clients that are connecting to a limited number of endpoints and would like to have these connections reliable.

This issue is to discuss the need for such functionality in zio-nio. The new layer will be a simple String => IO[..., SocketAddress] and provide a few built-in building blocks like a fallback to the latest know address, background refresh (to avoid blocking calls when cache TTL expires), and others.

The API could be like (PoC)

package zio.nio

import zio.{Ref, UIO, ZIO}

import java.net.UnknownHostException

trait ZNameResolver[R, E] {
  def addr(): ZIO[R, E, InetAddress]
}

object ZNameResolver {
  type UNameResolver = ZNameResolver[Any, Nothing]
  type URNameResolver[R] = ZNameResolver[R, Nothing]
  type NameResolver[E] = ZNameResolver[Any, E]

  def regular(name: String): NameResolver[UnknownHostException] = () => InetAddress.byName(name)

  def onceAndForever[R, E](nameResolver: ZNameResolver[R, E]): ZIO[R, E, UNameResolver] = {
    nameResolver.addr().map(addr => () => UIO.succeed(addr))
  }

  def cacheLatestSuccessful[R, E](resolver: ZNameResolver[R, E]): ZIO[R, E, URNameResolver[R]] = {
    for {
      intialAddr <- resolver.addr()
      ref <- Ref.make(intialAddr)
    } yield () => resolver
      .addr()
      .tap(addr => ref.set(addr))
      .catchAll(_ => ref.get)
  }
}

This layer can also provide additional aspects:

  • rotation among multiple addresses that corresponds to a single hostname
  • periodical checking of network reachability and eviction of unreachable addresses from addresses pool
  • support for SRV type of DNS records

trait ScatteringByteOps

Hi all

Would it be possible to improve the trait ScatteringByteOps ?

That's to say to add a new method readUntilNewLine() ( which would be more or less similar to the method readChunk() )

Roadmap for 1.0

What milestones do we need to hit to reach 1.0?

  • The main 1.0 feature is generally a commitment to not break backwards compatibility of the API, so we want to have the core API locked in.
  • Use ZManaged for all resource management. Many NIO objects require strict lifecycle management using error-prone methods like close and release, it would be great to use ZManaged instead (#30)
  • The microsite (already in progress #15 #20)
  • A reasonable level of Scaladoc.
  • Wrap DatagramChannel (#56)
  • Use ZIO's executor for AsynchronousChannelGroup (#29)
  • Wrapping of the java.nio.file package (#27 in progress by @quelgar)
  • Support for Scala 2.13 (and maybe 2.11)

Add more or throw out ideas in the comments!

Introduce zio.nio.channels.FileLock wrapper

While working on AsynchronousFileChannel I came across such case:

for {
  file <- AsynchronousFileChannel.open(Paths.get("./test.txt"), Set.empty)
  fileLock <- file.lock
  //sth
  _ = fileLock.release()  //plain NIO API
}

I think that for consistency it would be valuable to perform FileLock operations inside ZIO effect, like in lock. I would introduce FileLock wrapper in ZIO for this.
What do you think?

SocketChannel is never released

From the example given in https://zio.github.io/zio-nio/docs/essentials/essentials_sockets#creating-sockets

val server = AsynchronousServerSocketChannel()
  .mapM { socket =>
    for {
      _ <- SocketAddress.inetSocketAddress("127.0.0.1", 1337) >>= socket.bind
      _ <- socket.accept.preallocate.flatMap(_..ensuring(putStrLn("Connection closed")).use(channel => doWork(channel).catchAll(ex => putStrLn(ex.getMessage))).fork).forever.fork
    } yield ()
  }.useForever

def doWork(channel: AsynchronousSocketChannel): ZIO[Console with Clock, Throwable, Unit] = {
  val process =
    for {
      chunk <- channel.read(3)
      str = chunk.toArray.map(_.toChar).mkString
      _ <- putStrLn(s"received: [$str] [${chunk.length}]")
    } yield ()

  process.whenM(channel.isOpen).forever
}

If you run this code and make a curl on it, the socket is never closed by the server.

If i add .ensuring(putStrLn("Connection closed")) before use, i see the log happened in console, but the socket remains not closed, the curl request don't end, & a lsof cmd on curl process & server process, show that the socket stay opened.

The real code i use for my test is :

import zio._
import zio.clock.Clock
import zio.duration._
import zio.nio.core.SocketAddress
import zio.nio.channels._
import zio.stream._
import zio.console._

object Main extends App {
	override def run(args: List[String]): ZIO[zio.ZEnv, Nothing, Int] = {
		server.orDie.as(0)
	}

	val server = AsynchronousServerSocketChannel()
		.mapM { socket =>
			for {
				_ <- SocketAddress.inetSocketAddress("127.0.0.1", 8080) >>= socket.bind
				_ <- socket.accept.preallocate
                                      .flatMap {
                                          _.ensuring(putStrLn("Connection closed"))
                                            .use { channel =>
                                                doWork(channel).catchAll(ex => putStrLn(ex.getMessage))
                                             }
                                             .forkDaemon
                                     }
                                    .forever
			} yield ()
		}
    	.use(_ => putStrLn("coucou"))

	def doWork(channel: AsynchronousSocketChannel): ZIO[Console with Clock, Throwable, Unit] = {
		val readRequest: ZIO[Any, Nothing, String] = ZStream
			.fromEffectOption {                          
				channel.read(1024).orElse(ZIO.fail(None))
			}
			.flattenChunks
    		.transduce(ZTransducer.utf8Decode)
			.run(Sink.foldLeft("")(_ + (_: String)))

		val res = List(
			"HTTP/1.1 200 OK",
			"Location: http://localhost:8080",
			"Content-Type: text/html; charset=UTF-8",
			"Date: Tue, 26 May 2020 17:02:42 GMT",
			""
		).mkString("\n")

		for {
			request <- readRequest
			_ <- putStrLn(request)
			response = s"$res"
			_ <- channel.write(Chunk.fromArray(response.toCharArray.map { _.toByte }))
		} yield ()
	}
}

AsynchronousChannelGroup from the ZIO perspective

The use of AsynchronousChannelGroup from the ZIO perspective is a little confusing (to me at least).
As per JDK documentation:

AsynchronousChannelGroup

Java virtual machine maintains a system-wide default group that is constructed automatically. Asynchronous channels that do not specify a group at construction time are bound to the default group. The default group has an associated thread pool that creates new threads as needed.

So, AsynchronousChannels that are created without giving them explicitly a group, are working on a different thread pool than the rest of the ZIO application. So my question is this:
Is that a problem (I guess not) and can we do better in our "opinionated" module?

Providing a mock Stream that can be used for testing zio-nio functionality w/o requiring files

I am looking at zio-nio and zio-json interactions and would like to avoid the need to populate data files.

I created a mock Channel that is populated with a String.

Would this functionality be generally useful?
If so, where it best be placed?
I will create a pull request based on the responses.

import zio.{Chunk, Queue, ZIO}

import java.nio.channels.Channel

/**
 *
 * Mock a Channel containing a specified string.
 *
 * End of data is indicated by Chunk.empty
 *
 * @param queue
 */
class StringChannel(queue: Queue[Chunk[Byte]]) extends zio.nio.core.channels.Channel {
  override protected val channel: Channel = null // not referenced

  final def readChunk(capacity: Int): ZIO[Any, Nothing, Chunk[Byte]] = queue.take
}

object StringChannel {
  /**
   * Stream of individual Chunks for each byte in string.
   *
   * @param string
   * @return
   */
  def individual(string: String) = for {
    q <- Queue.unbounded[Chunk[Byte]]
    _ <- q.offerAll(string.getBytes().map(Chunk.single))
    _ <- q.offer(Chunk.empty)
  } yield new StringChannel(q)

  /**
   * Single Chunk containing entire string
   *
   * @param string
   * @return
   */
  def single(string: String) = for {
    q <- Queue.unbounded[Chunk[Byte]]
    _ <- q.offer(Chunk.fromArray(string.getBytes()))
    _ <- q.offer(Chunk.empty)
  } yield new StringChannel(q)
}

Usage

import zio.blocking.Blocking
import zio.console.Console
import zio.nio.core.charset.Charset
import zio.stream.ZStream
import zio.{App, ExitCode, URIO, ZIO, console}

object StringChannelDump extends App {

  val lines =
    """{"curvature":0.5}
      |{"curvature":1.5}
      |""".stripMargin

  override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = {

    val program = for {
      channel <- StringChannel.single(lines)
      _ <- dump(channel)
    } yield ()

    program.exitCode
  }

  private def dump(chan: StringChannel): ZIO[Console with Blocking, Exception, Unit] = {
    val inStream: ZStream[Blocking, Exception, Byte] = ZStream.repeatEffectChunkOption {
      chan.readChunk(1000).asSomeError.flatMap { chunk =>
        if (chunk.isEmpty) ZIO.fail(None) else ZIO.succeed(chunk)
      }
    }
    
    val charStream: ZStream[Blocking, Exception, Char] =
      inStream.transduce(Charset.Standard.utf8.newDecoder.transducer())

    charStream.foreachChunk(chars => console.putStr(chars.mkString))
  }

}

Make AsynchronousChannelGroup use ZIO's Executor

There's a set of factory methods for AsynchronousChannelGroup that use external ExecutorService and thread pools. As ZIO's philosophy is to simplify the correct usage of thread pools it would be good if these methods used ZIO's non-blocking Executor instead.
This executor can be obtained through ZIO.runtime.
We'll also need a ZIO Executor method similar to asEC that will return the representation as ExecutionContextExecutorService.

The question remains if the old methods should stay in case there's a need to use yet another thread pool.

Better representation for SelectionKey operations

Right now the operations of SelectionKey are represented as Integer constants - SelectionKey.OP_ACCEPT, SelectionKey.OP_CONNECT, SelectionKey.OP_READ, SelectionKey.OP_WRITE. Methods interestOps and readyOps need to deal with that. It could be represented better as a Set of case objects.

Issue moved from scalaz/scalaz-nio#87

Replace testz with zio tests

testz doesn't seem to be maintained anymore, and it doesn't allow us to support 2.11 (which I admit is a debatable goal). While zio tests is under development, it is already usable and maintained by our community, therefore I'd recommend unifying the tool chains wherever possible :).

Client Socket Example not compiling as is

The client socket example wasn't compiling.

I was getting an error message saying something like 'open isn't a method of AsynchronousSocketChannel'. The source code for AsynchronousSocketChannel makes it seem like the stated example should be working, but it didn't.

I also needed to import zio.nio.core._

I was able to get it to compile with the following:

val clientM: Managed[Exception, AsynchronousSocketChannel] = {
    AsynchronousSocketChannel()
      .mapM { client =>
        for {
          host    <- InetAddress.localHost
          address <- InetSocketAddress.inetAddress(host, 9418)
          _       <- client.connect(address)
        } yield client
      }
  }

Raw socket

Don't know if it is appropriate to post here or not, but here is my request. Is it possible to support raw socket?

Please feel free to close this if it won't be supported. Thanks

zio-nio-core_3 has Scala 2.13 dependencies

The zio-nio-core_3 in Maven has dependencies on Scala 2.13 libraries silencer-lib and scala-collection-compat. If I use zio-nio in a project that also depends on one of those libraries I get a compile error about cross-version suffixes.

        <dependency>
            <groupId>com.github.ghik</groupId>
            <artifactId>silencer-lib_2.13.6</artifactId>
            <version>1.7.4</version>
            <scope>provided</scope>
        </dependency>
       <dependency>
            <groupId>org.scala-lang.modules</groupId>
            <artifactId>scala-collection-compat_2.13</artifactId>
            <version>2.4.4</version>
        </dependency>

I cloned the repo and tried building the top-level project and it fails with the same error.

sbt "++ 3.0.2;compile"
[info] welcome to sbt 1.5.5 (Ubuntu Java 11.0.11)
[info] loading settings for project zio-nio from build.sbt ...
[info] set current project to zio-nio (in build file:/home/msaegesser/work/zio-nio/)
[info] Setting Scala version to 3.0.2 on 2 projects.
[info] Excluded 2 projects, run ++ 3.0.2 -v for more details.
[info] Reapplying settings...
[info] set current project to zio-nio (in build file:/home/msaegesser/work/zio-nio/)
[error] Modules were resolved with conflicting cross-version suffixes in ProjectRef(uri("file:/home/msaegesser/work/zio-nio/"), "docs"):
[error]    org.scala-lang.modules:scala-collection-compat _3, _2.13
[error] java.lang.RuntimeException: Conflicting cross-version suffixes in: org.scala-lang.modules:scala-collection-compat
[error] 	at scala.sys.package$.error(package.scala:30)
[error] 	at sbt.librarymanagement.ConflictWarning$.processCrossVersioned(ConflictWarning.scala:39)
[error] 	at sbt.librarymanagement.ConflictWarning$.apply(ConflictWarning.scala:19)
[error] 	at sbt.Classpaths$.$anonfun$ivyBaseSettings$71(Defaults.scala:3194)
[error] 	at scala.Function1.$anonfun$compose$1(Function1.scala:49)
[error] 	at sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:62)
[error] 	at sbt.std.Transform$$anon$4.work(Transform.scala:68)
[error] 	at sbt.Execute.$anonfun$submit$2(Execute.scala:282)
[error] 	at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:23)
[error] 	at sbt.Execute.work(Execute.scala:291)
[error] 	at sbt.Execute.$anonfun$submit$1(Execute.scala:282)
[error] 	at sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:265)
[error] 	at sbt.CompletionService$$anon$2.call(CompletionService.scala:64)
[error] 	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
[error] 	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
[error] 	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
[error] 	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
[error] 	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
[error] 	at java.base/java.lang.Thread.run(Thread.java:829)
[error] (docs / update) Conflicting cross-version suffixes in: org.scala-lang.modules:scala-collection-compat
[error] Total time: 1 s, completed Nov 22, 2021, 9:42:15 AM

Curiously, if I run sbt "++ 3.0.2;publishLocal I get a zio-nio artifact that does not depend on zio-nio-core and has a scala-collection-compat_3:2.5.5 dependency and only has a 2.13 dependency on silencer-lib.

I'm hoping someone here has better sbt chops that I do and understand how this happens.

Managed temporary files

It would be useful to have variants of the Files.createTemp* methods that returned ZManaged. When the managed value is released, the temporary file will be deleted.

Maybe we should offer only ZManaged versions of these.

Expose end-of-stream from channels

Currently whenever we read from a channel and it returns -1, we fail with an IOException using https://github.com/zio/zio-nio/blob/master/nio-core/src/main/scala/zio/nio/core/package.scala#L15.

This can be very inconvenient when writing for example a streams-based consumer as it makes it impossible to differentiate between the socket getting closed and an error, without exploiting implementation details.
I propose we should instead model read as def read(b: ByteBuffer): IO[Option[IOException], Int], where fail(None) signals end of stream.

Add support for 2.13

Investigate the necessary changes and apply them. Once they're in place, make sure to reflect them in CircleCI configuration.

Tests for zio.nio.file

There's some more complex functionality in zio.nio.file.Files that goes beyond simply wrapping effects:

  • The directory listing/walking methods that return ZStream
  • The attribute handling, especially useFileAttributeView

Files.deleteRecursive does not delete recursively

Hi all,

Files.deleteRecursive fails when passed a directory that contains a non-empty directory. I tested this using zio 2.0.10, zio-nio 2.0.1 and JDK "Temurin" 17.0.5:

import zio._
import zio.nio.file._

object DeleteRecursivelyTest extends ZIOAppDefault {
  override def run = {
    val dirPath = Path("delete-test")
    for {
      _ <- Files.createDirectories(dirPath / "inner")
      _ <- Files.writeLines(dirPath / "inner" / "blah.txt", Seq("test"))
      _ <- Files.deleteRecursive(dirPath)
    } yield ExitCode.success
  }

}

I believe this is not intended behavior.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.