fix IMAPIdleHandler thread safety: pass idleTag via init, clean up event loop group on reconnect
This commit is contained in:
@@ -67,6 +67,12 @@ public actor IMAPIdleClient {
|
||||
// MARK: - Connection
|
||||
|
||||
private func connectAndLogin() async throws {
|
||||
// Clean up previous connection if reconnecting
|
||||
try? await channel?.close()
|
||||
channel = nil
|
||||
try? await group?.shutdownGracefully()
|
||||
group = nil
|
||||
|
||||
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
|
||||
let sslContext = try NIOSSLContext(configuration: TLSConfiguration.makeClientConfiguration())
|
||||
let hostname = host
|
||||
@@ -138,16 +144,14 @@ public actor IMAPIdleClient {
|
||||
// Iterative IDLE loop — avoids unbounded stack growth from recursion
|
||||
while !Task.isCancelled {
|
||||
// Swap response handler for IDLE handler
|
||||
let idleTag = "IDLE1"
|
||||
let (stream, streamContinuation) = AsyncStream<IMAPIdleEvent>.makeStream()
|
||||
let idleHandler = IMAPIdleHandler(continuation: streamContinuation)
|
||||
let idleHandler = IMAPIdleHandler(continuation: streamContinuation, idleTag: idleTag)
|
||||
|
||||
let oldHandler = try await getResponseHandler()
|
||||
try await pipeline.removeHandler(oldHandler).get()
|
||||
try await pipeline.addHandler(idleHandler).get()
|
||||
|
||||
let idleTag = "IDLE1"
|
||||
idleHandler.setIdleTag(idleTag)
|
||||
|
||||
// Send IDLE command
|
||||
let idleCommand = TaggedCommand(tag: idleTag, command: .idleStart)
|
||||
channel.writeAndFlush(IMAPClientHandler.Message.part(.tagged(idleCommand)), promise: nil)
|
||||
|
||||
@@ -16,14 +16,11 @@ final class IMAPIdleHandler: ChannelInboundHandler, RemovableChannelHandler, @un
|
||||
typealias InboundIn = Response
|
||||
|
||||
private let continuation: AsyncStream<IMAPIdleEvent>.Continuation
|
||||
private var idleTag: String?
|
||||
private let idleTag: String
|
||||
|
||||
init(continuation: AsyncStream<IMAPIdleEvent>.Continuation) {
|
||||
init(continuation: AsyncStream<IMAPIdleEvent>.Continuation, idleTag: String) {
|
||||
self.continuation = continuation
|
||||
}
|
||||
|
||||
func setIdleTag(_ tag: String) {
|
||||
idleTag = tag
|
||||
self.idleTag = idleTag
|
||||
}
|
||||
|
||||
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
|
||||
|
||||
Reference in New Issue
Block a user