aboutsummaryrefslogtreecommitdiff
path: root/kvision-modules/kvision-remote/src
diff options
context:
space:
mode:
authorRobert Jaros <rjaros@finn.pl>2020-03-11 16:18:17 +0100
committerRobert Jaros <rjaros@finn.pl>2020-03-11 16:18:17 +0100
commit9e243a469ae6544e8cf523ad09b959f541c3f565 (patch)
treebe9c7447e221af49180c9e98434df7f988b940b8 /kvision-modules/kvision-remote/src
parentec6084c42c13a621e17b17bd40d90b5c7879f0ec (diff)
downloadkvision-9e243a469ae6544e8cf523ad09b959f541c3f565.tar.gz
kvision-9e243a469ae6544e8cf523ad09b959f541c3f565.tar.bz2
kvision-9e243a469ae6544e8cf523ad09b959f541c3f565.zip
Upgrade to Kotlin 1.3.70 + other dependencies (Coroutinse, Serialization, Spring Boot)
Major refactoring of build architecture.
Diffstat (limited to 'kvision-modules/kvision-remote/src')
-rw-r--r--kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/CallAgent.kt159
-rw-r--r--kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVRemoteAgent.kt562
-rw-r--r--kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt160
-rw-r--r--kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/RemoteAgent.kt207
-rw-r--r--kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/Security.kt115
-rw-r--r--kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/Socket.kt186
-rw-r--r--kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/Utils.kt74
-rw-r--r--kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/types/Date.kt97
-rw-r--r--kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/types/Decimal.kt24
9 files changed, 0 insertions, 1584 deletions
diff --git a/kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/CallAgent.kt b/kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/CallAgent.kt
deleted file mode 100644
index 9110d4df..00000000
--- a/kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/CallAgent.kt
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.remote
-
-import kotlinx.serialization.ImplicitReflectionSerializer
-import kotlinx.serialization.stringify
-import org.w3c.dom.get
-import pl.treksoft.jquery.JQueryAjaxSettings
-import pl.treksoft.jquery.JQueryXHR
-import pl.treksoft.jquery.jQuery
-import kotlin.browser.window
-import kotlin.js.Promise
-import kotlin.js.JSON as NativeJSON
-
-/**
- * HTTP status unauthorized (401).
- */
-const val HTTP_UNAUTHORIZED = 401
-
-/**
- * An agent responsible for remote calls.
- */
-open class CallAgent {
-
- private val kvUrlPrefix = window["kv_remote_url_prefix"]
- private val urlPrefix: String = if (kvUrlPrefix != undefined) kvUrlPrefix else ""
- private var counter = 1
-
- /**
- * Makes an JSON-RPC call to the remote server.
- * @param url an URL address
- * @param data data to be sent
- * @param method a HTTP method
- * @return a promise of the result
- */
- @UseExperimental(ImplicitReflectionSerializer::class)
- @Suppress("UnsafeCastFromDynamic", "ComplexMethod")
- fun jsonRpcCall(
- url: String,
- data: List<String?> = listOf(),
- method: HttpMethod = HttpMethod.POST
- ): Promise<String> {
- val jsonRpcRequest = JsonRpcRequest(counter++, url, data)
- val jsonData = if (method == HttpMethod.GET) {
- obj { id = jsonRpcRequest.id }
- } else {
- JSON.plain.stringify(jsonRpcRequest)
- }
- return Promise { resolve, reject ->
- jQuery.ajax(urlPrefix + url, obj {
- this.contentType = "application/json"
- this.data = jsonData
- this.method = method.name
- this.success =
- { data: dynamic, _: Any, _: Any ->
- when {
- data.id != jsonRpcRequest.id -> reject(Exception("Invalid response ID"))
- data.error != null -> {
- if (data.exceptionType == "pl.treksoft.kvision.remote.ServiceException") {
- reject(ServiceException(data.error.toString()))
- } else {
- reject(Exception(data.error.toString()))
- }
- }
- data.result != null -> resolve(data.result)
- else -> reject(Exception("Invalid response"))
- }
- }
- this.error =
- { xhr: JQueryXHR, _: String, errorText: String ->
- val message = if (xhr.responseJSON != null && xhr.responseJSON != undefined) {
- NativeJSON.stringify(xhr.responseJSON)
- } else if (xhr.responseText != undefined) {
- xhr.responseText
- } else {
- errorText
- }
- if (xhr.status.toInt() == HTTP_UNAUTHORIZED) {
- reject(SecurityException(message))
- } else {
- reject(Exception(message))
- }
- }
- this.xhrFields = obj {
- this.withCredentials = true
- }
- })
- }
- }
-
- /**
- * Makes a remote call to the remote server.
- * @param url an URL address
- * @param data data to be sent
- * @param method a HTTP method
- * @param contentType a content type of the request
- * @param beforeSend a function to set request parameters
- * @return a promise of the result
- */
- @Suppress("UnsafeCastFromDynamic", "ComplexMethod")
- fun remoteCall(
- url: String,
- data: dynamic = null,
- method: HttpMethod = HttpMethod.GET,
- contentType: String = "application/json",
- beforeSend: ((JQueryXHR, JQueryAjaxSettings) -> Boolean)? = null
- ): Promise<dynamic> {
- return Promise { resolve, reject ->
- jQuery.ajax(urlPrefix + url, obj {
- this.contentType = if (contentType != "multipart/form-data") contentType else false
- this.data = data
- this.method = method.name
- this.processData = if (contentType != "multipart/form-data") undefined else false
- this.success =
- { data: dynamic, _: Any, _: Any ->
- resolve(data)
- }
- this.error =
- { xhr: JQueryXHR, _: String, errorText: String ->
- val message = if (xhr.responseJSON != null && xhr.responseJSON != undefined) {
- NativeJSON.stringify(xhr.responseJSON)
- } else if (xhr.responseText != undefined) {
- xhr.responseText
- } else {
- errorText
- }
- if (xhr.status.toInt() == HTTP_UNAUTHORIZED) {
- reject(SecurityException(message))
- } else {
- reject(Exception(message))
- }
- }
- this.beforeSend = beforeSend
- this.xhrFields = obj {
- this.withCredentials = true
- }
- })
- }
- }
-}
diff --git a/kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVRemoteAgent.kt b/kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVRemoteAgent.kt
deleted file mode 100644
index 86d90e4c..00000000
--- a/kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVRemoteAgent.kt
+++ /dev/null
@@ -1,562 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.remote
-
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.asDeferred
-import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.channels.ReceiveChannel
-import kotlinx.coroutines.channels.SendChannel
-import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.launch
-import kotlinx.serialization.ImplicitReflectionSerializer
-import kotlinx.serialization.list
-import kotlinx.serialization.serializer
-import kotlinx.serialization.stringify
-import kotlin.reflect.KClass
-
-/**
- * Client side agent for JSON-RPC remote calls.
- */
-@Suppress("LargeClass", "TooManyFunctions")
-@UseExperimental(ImplicitReflectionSerializer::class, ExperimentalCoroutinesApi::class)
-open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceManager<T>) : RemoteAgent {
-
- val callAgent = CallAgent()
-
- /**
- * Executes defined call to a remote web service.
- */
- suspend inline fun <reified RET : Any, T> call(noinline function: suspend T.() -> RET): RET {
- val (url, method) =
- serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")]
- ?: throw IllegalStateException("Function not specified!")
- return callAgent.jsonRpcCall(url, method = method).then {
- try {
- @Suppress("UNCHECKED_CAST")
- deserialize<RET>(it, RET::class.js.name)
- } catch (t: NotStandardTypeException) {
- try {
- @Suppress("UNCHECKED_CAST")
- tryDeserializeEnum(RET::class as KClass<Any>, it) as RET
- } catch (t: NotEnumTypeException) {
- JSON.nonstrict.parse(RET::class.serializer(), it)
- }
- }
- }.asDeferred().await()
- }
-
- /**
- * Executes defined call to a remote web service.
- */
- suspend inline fun <reified RET : Any, T> call(
- noinline function: suspend T.() -> List<RET>
- ): List<RET> {
- val (url, method) =
- serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")]
- ?: throw IllegalStateException("Function not specified!")
- return callAgent.jsonRpcCall(url, method = method).then {
- try {
- deserializeList<RET>(it, RET::class.js.name)
- } catch (t: NotStandardTypeException) {
- try {
- @Suppress("UNCHECKED_CAST")
- tryDeserializeEnumList(RET::class as KClass<Any>, it) as List<RET>
- } catch (t: NotEnumTypeException) {
- JSON.nonstrict.parse(RET::class.serializer().list, it)
- }
- }
- }.asDeferred().await()
- }
-
- /**
- * Executes defined call to a remote web service.
- */
- suspend inline fun <reified PAR, reified RET : Any, T> call(
- noinline function: suspend T.(PAR) -> RET, p: PAR
- ): RET {
- val data = serialize(p)
- val (url, method) =
- serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")]
- ?: throw IllegalStateException("Function not specified!")
- return callAgent.jsonRpcCall(url, listOf(data), method).then {
- try {
- @Suppress("UNCHECKED_CAST")
- deserialize<RET>(it, RET::class.js.name)
- } catch (t: NotStandardTypeException) {
- try {
- @Suppress("UNCHECKED_CAST")
- tryDeserializeEnum(RET::class as KClass<Any>, it) as RET
- } catch (t: NotEnumTypeException) {
- JSON.nonstrict.parse(RET::class.serializer(), it)
- }
- }
- }.asDeferred().await()
- }
-
- /**
- * Executes defined call to a remote web service.
- */
- suspend inline fun <reified PAR, reified RET : Any, T> call(
- noinline function: suspend T.(PAR) -> List<RET>, p: PAR
- ): List<RET> {
- val data = serialize(p)
- val (url, method) =
- serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")]
- ?: throw IllegalStateException("Function not specified!")
- return callAgent.jsonRpcCall(url, listOf(data), method).then {
- try {
- deserializeList<RET>(it, RET::class.js.name)
- } catch (t: NotStandardTypeException) {
- try {
- @Suppress("UNCHECKED_CAST")
- tryDeserializeEnumList(RET::class as KClass<Any>, it) as List<RET>
- } catch (t: NotEnumTypeException) {
- JSON.nonstrict.parse(RET::class.serializer().list, it)
- }
- }
- }.asDeferred().await()
- }
-
- /**
- * Executes defined call to a remote web service.
- */
- suspend inline fun <reified PAR1, reified PAR2, reified RET : Any, T> call(
- noinline function: suspend T.(PAR1, PAR2) -> RET, p1: PAR1, p2: PAR2
- ): RET {
- val data1 = serialize(p1)
- val data2 = serialize(p2)
- val (url, method) =
- serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")]
- ?: throw IllegalStateException("Function not specified!")
- return callAgent.jsonRpcCall(url, listOf(data1, data2), method).then {
- try {
- @Suppress("UNCHECKED_CAST")
- deserialize<RET>(it, RET::class.js.name)
- } catch (t: NotStandardTypeException) {
- try {
- @Suppress("UNCHECKED_CAST")
- tryDeserializeEnum(RET::class as KClass<Any>, it) as RET
- } catch (t: NotEnumTypeException) {
- JSON.nonstrict.parse(RET::class.serializer(), it)
- }
- }
- }.asDeferred().await()
- }
-
- /**
- * Executes defined call to a remote web service.
- */
- suspend inline fun <reified PAR1, reified PAR2, reified RET : Any, T> call(
- noinline function: suspend T.(PAR1, PAR2) -> List<RET>, p1: PAR1, p2: PAR2
- ): List<RET> {
- val data1 = serialize(p1)
- val data2 = serialize(p2)
- val (url, method) =
- serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")]
- ?: throw IllegalStateException("Function not specified!")
- return callAgent.jsonRpcCall(url, listOf(data1, data2), method).then {
- try {
- deserializeList<RET>(it, RET::class.js.name)
- } catch (t: NotStandardTypeException) {
- try {
- @Suppress("UNCHECKED_CAST")
- tryDeserializeEnumList(RET::class as KClass<Any>, it) as List<RET>
- } catch (t: NotEnumTypeException) {
- JSON.nonstrict.parse(RET::class.serializer().list, it)
- }
- }
- }.asDeferred().await()
- }
-
- /**
- * Executes defined call to a remote web service.
- */
- suspend inline fun <reified PAR1, reified PAR2, reified PAR3, reified RET : Any, T> call(
- noinline function: suspend T.(PAR1, PAR2, PAR3) -> RET, p1: PAR1, p2: PAR2, p3: PAR3
- ): RET {
- val data1 = serialize(p1)
- val data2 = serialize(p2)
- val data3 = serialize(p3)
- val (url, method) =
- serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")]
- ?: throw IllegalStateException("Function not specified!")
- return callAgent.jsonRpcCall(url, listOf(data1, data2, data3), method).then {
- try {
- @Suppress("UNCHECKED_CAST")
- deserialize<RET>(it, RET::class.js.name)
- } catch (t: NotStandardTypeException) {
- try {
- @Suppress("UNCHECKED_CAST")
- tryDeserializeEnum(RET::class as KClass<Any>, it) as RET
- } catch (t: NotEnumTypeException) {
- JSON.nonstrict.parse(RET::class.serializer(), it)
- }
- }
- }.asDeferred().await()
- }
-
- /**
- * Executes defined call to a remote web service.
- */
- suspend inline fun <reified PAR1, reified PAR2, reified PAR3, reified RET : Any, T> call(
- noinline function: suspend T.(PAR1, PAR2, PAR3) -> List<RET>, p1: PAR1, p2: PAR2, p3: PAR3
- ): List<RET> {
- val data1 = serialize(p1)
- val data2 = serialize(p2)
- val data3 = serialize(p3)
- val (url, method) =
- serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")]
- ?: throw IllegalStateException("Function not specified!")
- return callAgent.jsonRpcCall(url, listOf(data1, data2, data3), method).then {
- try {
- deserializeList<RET>(it, RET::class.js.name)
- } catch (t: NotStandardTypeException) {
- try {
- @Suppress("UNCHECKED_CAST")
- tryDeserializeEnumList(RET::class as KClass<Any>, it) as List<RET>
- } catch (t: NotEnumTypeException) {
- JSON.nonstrict.parse(RET::class.serializer().list, it)
- }
- }
- }.asDeferred().await()
- }
-
- /**
- * Executes defined call to a remote web service.
- */
- suspend inline fun <reified PAR1, reified PAR2, reified PAR3, reified PAR4, reified RET : Any, T> call(
- noinline function: suspend T.(PAR1, PAR2, PAR3, PAR4) -> RET, p1: PAR1, p2: PAR2, p3: PAR3, p4: PAR4
- ): RET {
- val data1 = serialize(p1)
- val data2 = serialize(p2)
- val data3 = serialize(p3)
- val data4 = serialize(p4)
- val (url, method) =
- serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")]
- ?: throw IllegalStateException("Function not specified!")
- return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4), method).then {
- try {
- @Suppress("UNCHECKED_CAST")
- deserialize<RET>(it, RET::class.js.name)
- } catch (t: NotStandardTypeException) {
- try {
- @Suppress("UNCHECKED_CAST")
- tryDeserializeEnum(RET::class as KClass<Any>, it) as RET
- } catch (t: NotEnumTypeException) {
- JSON.nonstrict.parse(RET::class.serializer(), it)
- }
- }
- }.asDeferred().await()
- }
-
- /**
- * Executes defined call to a remote web service.
- */
- suspend inline fun <reified PAR1, reified PAR2, reified PAR3, reified PAR4, reified RET : Any, T> call(
- noinline function: suspend T.(PAR1, PAR2, PAR3, PAR4) -> List<RET>,
- p1: PAR1,
- p2: PAR2,
- p3: PAR3,
- p4: PAR4
- ): List<RET> {
- val data1 = serialize(p1)
- val data2 = serialize(p2)
- val data3 = serialize(p3)
- val data4 = serialize(p4)
- val (url, method) =
- serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")]
- ?: throw IllegalStateException("Function not specified!")
- return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4), method).then {
- try {
- deserializeList<RET>(it, RET::class.js.name)
- } catch (t: NotStandardTypeException) {
- try {
- @Suppress("UNCHECKED_CAST")
- tryDeserializeEnumList(RET::class as KClass<Any>, it) as List<RET>
- } catch (t: NotEnumTypeException) {
- JSON.nonstrict.parse(RET::class.serializer().list, it)
- }
- }
- }.asDeferred().await()
- }
-
- /**
- * Executes defined call to a remote web service.
- */
- @Suppress("LongParameterList")
- suspend inline fun <reified PAR1, reified PAR2, reified PAR3, reified PAR4, reified PAR5,
- reified RET : Any, T> call(
- noinline function: suspend T.(PAR1, PAR2, PAR3, PAR4, PAR5) -> RET,
- p1: PAR1,
- p2: PAR2,
- p3: PAR3,
- p4: PAR4,
- p5: PAR5
- ): RET {
- val data1 = serialize(p1)
- val data2 = serialize(p2)
- val data3 = serialize(p3)
- val data4 = serialize(p4)
- val data5 = serialize(p5)
- val (url, method) =
- serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")]
- ?: throw IllegalStateException("Function not specified!")
- return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4, data5), method).then {
- try {
- @Suppress("UNCHECKED_CAST")
- deserialize<RET>(it, RET::class.js.name)
- } catch (t: NotStandardTypeException) {
- try {
- @Suppress("UNCHECKED_CAST")
- tryDeserializeEnum(RET::class as KClass<Any>, it) as RET
- } catch (t: NotEnumTypeException) {
- JSON.nonstrict.parse(RET::class.serializer(), it)
- }
- }
- }.asDeferred().await()
- }
-
- /**
- * Executes defined call to a remote web service.
- */
- @Suppress("LongParameterList")
- suspend inline fun <reified PAR1, reified PAR2, reified PAR3, reified PAR4, reified PAR5,
- reified RET : Any, T> call(
- noinline function: suspend T.(PAR1, PAR2, PAR3, PAR4, PAR5) -> List<RET>,
- p1: PAR1,
- p2: PAR2,
- p3: PAR3,
- p4: PAR4,
- p5: PAR5
- ): List<RET> {
- val data1 = serialize(p1)
- val data2 = serialize(p2)
- val data3 = serialize(p3)
- val data4 = serialize(p4)
- val data5 = serialize(p5)
- val (url, method) =
- serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")]
- ?: throw IllegalStateException("Function not specified!")
- return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4, data5), method).then {
- try {
- deserializeList<RET>(it, RET::class.js.name)
- } catch (t: NotStandardTypeException) {
- try {
- @Suppress("UNCHECKED_CAST")
- tryDeserializeEnumList(RET::class as KClass<Any>, it) as List<RET>
- } catch (t: NotEnumTypeException) {
- JSON.nonstrict.parse(RET::class.serializer().list, it)
- }
- }
- }.asDeferred().await()
- }
-
- /**
- * Executes defined web socket connection
- */
- @Suppress("ComplexMethod", "TooGenericExceptionCaught")
- suspend inline fun <reified PAR1 : Any, reified PAR2 : Any> webSocket(
- noinline function: suspend T.(ReceiveChannel<PAR1>, SendChannel<PAR2>) -> Unit,
- noinline handler: suspend (SendChannel<PAR1>, ReceiveChannel<PAR2>) -> Unit
- ) {
- val (url, _) =
- serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")]
- ?: throw IllegalStateException("Function not specified!")
- val socket = Socket()
- val requestChannel = Channel<PAR1>()
- val responseChannel = Channel<PAR2>()
- try {
- coroutineScope {
- socket.connect(getWebSocketUrl(url))
- lateinit var responseJob: Job
- lateinit var handlerJob: Job
- val requestJob = launch {
- for (par1 in requestChannel) {
- val param = serialize(par1)
- val str = JSON.plain.stringify(JsonRpcRequest(0, url, listOf(param)))
- if (!socket.sendOrFalse(str)) break
- }
- responseJob.cancel()
- handlerJob.cancel()
- if (!requestChannel.isClosedForReceive) requestChannel.close()
- if (!responseChannel.isClosedForSend) responseChannel.close()
- }
- responseJob = launch {
- while (true) {
- val str = socket.receiveOrNull() ?: break
- val data = kotlin.js.JSON.parse<JsonRpcResponse>(str).result ?: ""
- val par2 = try {
- @Suppress("UNCHECKED_CAST")
- deserialize<PAR2>(data, PAR2::class.js.name)
- } catch (t: NotStandardTypeException) {
- try {
- @Suppress("UNCHECKED_CAST")
- tryDeserializeEnum(PAR2::class as KClass<Any>, data) as PAR2
- } catch (t: NotEnumTypeException) {
- JSON.nonstrict.parse(PAR2::class.serializer(), data)
- }
- }
- responseChannel.send(par2)
- }
- requestJob.cancel()
- handlerJob.cancel()
- if (!requestChannel.isClosedForReceive) requestChannel.close()
- if (!responseChannel.isClosedForSend) responseChannel.close()
- }
- handlerJob = launch {
- exceptionHelper {
- handler(requestChannel, responseChannel)
- }
- requestJob.cancel()
- responseJob.cancel()
- if (!requestChannel.isClosedForReceive) requestChannel.close()
- if (!responseChannel.isClosedForSend) responseChannel.close()
- }
- }
- } catch (e: Exception) {
- console.log(e)
- }
- if (!requestChannel.isClosedForReceive) requestChannel.close()
- if (!responseChannel.isClosedForSend) responseChannel.close()
- socket.close()
- }
-
- /**
- * Executes defined web socket connection returning list objects
- */
- @Suppress("ComplexMethod", "TooGenericExceptionCaught")
- suspend inline fun <reified PAR1 : Any, reified PAR2 : Any> webSocket(
- noinline function: suspend T.(ReceiveChannel<PAR1>, SendChannel<List<PAR2>>) -> Unit,
- noinline handler: suspend (SendChannel<PAR1>, ReceiveChannel<List<PAR2>>) -> Unit
- ) {
- val (url, _) =
- serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")]
- ?: throw IllegalStateException("Function not specified!")
- val socket = Socket()
- val requestChannel = Channel<PAR1>()
- val responseChannel = Channel<List<PAR2>>()
- try {
- coroutineScope {
- socket.connect(getWebSocketUrl(url))
- lateinit var responseJob: Job
- lateinit var handlerJob: Job
- val requestJob = launch {
- for (par1 in requestChannel) {
- val param = serialize(par1)
- val str = JSON.plain.stringify(JsonRpcRequest(0, url, listOf(param)))
- if (!socket.sendOrFalse(str)) break
- }
- responseJob.cancel()
- handlerJob.cancel()
- if (!requestChannel.isClosedForReceive) requestChannel.close()
- if (!responseChannel.isClosedForSend) responseChannel.close()
- }
- responseJob = launch {
- while (true) {
- val str = socket.receiveOrNull() ?: break
- val data = kotlin.js.JSON.parse<JsonRpcResponse>(str).result ?: ""
- val par2 = try {
- deserializeList<PAR2>(data, PAR2::class.js.name)
- } catch (t: NotStandardTypeException) {
- try {
- @Suppress("UNCHECKED_CAST")
- tryDeserializeEnumList(PAR2::class as KClass<Any>, data) as List<PAR2>
- } catch (t: NotEnumTypeException) {
- JSON.nonstrict.parse(PAR2::class.serializer().list, data)
- }
- }
- responseChannel.send(par2)
- }
- requestJob.cancel()
- handlerJob.cancel()
- if (!requestChannel.isClosedForReceive) requestChannel.close()
- if (!responseChannel.isClosedForSend) responseChannel.close()
- }
- handlerJob = launch {
- exceptionHelper {
- handler(requestChannel, responseChannel)
- }
- requestJob.cancel()
- responseJob.cancel()
- if (!requestChannel.isClosedForReceive) requestChannel.close()
- if (!responseChannel.isClosedForSend) responseChannel.close()
- }
- }
- } catch (e: Exception) {
- console.log(e)
- }
- if (!requestChannel.isClosedForReceive) requestChannel.close()
- if (!responseChannel.isClosedForSend) responseChannel.close()
- socket.close()
- }
-
- /**
- * @suppress internal function
- */
- suspend fun Socket.receiveOrNull(): String? {
- return try {
- this.receive()
- } catch (e: SocketClosedException) {
- console.log("Socket was closed: ${e.reason}")
- null
- }
- }
-
- /**
- * @suppress internal function
- */
- fun Socket.sendOrFalse(str: String): Boolean {
- return try {
- this.send(str)
- true
- } catch (e: SocketClosedException) {
- console.log("Socket was closed: ${e.reason}")
- false
- }
- }
-
- /**
- * @suppress internal function
- */
- @Suppress("TooGenericExceptionCaught")
- suspend fun exceptionHelper(block: suspend () -> Unit) {
- try {
- block()
- } catch (e: Exception) {
- console.log(e)
- }
- }
-
- /**
- * @suppress
- * Internal function
- */
- inline fun <reified PAR> serialize(value: PAR): String? {
- return value?.let {
- @Suppress("UNCHECKED_CAST")
- trySerialize((PAR::class as KClass<Any>), it as Any)
- }
- }
-
-}
diff --git a/kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt b/kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt
deleted file mode 100644
index aaf63153..00000000
--- a/kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.remote
-
-import kotlinx.coroutines.channels.ReceiveChannel
-import kotlinx.coroutines.channels.SendChannel
-import kotlin.reflect.KClass
-
-/**
- * Multiplatform service manager.
- */
-actual open class KVServiceManager<T : Any> actual constructor(serviceClass: KClass<T>) {
-
- protected val calls: MutableMap<String, Pair<String, HttpMethod>> = mutableMapOf()
- var counter: Int = 0
-
- /**
- * Binds a given route with a function of the receiver.
- * @param function a function of the receiver
- * @param method a HTTP method
- * @param route a route
- */
- protected actual inline fun <reified RET> bind(
- noinline function: suspend T.() -> RET,
- method: HttpMethod, route: String?
- ) {
- val routeDef = route ?: "route${this::class.simpleName}${counter++}"
- calls[function.toString().replace("\\s".toRegex(), "")] = Pair("/kv/$routeDef", method)
- }
-
- /**
- * Binds a given route with a function of the receiver.
- * @param function a function of the receiver
- * @param method a HTTP method
- * @param route a route
- */
- protected actual inline fun <reified PAR, reified RET> bind(
- noinline function: suspend T.(PAR) -> RET,
- method: HttpMethod, route: String?
- ) {
- if (method == HttpMethod.GET)
- throw UnsupportedOperationException("GET method is only supported for methods without parameters")
- val routeDef = route ?: "route${this::class.simpleName}${counter++}"
- calls[function.toString().replace("\\s".toRegex(), "")] = Pair("/kv/$routeDef", method)
- }
-
- /**
- * Binds a given route with a function of the receiver.
- * @param function a function of the receiver
- * @param method a HTTP method
- * @param route a route
- */
- pr