Add port configuration to magix server

This commit is contained in:
Alexander Nozik 2022-06-06 10:57:24 +03:00
parent cfaeb964e7
commit 535e44286c
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
9 changed files with 72 additions and 11 deletions

View File

@ -8,7 +8,7 @@ import kotlinx.serialization.json.JsonObject
import ru.mipt.npm.magix.api.MagixEndpoint import ru.mipt.npm.magix.api.MagixEndpoint
import ru.mipt.npm.magix.api.MagixMessage import ru.mipt.npm.magix.api.MagixMessage
import ru.mipt.npm.magix.api.MagixMessageFilter import ru.mipt.npm.magix.api.MagixMessageFilter
import ru.mipt.npm.magix.rsocket.rSocketStreamWithTcp import ru.mipt.npm.magix.rsocket.rSocketStreamWithWebSockets
import ru.mipt.npm.magix.server.startMagixServer import ru.mipt.npm.magix.server.startMagixServer
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime
import kotlin.time.measureTime import kotlin.time.measureTime
@ -59,7 +59,7 @@ private suspend fun MagixEndpoint.collectEcho(scope: CoroutineScope, n: Int) {
@OptIn(ExperimentalTime::class) @OptIn(ExperimentalTime::class)
suspend fun main(): Unit = coroutineScope { suspend fun main(): Unit = coroutineScope {
launch(Dispatchers.Default) { launch(Dispatchers.Default) {
val server = startMagixServer(enableRawRSocket = true, enableZmq = true) { flow -> val server = startMagixServer(enableRawRSocket = false, enableZmq = false) { flow ->
//echo each message //echo each message
flow.onEach { message -> flow.onEach { message ->
if (message.parentId == null) { if (message.parentId == null) {
@ -72,7 +72,7 @@ suspend fun main(): Unit = coroutineScope {
val responseTime = measureTime { val responseTime = measureTime {
MagixEndpoint.rSocketStreamWithTcp("localhost").use { MagixEndpoint.rSocketStreamWithWebSockets("localhost").use {
it.collectEcho(this, 5000) it.collectEcho(this, 5000)
} }
} }

View File

@ -23,6 +23,11 @@ public interface MagixEndpoint {
message: MagixMessage, message: MagixMessage,
) )
/**
* Close the endpoint and the associated connection if it exists
*/
public fun close()
public companion object { public companion object {
/** /**
* A default port for HTTP/WS connections * A default port for HTTP/WS connections

View File

@ -0,0 +1,13 @@
plugins {
id("ru.mipt.npm.gradle.jvm")
`maven-publish`
}
description = """
RabbitMQ client magix endpoint
""".trimIndent()
dependencies {
api(projects.magix.magixApi)
implementation("com.rabbitmq:amqp-client:5.14.2")
}

View File

@ -14,7 +14,6 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.serialization.encodeToString
import ru.mipt.npm.magix.api.MagixEndpoint import ru.mipt.npm.magix.api.MagixEndpoint
import ru.mipt.npm.magix.api.MagixMessage import ru.mipt.npm.magix.api.MagixMessage
import ru.mipt.npm.magix.api.MagixMessageFilter import ru.mipt.npm.magix.api.MagixMessageFilter
@ -30,7 +29,7 @@ public class RSocketMagixEndpoint(
override fun subscribe( override fun subscribe(
filter: MagixMessageFilter, filter: MagixMessageFilter,
): Flow<MagixMessage> { ): Flow<MagixMessage> {
val payload = buildPayload { data(MagixEndpoint.magixJson.encodeToString(filter)) } val payload = buildPayload { data(MagixEndpoint.magixJson.encodeToString(MagixMessageFilter.serializer(), filter)) }
val flow = rSocket.requestStream(payload) val flow = rSocket.requestStream(payload)
return flow.map { return flow.map {
MagixEndpoint.magixJson.decodeFromString(MagixMessage.serializer(), it.data.readText()) MagixEndpoint.magixJson.decodeFromString(MagixMessage.serializer(), it.data.readText())

View File

@ -1,12 +1,18 @@
package ru.mipt.npm.magix.rsocket package ru.mipt.npm.magix.rsocket
import io.ktor.client.HttpClient
import io.ktor.client.plugins.websocket.WebSockets
import io.ktor.utils.io.core.Closeable import io.ktor.utils.io.core.Closeable
import io.rsocket.kotlin.RSocket import io.rsocket.kotlin.RSocket
import io.rsocket.kotlin.core.RSocketConnectorBuilder
import io.rsocket.kotlin.ktor.client.RSocketSupport
import io.rsocket.kotlin.ktor.client.rSocket
import io.rsocket.kotlin.payload.Payload import io.rsocket.kotlin.payload.Payload
import io.rsocket.kotlin.payload.buildPayload import io.rsocket.kotlin.payload.buildPayload
import io.rsocket.kotlin.payload.data import io.rsocket.kotlin.payload.data
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
@ -17,20 +23,32 @@ import ru.mipt.npm.magix.api.MagixMessage
import ru.mipt.npm.magix.api.MagixMessageFilter import ru.mipt.npm.magix.api.MagixMessageFilter
import ru.mipt.npm.magix.api.filter import ru.mipt.npm.magix.api.filter
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
/** /**
* RSocket endpoint based on established channel * RSocket endpoint based on established channel. This way it works a bit faster than [RSocketMagixEndpoint]
* for sending and receiving, but less flexible in terms of filters. One general [streamFilter] could be set
* in constructor and applied on the loop side. Filters in [subscribe] are applied on the endpoint side on top
* of received data.
*/ */
public class RSocketStreamMagixEndpoint( public class RSocketStreamMagixEndpoint(
private val rSocket: RSocket, private val rSocket: RSocket,
private val coroutineContext: CoroutineContext, private val coroutineContext: CoroutineContext,
public val streamFilter: MagixMessageFilter = MagixMessageFilter(),
) : MagixEndpoint, Closeable { ) : MagixEndpoint, Closeable {
private val output: MutableSharedFlow<MagixMessage> = MutableSharedFlow() private val output: MutableSharedFlow<MagixMessage> = MutableSharedFlow()
private val input: Flow<Payload> by lazy { private val input: Flow<Payload> by lazy {
rSocket.requestChannel( rSocket.requestChannel(
Payload.Empty, buildPayload {
data(
MagixEndpoint.magixJson.encodeToString(
MagixMessageFilter.serializer(),
streamFilter
)
)
},
output.map { message -> output.map { message ->
buildPayload { buildPayload {
data(MagixEndpoint.magixJson.encodeToString(MagixMessage.serializer(), message)) data(MagixEndpoint.magixJson.encodeToString(MagixMessage.serializer(), message))
@ -55,3 +73,26 @@ public class RSocketStreamMagixEndpoint(
rSocket.cancel() rSocket.cancel()
} }
} }
public suspend fun MagixEndpoint.Companion.rSocketStreamWithWebSockets(
host: String,
port: Int = DEFAULT_MAGIX_HTTP_PORT,
path: String = "/rsocket",
rSocketConfig: RSocketConnectorBuilder.ConnectionConfigBuilder.() -> Unit = {},
): RSocketStreamMagixEndpoint {
val client = HttpClient {
install(WebSockets)
install(RSocketSupport) {
connector = buildConnector(rSocketConfig)
}
}
val rSocket = client.rSocket(host, port, path)
//Ensure client is closed after rSocket if finished
rSocket.coroutineContext[Job]?.invokeOnCompletion {
client.close()
}
return RSocketStreamMagixEndpoint(rSocket, coroutineContext)
}

View File

@ -42,7 +42,10 @@ public fun CoroutineScope.startMagixServer(
port: Int = DEFAULT_MAGIX_HTTP_PORT, port: Int = DEFAULT_MAGIX_HTTP_PORT,
buffer: Int = 1000, buffer: Int = 1000,
enableRawRSocket: Boolean = true, enableRawRSocket: Boolean = true,
rawRSocketPort: Int = DEFAULT_MAGIX_RAW_PORT,
enableZmq: Boolean = true, enableZmq: Boolean = true,
zmqPubSocketPort: Int = MagixEndpoint.DEFAULT_MAGIX_ZMQ_PUB_PORT,
zmqPullSocketPort: Int = MagixEndpoint.DEFAULT_MAGIX_ZMQ_PULL_PORT,
applicationConfiguration: Application.(MutableSharedFlow<MagixMessage>) -> Unit = {}, applicationConfiguration: Application.(MutableSharedFlow<MagixMessage>) -> Unit = {},
): ApplicationEngine { ): ApplicationEngine {
val logger = LoggerFactory.getLogger("magix-server") val logger = LoggerFactory.getLogger("magix-server")
@ -54,14 +57,11 @@ public fun CoroutineScope.startMagixServer(
if (enableRawRSocket) { if (enableRawRSocket) {
//Start tcpRSocket server //Start tcpRSocket server
val rawRSocketPort = DEFAULT_MAGIX_RAW_PORT
logger.info("Starting magix raw rsocket server on port $rawRSocketPort") logger.info("Starting magix raw rsocket server on port $rawRSocketPort")
launchMagixServerRawRSocket(magixFlow, rawRSocketPort) launchMagixServerRawRSocket(magixFlow, rawRSocketPort)
} }
if (enableZmq) { if (enableZmq) {
//Start ZMQ server socket pair //Start ZMQ server socket pair
val zmqPubSocketPort: Int = MagixEndpoint.DEFAULT_MAGIX_ZMQ_PUB_PORT
val zmqPullSocketPort: Int = MagixEndpoint.DEFAULT_MAGIX_ZMQ_PULL_PORT
logger.info("Starting magix zmq server on pub port $zmqPubSocketPort and pull port $zmqPullSocketPort") logger.info("Starting magix zmq server on pub port $zmqPubSocketPort and pull port $zmqPullSocketPort")
launchMagixServerZmqSocket( launchMagixServerZmqSocket(
magixFlow, magixFlow,

View File

@ -1,4 +1,5 @@
rootProject.name = "controls-kt" rootProject.name = "controls-kt"
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
enableFeaturePreview("VERSION_CATALOGS") enableFeaturePreview("VERSION_CATALOGS")
@ -53,11 +54,13 @@ include(
":magix:magix-rsocket", ":magix:magix-rsocket",
":magix:magix-java-client", ":magix:magix-java-client",
":magix:magix-zmq", ":magix:magix-zmq",
":magix:magix-demo", ":magix:magix-rabbit",
// ":magix:magix-storage", // ":magix:magix-storage",
":magix:magix-storage:magix-storage-xodus", ":magix:magix-storage:magix-storage-xodus",
":controls-magix-client", ":controls-magix-client",
":demo:all-things", ":demo:all-things",
":demo:magix-demo",
":demo:car", ":demo:car",
":demo:motors", ":demo:motors",
":demo:echo" ":demo:echo"