Skip to content

Commit

Permalink
Add TLS and WebSocket support for NodeJS
Browse files Browse the repository at this point in the history
  • Loading branch information
davidepianca98 committed Feb 12, 2022
1 parent 111ec0e commit c12358e
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 34 deletions.
2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 9 additions & 9 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
:white_check_mark: = Supported
:heavy_plus_sign: = Work In Progress

| Platform | MQTT 3.1.1 | MQTT 5.0 | TCP | TLS | Websocket | Clustering |
| :---: | :---: | :---: | :---: |:------------------:|:------------------:|:-----------------:|
| JVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_plus_sign: |
| Windows X64 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
| Windows X86 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
| Linux X64 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
| Linux ARM32 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
| Linux ARM64 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
| Node.js | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: |
| Platform | MQTT 3.1.1 | MQTT 5.0 | TCP | TLS | Websocket | Clustering |
| :---: |:------------------:| :---: | :---: |:------------------:|:------------------:|:-----------------:|
| JVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_plus_sign: |
| Windows X64 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
| Windows X86 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
| Linux X64 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
| Linux ARM32 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
| Linux ARM64 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
| Node.js | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |

## Getting Started

Expand Down
8 changes: 4 additions & 4 deletions src/commonMain/kotlin/datastructures/Trie.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@ class Trie(subscriptions: Map<String, Subscription>? = null) {
): Boolean {
val character = topic.getOrNull(index)
val childNode = node.children[character]
if (childNode != null) {
return insert(childNode, topic, index + 1, subscription, clientId)
return if (childNode != null) {
insert(childNode, topic, index + 1, subscription, clientId)
} else {
if (character == null) {
val replaced = node.subscriptions[clientId] != null
node.subscriptions[clientId] = subscription
return replaced
replaced
} else {
val newNode = TrieNode(character)
node.children[character] = newNode
return insert(newNode, topic, index + 1, subscription, clientId)
insert(newNode, topic, index + 1, subscription, clientId)
}
}
}
Expand Down
37 changes: 29 additions & 8 deletions src/jsMain/kotlin/socket/ServerSocket.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,21 @@ import kotlinx.coroutines.launch
import mqtt.broker.Broker
import mqtt.broker.ClientConnection
import mqtt.broker.cluster.ClusterConnection
import net.createServer
import setTimeout
import socket.tcp.Socket
import socket.tcp.WebSocket
import kotlin.js.Promise

actual open class ServerSocket actual constructor(
private val broker: Broker,
private val selectCallback: (attachment: Any?, state: ServerSocketLoop.SocketState) -> Boolean
) : ServerSocketInterface {

private val clients = mutableMapOf<String, Any?>()
private val mqttSocket = createServer { socket: net.Socket ->
val localSocket = createSocket(socket)
clients[socket.socketId()] = ClientConnection(localSocket, broker)
localSocket.setAttachment(clients[socket.socketId()])
protected val clients = mutableMapOf<String, Any?>()
protected open lateinit var mqttSocket: net.Server
protected open lateinit var mqttWebSocket: net.Server

fun onConnect(socket: net.Socket) {
socket.on("error") { error: Error ->
println(error.message)
}
Expand All @@ -43,14 +42,35 @@ actual open class ServerSocket actual constructor(
private fun net.Socket.socketId(): String = "$remoteAddress:$remotePort"

init {
initialize(broker)
}

open fun initialize(broker: Broker) {
mqttSocket = net.createServer { socket: net.Socket ->
val localSocket = createSocket(socket)
val connection = ClientConnection(localSocket, broker)
clients[socket.socketId()] = connection
localSocket.setAttachment(connection)

onConnect(socket)
}
mqttWebSocket = net.createServer { socket: net.Socket ->
val localSocket = createSocket(socket)
val connection = ClientConnection(WebSocket(localSocket), broker)
clients[socket.socketId()] = connection
localSocket.setAttachment(connection)

onConnect(socket)
}

mqttSocket.listen(broker.port, broker.host)

if (broker.enableUdp) {
TODO("UDP in JS not yet implemented")
}

if (broker.webSocketPort != null) {
TODO("WebSocket in JS not yet implemented")
mqttWebSocket.listen(broker.webSocketPort, broker.host)
}

if (broker.cluster != null) {
Expand All @@ -64,9 +84,10 @@ actual open class ServerSocket actual constructor(

actual fun close() {
mqttSocket.close()
mqttWebSocket.close()
}

actual fun isRunning(): Boolean = mqttSocket.listening
actual fun isRunning(): Boolean = mqttSocket.listening || mqttWebSocket.listening

private fun sleep(ms: Long): Promise<Any> {
return Promise { resolve, _ ->
Expand Down
57 changes: 52 additions & 5 deletions src/jsMain/kotlin/socket/tls/TLSServerSocket.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,67 @@
package socket.tls

import mqtt.broker.Broker
import mqtt.broker.ClientConnection
import socket.ServerSocket
import socket.ServerSocketLoop
import socket.tcp.Socket
import socket.tcp.WebSocket
import tls.TlsOptions

actual class TLSServerSocket actual constructor(
private val broker: Broker,
private val selectCallback: (attachment: Any?, state: ServerSocketLoop.SocketState) -> Boolean
) : ServerSocket(broker, selectCallback) {

init {
TODO("TLS in JS not yet implemented")
private fun TlsOptions(): TlsOptions = js("{}") as TlsOptions

private val tlsOptions = TlsOptions().apply {
pfx = fs.readFileSync(broker.tlsSettings!!.keyStoreFilePath, null as String?)
passphrase = broker.tlsSettings.keyStorePassword
requestCert = broker.tlsSettings.requireClientCertificate
}
override lateinit var mqttSocket: net.Server

override lateinit var mqttWebSocket: net.Server

// TODO this duplication is necessary because overriding the properties, they would get initialized too late and get
// undefined
override fun initialize(broker: Broker) {
mqttSocket = tls.createServer(tlsOptions) { socket: tls.TLSSocket ->
val localSocket = createSocket(socket)
val connection = ClientConnection(localSocket, broker)
clients[socket.socketId()] = connection
localSocket.setAttachment(connection)

onConnect(socket)
}

mqttWebSocket = tls.createServer(tlsOptions) { socket: tls.TLSSocket ->
val localSocket = createSocket(socket)
val connection = ClientConnection(WebSocket(localSocket), broker)
clients[socket.socketId()] = connection
localSocket.setAttachment(connection)

onConnect(socket)
}

mqttSocket.listen(broker.port, broker.host)

if (broker.enableUdp) {
TODO("UDP in JS not yet implemented")
}

if (broker.webSocketPort != null) {
mqttWebSocket.listen(broker.webSocketPort, broker.host)
}

if (broker.cluster != null) {
TODO("Cluster in JS not yet implemented")
}
}

override fun createSocket(socket: net.Socket): Socket {
TODO("TLS in JS not yet implemented")
private fun tls.TLSSocket.socketId(): String = "$remoteAddress:$remotePort"

private fun createSocket(socket: tls.TLSSocket): TLSSocket {
return TLSSocket(socket, selectCallback)
}
}
7 changes: 0 additions & 7 deletions src/jsMain/kotlin/socket/tls/TLSSocket.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,4 @@ actual class TLSSocket(
private val selectCallback: (attachment: Any?, state: ServerSocketLoop.SocketState) -> Boolean
) : Socket(socket, selectCallback) {

override fun send(data: UByteArray) {
TODO("TLS in JS not yet implemented")
}

override fun read(): UByteArray? {
TODO("TLS in JS not yet implemented")
}
}

0 comments on commit c12358e

Please sign in to comment.