diff options
author | Robert Jaros <rjaros@finn.pl> | 2018-12-18 18:54:27 +0100 |
---|---|---|
committer | Robert Jaros <rjaros@finn.pl> | 2018-12-18 18:54:27 +0100 |
commit | 161264957dc1b41cd6716ee7777139c5e29589f5 (patch) | |
tree | c7977850428319b17888f2c7ceffc2557e68a360 /src/main/kotlin/pl/treksoft/kvision/remote | |
parent | 1fbd940e57b6917ab6677ff285f632f0d10f4809 (diff) | |
download | kvision-161264957dc1b41cd6716ee7777139c5e29589f5.tar.gz kvision-161264957dc1b41cd6716ee7777139c5e29589f5.tar.bz2 kvision-161264957dc1b41cd6716ee7777139c5e29589f5.zip |
Refactor modules.
Diffstat (limited to 'src/main/kotlin/pl/treksoft/kvision/remote')
8 files changed, 0 insertions, 1575 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/remote/CallAgent.kt b/src/main/kotlin/pl/treksoft/kvision/remote/CallAgent.kt deleted file mode 100644 index 4a086e2a..00000000 --- a/src/main/kotlin/pl/treksoft/kvision/remote/CallAgent.kt +++ /dev/null @@ -1,135 +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 pl.treksoft.jquery.JQueryAjaxSettings -import pl.treksoft.jquery.JQueryXHR -import pl.treksoft.jquery.jQuery -import pl.treksoft.kvision.utils.JSON -import pl.treksoft.kvision.utils.obj -import kotlin.js.Promise -import kotlin.js.undefined -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 var counter = 1 - - /** - * Makes an JSON-RPC call to the remote server. - * @param url an URL address - * @param method a HTTP method - * @param data data to be sent - * @return a promise of the result - */ - @UseExperimental(ImplicitReflectionSerializer::class) - @Suppress("UnsafeCastFromDynamic") - fun jsonRpcCall( - url: String, - data: List<String?> = listOf(), - method: RpcHttpMethod = RpcHttpMethod.POST - ): Promise<String> { - val jsonRpcRequest = JsonRpcRequest(counter++, url, data) - val jsonData = JSON.plain.stringify(jsonRpcRequest) - return Promise { resolve, reject -> - jQuery.ajax(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 -> 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) { - xhr.responseJSON.toString() - } else { - errorText - } - if (xhr.status.toInt() == HTTP_UNAUTHORIZED) { - reject(SecurityException(message)) - } else { - reject(Exception(message)) - } - } - }) - } - } - - /** - * Makes a remote call to the remote server. - * @param url an URL address - * @param method a HTTP method - * @param data data to be sent - * @return a promise of the result - */ - @Suppress("UnsafeCastFromDynamic") - 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(url, obj { - this.contentType = contentType - this.data = data - this.method = method.name - this.success = - { data: dynamic, _: Any, _: Any -> - resolve(data) - } - this.error = - { xhr: JQueryXHR, _: String, errorText: String -> - val message = if (xhr.responseJSON != null && xhr.responseJSON != undefined) { - xhr.responseJSON.toString() - } else { - errorText - } - if (xhr.status.toInt() == HTTP_UNAUTHORIZED) { - reject(SecurityException(message)) - } else { - reject(Exception(message)) - } - } - this.beforeSend = beforeSend - }) - } - } -} diff --git a/src/main/kotlin/pl/treksoft/kvision/remote/JoobyRemoteAgent.kt b/src/main/kotlin/pl/treksoft/kvision/remote/JoobyRemoteAgent.kt deleted file mode 100644 index 318f77ea..00000000 --- a/src/main/kotlin/pl/treksoft/kvision/remote/JoobyRemoteAgent.kt +++ /dev/null @@ -1,370 +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.asDeferred -import kotlinx.serialization.ImplicitReflectionSerializer -import kotlinx.serialization.list -import kotlinx.serialization.serializer -import pl.treksoft.kvision.utils.JSON -import kotlin.js.js -import kotlin.reflect.KClass -import kotlin.js.JSON as NativeJSON - -/** - * Client side agent for JSON-RPC remote calls with Jooby. - */ -@Suppress("LargeClass", "TooManyFunctions") -@UseExperimental(ImplicitReflectionSerializer::class) -open class JoobyRemoteAgent<T : Any>(val serviceManager: JoobyServiceManager<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.(Request?) -> RET): RET { - val (url, method) = - serviceManager.getCalls()[function.toString()] ?: 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.(Request?) -> List<RET> - ): List<RET> { - val (url, method) = - serviceManager.getCalls()[function.toString()] ?: 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, Request?) -> RET, p: PAR - ): RET { - val data = serialize(p) - val (url, method) = - serviceManager.getCalls()[function.toString()] ?: 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, Request?) -> List<RET>, p: PAR - ): List<RET> { - val data = serialize(p) - val (url, method) = - serviceManager.getCalls()[function.toString()] ?: 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, Request?) -> RET, p1: PAR1, p2: PAR2 - ): RET { - val data1 = serialize(p1) - val data2 = serialize(p2) - val (url, method) = - serviceManager.getCalls()[function.toString()] ?: 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, Request?) -> List<RET>, p1: PAR1, p2: PAR2 - ): List<RET> { - val data1 = serialize(p1) - val data2 = serialize(p2) - val (url, method) = - serviceManager.getCalls()[function.toString()] ?: 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, Request?) -> 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()] ?: 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, Request?) -> 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()] ?: 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, Request?) -> 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()] ?: 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, Request?) -> 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()] ?: 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, Request?) -> 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()] ?: 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, Request?) -> 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()] ?: 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() - } - - - /** - * @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/src/main/kotlin/pl/treksoft/kvision/remote/JoobyServiceManager.kt b/src/main/kotlin/pl/treksoft/kvision/remote/JoobyServiceManager.kt deleted file mode 100644 index 0d3515a1..00000000 --- a/src/main/kotlin/pl/treksoft/kvision/remote/JoobyServiceManager.kt +++ /dev/null @@ -1,129 +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 - -/** - * Multiplatform service manager for Jooby. - */ -actual open class JoobyServiceManager<T : Any> actual constructor(service: T) : ServiceManager { - - protected val calls: MutableMap<String, Pair<String, RpcHttpMethod>> = mutableMapOf() - var counter: Int = 0 - - /** - * Binds a given route with a function of the receiver. - * @param function a function of the receiver - * @param route a route - * @param method a HTTP method - */ - protected actual inline fun <reified RET> bind( - noinline function: suspend T.(Request?) -> RET, - route: String?, method: RpcHttpMethod - ) { - val routeDef = route ?: "route${this::class.simpleName}${counter++}" - calls[function.toString()] = Pair("/kv/$routeDef", method) - } - - /** - * Binds a given route with a function of the receiver. - * @param function a function of the receiver - * @param route a route - * @param method a HTTP method - */ - protected actual inline fun <reified PAR, reified RET> bind( - noinline function: suspend T.(PAR, Request?) -> RET, - route: String?, method: RpcHttpMethod - ) { - val routeDef = route ?: "route${this::class.simpleName}${counter++}" - calls[function.toString()] = Pair("/kv/$routeDef", method) - } - - /** - * Binds a given route with a function of the receiver. - * @param function a function of the receiver - * @param route a route - * @param method a HTTP method - */ - protected actual inline fun <reified PAR1, reified PAR2, reified RET> bind( - noinline function: suspend T.(PAR1, PAR2, Request?) -> RET, - route: String?, method: RpcHttpMethod - ) { - val routeDef = route ?: "route${this::class.simpleName}${counter++}" - calls[function.toString()] = Pair("/kv/$routeDef", method) - } - - /** - * Binds a given route with a function of the receiver. - * @param function a function of the receiver - * @param route a route - * @param method a HTTP method - */ - protected actual inline fun <reified PAR1, reified PAR2, reified PAR3, reified RET> bind( - noinline function: suspend T.(PAR1, PAR2, PAR3, Request?) -> RET, - route: String?, method: RpcHttpMethod - ) { - val routeDef = route ?: "route${this::class.simpleName}${counter++}" - calls[function.toString()] = Pair("/kv/$routeDef", method) - } - - /** - * Binds a given route with a function of the receiver. - * @param function a function of the receiver - * @param route a route - * @param method a HTTP method - */ - protected actual inline fun <reified PAR1, reified PAR2, reified PAR3, reified PAR4, reified RET> bind( - noinline function: suspend T.(PAR1, PAR2, PAR3, PAR4, Request?) -> RET, - route: String?, method: RpcHttpMethod - ) { - val routeDef = route ?: "route${this::class.simpleName}${counter++}" - calls[function.toString()] = Pair("/kv/$routeDef", method) - } - - /** - * Binds a given route with a function of the receiver. - * @param function a function of the receiver - * @param route a route - * @param method a HTTP method - */ - protected actual inline fun <reified PAR1, reified PAR2, reified PAR3, - reified PAR4, reified PAR5, reified RET> bind( - noinline function: suspend T.(PAR1, PAR2, PAR3, PAR4, PAR5, Request?) -> RET, - route: String?, - method: RpcHttpMethod - ) { - val routeDef = route ?: "route${this::class.simpleName}${counter++}" - calls[function.toString()] = Pair("/kv/$routeDef", method) - } - - /** - * Applies all defined routes to the given server. - * Not used on the js platform. - */ - actual fun applyRoutes(k: KVServer) { - } - - /** - * Returns the map of defined paths. - */ - override fun getCalls(): Map<String, Pair<String, RpcHttpMethod>> = calls -} diff --git a/src/main/kotlin/pl/treksoft/kvision/remote/KVServer.kt b/src/main/kotlin/pl/treksoft/kvision/remote/KVServer.kt deleted file mode 100644 index a1cc40ca..00000000 --- a/src/main/kotlin/pl/treksoft/kvision/remote/KVServer.kt +++ /dev/null @@ -1,123 +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.Serializable -import kotlinx.serialization.Transient - -/** - * A server. - * Not used on the js platform. - */ -actual open class KVServer - -/** - * A server request. - * Not used on the js platform. - */ -actual interface Request - -/** - * A user profile. - */ -@Serializable -actual data class Profile( - val id: String? = null, - val attributes: MutableMap<String, String> = mutableMapOf(), - val authenticationAttributes: MutableMap<String, String> = mutableMapOf(), - val roles: MutableSet<String> = mutableSetOf(), - val permissions: MutableSet<String> = mutableSetOf(), - val linkedId: String? = null, - val remembered: Boolean = false, - val clientName: String? = null -) { - @Transient - var username: String? - get() = attributes["username"] - set(value) { - if (value != null) { - attributes["username"] = value - } else { - attributes.remove("username") - } - } - @Transient - var firstName: String? - get() = attributes["first_name"] - set(value) { - if (value != null) { - attributes["first_name"] = value - } else { - attributes.remove("first_name") - } - } - @Transient - var familyName: String? - get() = attributes["family_name"] - set(value) { - if (value != null) { - attributes["family_name"] = value - } else { - attributes.remove("family_name") - } - } - @Transient - var displayName: String? - get() = attributes["display_name"] - set(value) { - if (value != null) { - attributes["display_name"] = value - } else { - attributes.remove("display_name") - } - } - @Transient - var email: String? - get() = attributes["email"] - set(value) { - if (value != null) { - attributes["email"] = value - } else { - attributes.remove("email") - } - } - @Transient - var pictureUrl: String? - get() = attributes["picture_url"] - set(value) { - if (value != null) { - attributes["picture_url"] = value - } else { - attributes.remove("picture_url") - } - } - @Transient - var profileUrl: String? - get() = attributes["profile_url"] - set(value) { - if (value != null) { - attributes["profile_url"] = value - } else { - attributes.remove("profile_url") - } - } -} diff --git a/src/main/kotlin/pl/treksoft/kvision/remote/RemoteAgent.kt b/src/main/kotlin/pl/treksoft/kvision/remote/RemoteAgent.kt deleted file mode 100644 index cbb2978a..00000000 --- a/src/main/kotlin/pl/treksoft/kvision/remote/RemoteAgent.kt +++ /dev/null @@ -1,208 +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.KSerializer -import kotlinx.serialization.internal.BooleanSerializer -import kotlinx.serialization.internal.ByteSerializer -import kotlinx.serialization.internal.CharSerializer -import kotlinx.serialization.internal.DoubleSerializer -import kotlinx.serialization.internal.FloatSerializer -import kotlinx.serialization.internal.IntSerializer -import kotlinx.serialization.internal.LongSerializer -import kotlinx.serialization.internal.ShortSerializer -import kotlinx.serialization.internal.StringSerializer -import kotlinx.serialization.list -import kotlinx.serialization.serializer -import pl.treksoft.kvision.types.DateSerializer -import pl.treksoft.kvision.types.toStringF -import pl.treksoft.kvision.utils.JSON -import kotlin.js.Date -import kotlin.reflect.KClass - -internal class NotStandardTypeException(type: String) : Exception("Not a standard type: $type!") - -internal class NotEnumTypeException : Exception("Not the Enum type!") - -/** - * Interface for client side agent for JSON-RPC remote calls. - */ -interface RemoteAgent { - - /** - * @suppress - * Internal function - */ - @UseExperimental(ImplicitReflectionSerializer::class) - @Suppress("ComplexMethod", "TooGenericExceptionCaught", "NestedBlockDepth") - fun trySerialize(kClass: KClass<Any>, value: Any): String { - return if (value is List<*>) { - if (value.size > 0) { - when { - value[0] is String -> - @Suppress("UNCHECKED_CAST") - JSON.plain.stringify(StringSerializer.list as KSerializer<Any>, value) - value[0] is Date -> - @Suppress("UNCHECKED_CAST") - JSON.plain.stringify(DateSerializer.list as KSerializer<Any>, value) - value[0] is Int -> - @Suppress("UNCHECKED_CAST") - JSON.plain.stringify(IntSerializer.list as KSerializer<Any>, value) - value[0] is Long -> - @Suppress("UNCHECKED_CAST") - JSON.plain.stringify(LongSerializer.list as KSerializer<Any>, value) - value[0] is Boolean -> - @Suppress("UNCHECKED_CAST") - JSON.plain.stringify(BooleanSerializer.list as KSerializer<Any>, value) - value[0] is Float -> - @Suppress("UNCHECKED_CAST") - JSON.plain.stringify(FloatSerializer.list as KSerializer<Any>, value) - value[0] is Double -> - @Suppress("UNCHECKED_CAST") - JSON.plain.stringify(DoubleSerializer.list as KSerializer<Any>, value) - value[0] is Char -> - @Suppress("UNCHECKED_CAST") - JSON.plain.stringify(CharSerializer.list as KSerializer<Any>, value) - value[0] is Short -> - @Suppress("UNCHECKED_CAST") - JSON.plain.stringify(ShortSerializer.list as KSerializer<Any>, value) - value[0] is Byte -> - @Suppress("UNCHECKED_CAST") - JSON.plain.stringify(ByteSerializer.list as KSerializer<Any>, value) - value[0] is Enum<*> -> "[" + value.joinToString(",") { "\"$it\"" } + "]" - else -> try { - @Suppress("UNCHECKED_CAST") - JSON.plain.stringify(kClass.serializer().list as KSerializer<Any>, value) - } catch (e: Throwable) { - try { - @Suppress("UNCHECKED_CAST") - JSON.plain.stringify(value[0]!!::class.serializer().list as KSerializer<Any>, value) - } catch (e: Throwable) { - try { - @Suppress("UNCHECKED_CAST") - JSON.plain.stringify(StringSerializer.list as KSerializer<Any>, value) - } catch (e: Throwable) { - value.toString() - } - } - } - } - } else { - "[]" - } - } else { - when (value) { - is Enum<*> -> "\"$value\"" - is String -> value - is Char -> "\"$value\"" - is Date -> "\"${value.toStringF()}\"" - else -> try { - @Suppress("UNCHECKED_CAST") - JSON.plain.stringify(kClass.serializer(), value) - } catch (e: Throwable) { - value.toString() - } - } - } - } - - /** - * @suppress - * Internal function - */ - @Suppress("UNCHECKED_CAST", "ComplexMethod") - fun <RET> deserialize(value: String, jsType: String): RET { - return when (jsType) { - "String" -> JSON.plain.parse(StringSerializer, value) as RET - "Number" -> JSON.plain.parse(DoubleSerializer, value) as RET - "Long" -> JSON.plain.parse(LongSerializer, value) as RET - "Boolean" -> JSON.plain.parse(BooleanSerializer, value) as RET - "BoxedChar" -> JSON.plain.parse(CharSerializer, value) as RET - "Short" -> JSON.plain.parse(ShortSerializer, value) as RET - "Date" -> JSON.plain.parse(DateSerializer, value) as RET - "Byte" -> JSON.plain.parse(ByteSerializer, value) as RET - else -> throw NotStandardTypeException(jsType) - } - } - - /** - * @suppress - * Internal function - */ - @Suppress("UNCHECKED_CAST", "ComplexMethod") - fun <RET> deserializeList(value: String, jsType: String): List<RET> { - return when (jsType) { - "String" -> JSON.plain.parse(StringSerializer.list, value) as List<RET> - "Number" -> JSON.plain.parse(DoubleSerializer.list, value) as List<RET> - "Long" -> JSON.plain.parse(LongSerializer.list, value) as List<RET> - "Boolean" -> JSON.plain.parse(BooleanSerializer.list, value) as List<RET> - "BoxedChar" -> JSON.plain.parse(CharSerializer.list, value) as List<RET> - "Short" -> JSON.plain.parse(ShortSerializer.list, value) as List<RET> - "Date" -> JSON.plain.parse(DateSerializer.list, value) as List<RET> - "Byte" -> JSON.plain.parse(ByteSerializer.list, value) as List<RET> - else -> throw NotStandardTypeException(jsType) - } - } - - /** - * @suppress - * Internal function - */ - @Suppress("TooGenericExceptionCaught", "ThrowsCount") - fun tryDeserializeEnum(kClass: KClass<Any>, value: String): Any { - return try { - if (kClass.asDynamic().jClass.`$metadata$`.interfaces[0].name == "Enum") { - findEnumValue(kClass, JSON.plain.parse(StringSerializer, value)) ?: throw NotEnumTypeException() - } else { - throw NotEnumTypeException() - } - } catch (e: Throwable) { - throw NotEnumTypeException() - } - } - - /** - * @suppress - * Internal function - */ - @Suppress("TooGenericExceptionCaught", "ThrowsCount") - fun tryDeserializeEnumList(kClass: KClass<Any>, value: String): List<Any> { - return try { - if (kClass.asDynamic().jClass.`$metadata$`.interfaces[0].name == "Enum") { - JSON.plain.parse(StringSerializer.list, value).map { - findEnumValue(kClass, JSON.plain.parse(StringSerializer, it)) ?: throw NotEnumTypeException() - } - } else { - throw NotEnumTypeException() - } - } catch (e: Throwable) { - throw NotEnumTypeException() - } - } - - private fun findEnumValue(kClass: KClass<Any>, value: String): Any? { - return (kClass.asDynamic().jClass.values() as Array<Any>).find { - it.asDynamic().name == value - } - } -} diff --git a/src/main/kotlin/pl/treksoft/kvision/remote/Security.kt b/src/main/kotlin/pl/treksoft/kvision/remote/Security.kt deleted file mode 100644 index b485e17d..00000000 --- a/src/main/kotlin/pl/treksoft/kvision/remote/Security.kt +++ /dev/null @@ -1,116 +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.asDeferred -import kotlinx.serialization.Serializable -import pl.treksoft.kvision.utils.obj - -/** - * A security exception. - */ -class SecurityException(message: String) : Exception(message) - -/** - * Username and password credentials. - */ -@Serializable -data class Credentials(val username: String? = null, val password: String? = null) - -/** - * Pac4j form login dispatcher. - */ -class LoginService { - val loginAgent = CallAgent() - - /** - * Login with Pac4j FormClient. - * @param credentials username and password credentials - */ - suspend fun login(credentials: Credentials?): Boolean = - if (credentials?.username != null) { - loginAgent.remoteCall("callback?client_name=FormClient", obj { - this.username = credentials.username - this.password = credentials.password - }, HttpMethod.POST, "application/x-www-form-urlencoded").then { _: dynamic -> true }.asDeferred().await() - } else { - throw SecurityException("Credentials cannot be empty") - } -} - -/** - * Pac4j form login dispatcher. - */ -abstract class SecurityMgr { - - private var isLoggedIn = false - - /** - * Executes given block of code after successful authentication. - * @param block a block of code - */ - @Suppress("NestedBlockDepth", "TooGenericExceptionCaught") - suspend fun <T> withAuth(block: suspend () -> T): T { - return try { - block().also { - if (!isLoggedIn) { - isLoggedIn = true - afterLogin() - } - } - } catch (e: Exception) { - if (e is SecurityException || !isLoggedIn) { - afterError() - isLoggedIn = false - while (!isLoggedIn) { - try { - login() - isLoggedIn = true - afterLogin() - } catch (e: Throwable) { - console.log(e) - } - } - block() - } else { - throw e - } - } - } - - /** - * Login user. - * @return true if login is successful - * @throws SecurityException if login is not successful - */ - abstract suspend fun login(): Boolean - - /** - * Method called after successful login. - */ - open suspend fun afterLogin() {} - - /** - * Method called after error. - */ - open suspend fun afterError() {} -} diff --git a/src/main/kotlin/pl/treksoft/kvision/remote/SpringRemoteAgent.kt b/src/main/kotlin/pl/treksoft/kvision/remote/SpringRemoteAgent.kt deleted file mode 100644 index fea16b99..00000000 --- a/src/main/kotlin/pl/treksoft/kvision/remote/SpringRemoteAgent.kt +++ /dev/null @@ -1,370 +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.asDeferred -import kotlinx.serialization.ImplicitReflectionSerializer -import kotlinx.serialization.list -import kotlinx.serialization.serializer -import pl.treksoft.kvision.utils.JSON -import kotlin.js.js -import kotlin.reflect.KClass -import kotlin.js.JSON as NativeJSON - -/** - * Client side agent for JSON-RPC remote calls with Spring Boot. - */ -@Suppress("LargeClass", "TooManyFunctions") -@UseExperimental(ImplicitReflectionSerializer::class) -open class SpringRemoteAgent<T : Any>(val serviceManager: SpringServiceManager<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()] ?: 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()] ?: 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()] ?: 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()] ?: 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()] ?: 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()] ?: 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()] ?: 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()] ?: 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()] ?: 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()] ?: 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()] ?: 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()] ?: 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() - } - - - /** - * @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/src/main/kotlin/pl/treksoft/kvision/remote/SpringServiceManager.kt b/src/main/kotlin/pl/treksoft/kvision/remote/SpringServiceManager.kt deleted file mode 100644 index 524347d7..00000000 --- a/src/main/kotlin/pl/treksoft/kvision/remote/SpringServiceManager.kt +++ /dev/null @@ -1,124 +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 kotlin.reflect.KClass - -/** - * Multiplatform service manager for Spring Boot. - */ -actual open class SpringServiceManager<T : Any> actual constructor(serviceClass: KClass<T>) : ServiceManager { - - protected val calls: MutableMap<String, Pair<String, RpcHttpMethod>> = mutableMapOf() - var counter: Int = 0 - - /** - * Binds a given route with a function of the receiver. - * @param function a function of the receiver - * @param route a route - * @param method a HTTP method - */ - protected actual inline fun <reified RET> bind( - noinline function: suspend T.() -> RET, - route: String?, method: RpcHttpMethod - ) { - val routeDef = route ?: "route${this::class.simpleName}${counter++}" - calls[function.toString()] = Pair("/kv/$routeDef", method) - } - - /** - * Binds a given route with a function of the receiver. - * @param function a function of the receiver - * @param route a route - * @param method a HTTP method - */ - protected actual inline fun <reified PAR, reified RET> bind( - noinline function: suspend T.(PAR) -> RET, - route: String?, method: RpcHttpMethod - ) { - val routeDef = route ?: "route${this::class.simpleName}${counter++}" - calls[function.toString()] = Pair("/kv/$routeDef", method) - } - - /** - * Binds a given route with a function of the receiver. - * @param function a function of the receiver - * @param route a route - * @param method a HTTP method - */ - protected actual inline fun <reified PAR1, reified PAR2, reified RET> bind( - noinline function: suspend T.(PAR1, PAR2) -> RET, - route: String?, method: RpcHttpMethod - ) { - val routeDef = route ?: "route${this::class.simpleName}${counter++}" - calls[function.toString()] = Pair("/kv/$routeDef", method) - } - - /** - * Binds a given route with a function of the receiver. - * @param function a function of the receiver - * @param route a route - * @param method a HTTP method - */ - protected actual inline fun <reified PAR1, reified PAR2, reified PAR3, reified RET> bind( - noinline function: suspend T.(PAR1, PAR2, PAR3) -> RET, - route: String?, method: RpcHttpMethod - ) { - val routeDef = route ?: "route${this::class.simpleName}${counter++}" - calls[function.toString()] = Pair("/kv/$routeDef", method) - } - - /** - * Binds a given route with a function of the receiver. - * @param function a function of the receiver - * @param route a route - * @param method a HTTP method - */ - protected actual inline fun <reified PAR1, reified PAR2, reified PAR3, reified PAR4, reified RET> bind( - noinline function: suspend T.(PAR1, PAR2, PAR3, PAR4) -> RET, - route: String?, method: RpcHttpMethod - ) { - val routeDef = route ?: "route${this::class.simpleName}${counter++}" - calls[function.toString()] = Pair("/kv/$routeDef", method) - } - - /** - * Binds a given route with a function of the receiver. - * @param function a function of the receiver - * @param route a route - * @param method a HTTP method - */ - protected actual inline fun <reified PAR1, reified PAR2, reified PAR3, - reified PAR4, reified PAR5, reified RET> bind( - noinline function: suspend T.(PAR1, PAR2, PAR3, PAR4, PAR5) -> RET, - route: String?, - method: RpcHttpMethod - ) { - val routeDef = route ?: "route${this::class.simpleName}${counter++}" - calls[function.toString()] = Pair("/kv/$routeDef", method) - } - - /** - * Returns the map of defined paths. - */ - override fun getCalls(): Map<String, Pair<String, RpcHttpMethod>> = calls -} |