Skip to content

Commit f6b8f1f

Browse files
Add removeHandler(context: ChannelHandlerContext) to SynchronousOperations of ChannelPipeline (#2912)
### Motivation: As per #2906. ### Modifications: Added a method to SynchrounousOperations of ChannelPipeline. ### Result: Now we are able to remove channel handlers by context. --------- Co-authored-by: Franz Busch <[email protected]>
1 parent 611fa09 commit f6b8f1f

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

Sources/NIOCore/ChannelPipeline.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,17 @@ extension ChannelPipeline {
11611161
return promise.futureResult
11621162
}
11631163

1164+
/// Remove a `ChannelHandler` from the `ChannelPipeline`.
1165+
///
1166+
/// - parameters:
1167+
/// - context: the `ChannelHandlerContext` that belongs to `ChannelHandler` that should be removed.
1168+
/// - returns: the `EventLoopFuture` which will be notified once the `ChannelHandler` was removed.
1169+
public func removeHandler(context: ChannelHandlerContext) -> EventLoopFuture<Void> {
1170+
let promise = self.eventLoop.makePromise(of: Void.self)
1171+
self._pipeline.removeHandler(context: context, promise: promise)
1172+
return promise.futureResult
1173+
}
1174+
11641175
/// Returns the `ChannelHandlerContext` for the given handler instance if it is in
11651176
/// the `ChannelPipeline`, if it exists.
11661177
///

Tests/NIOPosixTests/ChannelPipelineTest.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,6 +1119,51 @@ class ChannelPipelineTest: XCTestCase {
11191119
}
11201120
}
11211121

1122+
func testRemovingByContexSync() throws {
1123+
class Handler: ChannelInboundHandler, RemovableChannelHandler {
1124+
typealias InboundIn = Never
1125+
1126+
var removeHandlerCalled = false
1127+
var withinRemoveHandler = false
1128+
1129+
func removeHandler(context: ChannelHandlerContext, removalToken: ChannelHandlerContext.RemovalToken) {
1130+
self.removeHandlerCalled = true
1131+
self.withinRemoveHandler = true
1132+
defer {
1133+
self.withinRemoveHandler = false
1134+
}
1135+
context.leavePipeline(removalToken: removalToken)
1136+
}
1137+
1138+
func handlerRemoved(context: ChannelHandlerContext) {
1139+
XCTAssertTrue(self.removeHandlerCalled)
1140+
XCTAssertTrue(self.withinRemoveHandler)
1141+
}
1142+
}
1143+
1144+
let channel = EmbeddedChannel()
1145+
defer {
1146+
XCTAssertNoThrow(XCTAssertTrue(try channel.finish().isClean))
1147+
}
1148+
let allHandlers = [Handler(), Handler(), Handler()]
1149+
XCTAssertNoThrow(try channel.pipeline.addHandler(allHandlers[0], name: "the first one to remove").wait())
1150+
XCTAssertNoThrow(try channel.pipeline.addHandler(allHandlers[1], name: "the second one to remove").wait())
1151+
XCTAssertNoThrow(try channel.pipeline.addHandler(allHandlers[2], name: "the last one to remove").wait())
1152+
1153+
let firstContext = try! channel.pipeline.syncOperations.context(name: "the first one to remove")
1154+
let secondContext = try! channel.pipeline.syncOperations.context(name: "the second one to remove")
1155+
let lastContext = try! channel.pipeline.syncOperations.context(name: "the last one to remove")
1156+
1157+
XCTAssertNoThrow(try channel.pipeline.syncOperations.removeHandler(context: firstContext).wait())
1158+
XCTAssertNoThrow(try channel.pipeline.syncOperations.removeHandler(context: secondContext).wait())
1159+
XCTAssertNoThrow(try channel.pipeline.syncOperations.removeHandler(context: lastContext).wait())
1160+
1161+
for handler in allHandlers {
1162+
XCTAssertTrue(handler.removeHandlerCalled)
1163+
XCTAssertFalse(handler.withinRemoveHandler)
1164+
}
1165+
}
1166+
11221167
func testNonRemovableChannelHandlerIsNotRemovable() {
11231168
class NonRemovableHandler: ChannelInboundHandler {
11241169
typealias InboundIn = Never

0 commit comments

Comments
 (0)