WebSocket extensions API
The API is production ready, but may be slightly modified in a minor release. This is why it’s marked with the annotation. If you want to use this API you need to OptIn
:
If you want to leave your feedback or subscribe on updates, check KTOR-688 design issue.
To install and configure the extensions we provide two methods: extensions
and install
which can be used in the following way:
install(WebSockets) {
extensions { /* WebSocketExtensionConfig.() -> Unit */
install(MyWebSocketExtension) { /* MyWebSocketExtensionConfig.() -> Unit */
/* Optional extension configuration. */
}
}
}
All installed extensions go through the negotiation process, and those that are successfully negotiated are used during the request. You can use WebSocketSession.extensions: : List<WebSocketExtension<*>>
property with list of all extensions used by for the current session.
There are two methods to check if the extension is in use: WebSocketSession.extension
and WebSocketSession.extensionOrNull
:
There are two interfaces for implementing a new extension: WebSocketExtension<ConfigType: Any>
and . A single implementation can work for both clients and servers.
class FrameLoggerExtension(val logger: Logger) : WebSocketExtension<FrameLogger.Config> {
The feature has two groups of fields and methods. The first group is for extension negotiation:
The second group is the place for actual frame processing. Methods will take a frame and produce a new processed frame if necessary:
logger.log("Process outgoing frame: $frame")
return frame
}
override fun processIncomingFrame(frame: Frame): Frame {
logger.log("Process incoming frame: $frame")
return frame
}
There are also some implementation details: the feature has Config
and reference to the origin factory
.
companion object : WebSocketExtensionFactory<Config, FrameLogger> {
/* Key to discover installed extension instance */
/** List of occupied rsv bits.
* If the extension occupy a bit, it can't be used in other installed extensions. We use that bits to prevent feature conflicts(prevent to install multiple compression features). If you implementing feature using some RFC, rsv occupied bits should be referenced there.
*/
override val rsv1: Boolean = false
override val rsv2: Boolean = false
override val rsv3: Boolean = false
/** Create feature instance. Will be called for each WebSocket session **/
override fun install(config: Config.() -> Unit): FrameLogger {
return FrameLogger(Config().apply(config).logger)
}
}