@@ -18,36 +18,40 @@ package org.http4s.netty
1818package client
1919
2020import io .netty .bootstrap .Bootstrap
21+ import io .netty .channel .Channel
2122import io .netty .channel .ChannelOption
2223import io .netty .channel .MultiThreadIoEventLoopGroup
2324import io .netty .channel .MultithreadEventLoopGroup
2425import io .netty .channel .epoll .Epoll
26+ import io .netty .channel .epoll .EpollDatagramChannel
2527import io .netty .channel .epoll .EpollIoHandler
2628import io .netty .channel .epoll .EpollSocketChannel
2729import io .netty .channel .kqueue .KQueue
30+ import io .netty .channel .kqueue .KQueueDatagramChannel
2831import io .netty .channel .kqueue .KQueueIoHandler
2932import io .netty .channel .kqueue .KQueueSocketChannel
3033import io .netty .channel .nio .NioIoHandler
34+ import io .netty .channel .socket .DatagramChannel
3135import io .netty .channel .socket .SocketChannel
36+ import io .netty .channel .socket .nio .NioDatagramChannel
3237import io .netty .channel .socket .nio .NioSocketChannel
3338import io .netty .channel .uring .IoUring
39+ import io .netty .channel .uring .IoUringDatagramChannel
3440import io .netty .channel .uring .IoUringIoHandler
3541import io .netty .channel .uring .IoUringSocketChannel
3642import org .slf4j .Logger
3743import org .slf4j .LoggerFactory
3844
39- import scala .annotation .nowarn
4045import scala .reflect .ClassTag
4146
42- private [client] final case class EventLoopHolder [A <: SocketChannel ](
47+ private [client] final case class EventLoopHolder [A <: Channel ](
4348 eventLoop : MultithreadEventLoopGroup )(implicit classTag : ClassTag [A ]) {
4449 def runtimeClass : Class [A ] = classTag.runtimeClass.asInstanceOf [Class [A ]]
4550
4651 def configure (bootstrap : Bootstrap ): Bootstrap =
4752 bootstrap
4853 .group(eventLoop)
4954 .channel(runtimeClass)
50- .option(ChannelOption .TCP_NODELAY , java.lang.Boolean .TRUE )
5155 .option(ChannelOption .SO_KEEPALIVE , java.lang.Boolean .TRUE )
5256}
5357
@@ -66,7 +70,18 @@ private[client] object EventLoopHolder {
6670 throw new IllegalStateException (" No native transport available" ))
6771 }
6872
69- @ nowarn(" cat=deprecation" )
73+ def fromUdpTransport (
74+ transport : NettyTransport ,
75+ eventLoopThreads : Int ): EventLoopHolder [_ <: DatagramChannel ] =
76+ transport match {
77+ case NettyTransport .Nio =>
78+ EventLoopHolder [NioDatagramChannel ](
79+ new MultiThreadIoEventLoopGroup (eventLoopThreads, NioIoHandler .newFactory()))
80+ case n : NettyTransport .Native =>
81+ selectUdpTransport(n, eventLoopThreads).getOrElse(
82+ throw new IllegalStateException (" No native transport available" ))
83+ }
84+
7085 def selectTransport (
7186 native : NettyTransport .Native ,
7287 eventLoopThreads : Int ): Option [EventLoopHolder [_ <: SocketChannel ]] =
@@ -86,7 +101,7 @@ private[client] object EventLoopHolder {
86101 Some (
87102 EventLoopHolder [KQueueSocketChannel ](
88103 new MultiThreadIoEventLoopGroup (eventLoopThreads, KQueueIoHandler .newFactory())))
89- case NettyTransport .Auto | NettyTransport . Native =>
104+ case NettyTransport .Auto =>
90105 selectTransport(NettyTransport .IOUring , eventLoopThreads)
91106 .orElse(selectTransport(NettyTransport .Epoll , eventLoopThreads))
92107 .orElse(selectTransport(NettyTransport .KQueue , eventLoopThreads))
@@ -98,4 +113,36 @@ private[client] object EventLoopHolder {
98113 }
99114 case _ => None
100115 }
116+
117+ def selectUdpTransport (
118+ native : NettyTransport .Native ,
119+ eventLoopThreads : Int ): Option [EventLoopHolder [_ <: DatagramChannel ]] =
120+ native match {
121+ case NettyTransport .IOUring if IoUring .isAvailable =>
122+ logger.info(" Using IOUring" )
123+ Some (
124+ EventLoopHolder [IoUringDatagramChannel ](
125+ new MultiThreadIoEventLoopGroup (eventLoopThreads, IoUringIoHandler .newFactory())))
126+ case NettyTransport .Epoll if Epoll .isAvailable =>
127+ logger.info(" Using Epoll" )
128+ Some (
129+ EventLoopHolder [EpollDatagramChannel ](
130+ new MultiThreadIoEventLoopGroup (eventLoopThreads, EpollIoHandler .newFactory())))
131+ case NettyTransport .KQueue if KQueue .isAvailable =>
132+ logger.info(" Using KQueue" )
133+ Some (
134+ EventLoopHolder [KQueueDatagramChannel ](
135+ new MultiThreadIoEventLoopGroup (eventLoopThreads, KQueueIoHandler .newFactory())))
136+ case NettyTransport .Auto =>
137+ selectUdpTransport(NettyTransport .IOUring , eventLoopThreads)
138+ .orElse(selectUdpTransport(NettyTransport .Epoll , eventLoopThreads))
139+ .orElse(selectUdpTransport(NettyTransport .KQueue , eventLoopThreads))
140+ .orElse {
141+ logger.info(" Falling back to NIO EventLoopGroup" )
142+ Some (
143+ EventLoopHolder [NioDatagramChannel ](
144+ new MultiThreadIoEventLoopGroup (eventLoopThreads, NioIoHandler .newFactory())))
145+ }
146+ case _ => None
147+ }
101148}
0 commit comments