+login by token and server library improvements
This commit is contained in:
parent
5df6709983
commit
449de2e504
@ -44,7 +44,7 @@ kotlin {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3")
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3")
|
||||||
api("net.sergeych:unikrypto:1.2.1-SNAPSHOT")
|
api("net.sergeych:unikrypto:1.2.1-SNAPSHOT")
|
||||||
api("net.sergeych:parsec3:0.3.1-SNAPSHOT")
|
api("net.sergeych:parsec3:0.3.2-SNAPSHOT")
|
||||||
api("net.sergeych:boss-serialization-mp:0.2.4-SNAPSHOT")
|
api("net.sergeych:boss-serialization-mp:0.2.4-SNAPSHOT")
|
||||||
3 }
|
3 }
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ class SuperloginClient<D, S : WithAdapter>(
|
|||||||
adapterReady = CompletableDeferred()
|
adapterReady = CompletableDeferred()
|
||||||
}
|
}
|
||||||
globalLaunch {
|
globalLaunch {
|
||||||
transport.adapter().invokeCommand(api.slLogout)
|
transport.adapter().invokeCommand(serverApi.slLogout)
|
||||||
adapterReady.complete(Unit)
|
adapterReady.complete(Unit)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -102,12 +102,12 @@ class SuperloginClient<D, S : WithAdapter>(
|
|||||||
|
|
||||||
private var jobs = listOf<Job>()
|
private var jobs = listOf<Job>()
|
||||||
|
|
||||||
private val api = SuperloginServerApi<WithAdapter>()
|
private val serverApi = SuperloginServerApi<WithAdapter>()
|
||||||
|
|
||||||
private suspend fun tryRestoreLogin() {
|
private suspend fun tryRestoreLogin() {
|
||||||
slData?.loginToken?.let { token ->
|
slData?.loginToken?.let { token ->
|
||||||
try {
|
try {
|
||||||
val ar = transport.adapter().invokeCommand(api.slLoginByToken, token)
|
val ar = transport.adapter().invokeCommand(serverApi.slLoginByToken, token)
|
||||||
slData = if (ar is AuthenticationResult.Success) {
|
slData = if (ar is AuthenticationResult.Success) {
|
||||||
val data: D? = ar.applicationData?.let { BossDecoder.decodeFrom(dataType, it) }
|
val data: D? = ar.applicationData?.let { BossDecoder.decodeFrom(dataType, it) }
|
||||||
SuperloginData(ar.loginToken, data)
|
SuperloginData(ar.loginToken, data)
|
||||||
@ -170,11 +170,14 @@ class SuperloginClient<D, S : WithAdapter>(
|
|||||||
return rn.registerWithData(loginName, password, extraData = BossEncoder.encode(dataType, data))
|
return rn.registerWithData(loginName, password, extraData = BossEncoder.encode(dataType, data))
|
||||||
.also { rr ->
|
.also { rr ->
|
||||||
if (rr is Registration.Result.Success) {
|
if (rr is Registration.Result.Success) {
|
||||||
slData = SuperloginData(rr.loginToken, rr.encodedData?.let { BossDecoder.decodeFrom(dataType, it) })
|
slData = SuperloginData(rr.loginToken, extractData(rr.encodedData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun extractData(rr: ByteArray?): D?
|
||||||
|
= rr?.let { BossDecoder.decodeFrom(dataType, it) }
|
||||||
|
|
||||||
private fun mustBeLoggedOut() {
|
private fun mustBeLoggedOut() {
|
||||||
if (isLoggedIn)
|
if (isLoggedIn)
|
||||||
throw IllegalStateException("please log out first")
|
throw IllegalStateException("please log out first")
|
||||||
@ -190,14 +193,24 @@ class SuperloginClient<D, S : WithAdapter>(
|
|||||||
slData = null
|
slData = null
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun LoginByToken(token: ByteArray): SuperloginData<D> {
|
/**
|
||||||
|
* Try to log in by specified token, returned by [Registration.Result.Success.loginToken] or
|
||||||
|
* [SuperloginData.loginToken] respectively.
|
||||||
|
*
|
||||||
|
* @return updated login data (and new token value) or null if token is not (or not anymore)
|
||||||
|
* available for logging in.
|
||||||
|
*/
|
||||||
|
suspend fun loginByToken(token: ByteArray): SuperloginData<D>? {
|
||||||
mustBeLoggedOut()
|
mustBeLoggedOut()
|
||||||
val r = invoke(api.slLoginByToken,token)
|
val r = invoke(serverApi.slLoginByToken,token)
|
||||||
when(r) {
|
return when(r) {
|
||||||
AuthenticationResult.LoginIdUnavailable -> TODO()
|
AuthenticationResult.LoginIdUnavailable -> TODO()
|
||||||
AuthenticationResult.LoginUnavailable -> TODO()
|
AuthenticationResult.LoginUnavailable -> null
|
||||||
AuthenticationResult.RestoreIdUnavailable -> TODO()
|
AuthenticationResult.RestoreIdUnavailable -> TODO()
|
||||||
is AuthenticationResult.Success -> TODO()
|
is AuthenticationResult.Success -> SuperloginData(
|
||||||
|
r.loginToken,
|
||||||
|
extractData(r.applicationData)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,5 +23,20 @@ interface SLServerTraits {
|
|||||||
*/
|
*/
|
||||||
suspend fun register(registrationArgs: RegistrationArgs): AuthenticationResult
|
suspend fun register(registrationArgs: RegistrationArgs): AuthenticationResult
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logging out procedure does not need any extra logic unless reuired by application
|
||||||
|
* server software. Default implementation does nothing.
|
||||||
|
*/
|
||||||
suspend fun logout() {}
|
suspend fun logout() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to log in using an authentication token, which normally is returned in
|
||||||
|
* [AuthenticationResult.Success.loginToken]. If the server implementation
|
||||||
|
* does not support login token, don't implement it, use the default implementation.
|
||||||
|
*
|
||||||
|
* Otherwise, implement login by token and return either [AuthenticationResult.Success]
|
||||||
|
* or [AuthenticationResult.LoginUnavailable]. So not return anything else.
|
||||||
|
*/
|
||||||
|
suspend fun loginByToken(token: ByteArray): AuthenticationResult
|
||||||
|
= AuthenticationResult.LoginUnavailable
|
||||||
}
|
}
|
@ -25,4 +25,7 @@ inline fun <reified D, T : SLServerSession<D>, H : CommandHost<T>> AdapterBuilde
|
|||||||
loginName = null
|
loginName = null
|
||||||
traits.logout()
|
traits.logout()
|
||||||
}
|
}
|
||||||
|
on(a2.slLoginByToken) { token ->
|
||||||
|
traits.loginByToken(token)
|
||||||
|
}
|
||||||
}
|
}
|
@ -4,16 +4,15 @@ import io.ktor.server.engine.*
|
|||||||
import io.ktor.server.netty.*
|
import io.ktor.server.netty.*
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import net.sergeych.parsec3.CommandHost
|
||||||
import net.sergeych.parsec3.Parsec3WSClient
|
import net.sergeych.parsec3.Parsec3WSClient
|
||||||
import net.sergeych.parsec3.WithAdapter
|
import net.sergeych.parsec3.WithAdapter
|
||||||
import net.sergeych.parsec3.parsec3TransportServer
|
import net.sergeych.parsec3.parsec3TransportServer
|
||||||
import net.sergeych.superlogin.AuthenticationResult
|
import net.sergeych.superlogin.AuthenticationResult
|
||||||
import net.sergeych.superlogin.RegistrationArgs
|
import net.sergeych.superlogin.RegistrationArgs
|
||||||
import net.sergeych.superlogin.SuperloginServerApi
|
|
||||||
import net.sergeych.superlogin.client.LoginState
|
import net.sergeych.superlogin.client.LoginState
|
||||||
import net.sergeych.superlogin.client.Registration
|
import net.sergeych.superlogin.client.Registration
|
||||||
import net.sergeych.superlogin.client.SuperloginClient
|
import net.sergeych.superlogin.client.SuperloginClient
|
||||||
import net.sergeych.superlogin.server.SLServerApiBase
|
|
||||||
import net.sergeych.superlogin.server.SLServerSession
|
import net.sergeych.superlogin.server.SLServerSession
|
||||||
import net.sergeych.superlogin.server.SLServerTraits
|
import net.sergeych.superlogin.server.SLServerTraits
|
||||||
import net.sergeych.superlogin.server.superloginServer
|
import net.sergeych.superlogin.server.superloginServer
|
||||||
@ -22,11 +21,12 @@ import kotlin.random.Random
|
|||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertIs
|
import kotlin.test.assertIs
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
|
||||||
data class TestSession(var buzz: String = "BuZZ") : SLServerSession<TestData>()
|
data class TestSession(var buzz: String = "BuZZ") : SLServerSession<TestData>()
|
||||||
|
|
||||||
|
|
||||||
object TestApiServer : SLServerApiBase<TestData>() {
|
class TestApiServer<T : WithAdapter> : CommandHost<T>() {
|
||||||
val loginName by command<Unit, String?>()
|
val loginName by command<Unit, String?>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +56,12 @@ object TestServerTraits : SLServerTraits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun loginByToken(token: ByteArray): AuthenticationResult {
|
||||||
|
return byToken[token.toList()]?.let {
|
||||||
|
AuthenticationResult.Success(token, it.extraData)
|
||||||
|
} ?: AuthenticationResult.LoginUnavailable
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -63,6 +69,16 @@ data class TestData(
|
|||||||
val foo: String,
|
val foo: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//fun <S: SLServerSession<*>,A: CommandHost<S>> Application.superloginServer(
|
||||||
|
// traits: SLServerTraits,
|
||||||
|
// api: A,
|
||||||
|
// f: AdapterBuilder<S,A>.()->Unit) {
|
||||||
|
// parsec3TransportServer(api) {
|
||||||
|
// superloginServer(traits)
|
||||||
|
// f()
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
internal class WsServerKtTest {
|
internal class WsServerKtTest {
|
||||||
|
|
||||||
@ -71,7 +87,8 @@ internal class WsServerKtTest {
|
|||||||
fun testWsServer() {
|
fun testWsServer() {
|
||||||
|
|
||||||
embeddedServer(Netty, port = 8080) {
|
embeddedServer(Netty, port = 8080) {
|
||||||
parsec3TransportServer(TestApiServer) {
|
parsec3TransportServer(TestApiServer<SLServerSession<TestData>>()) {
|
||||||
|
// superloginServer(TestServerTraits,TestApiServer<SLServerSession<TestData>>()) {
|
||||||
newSession { TestSession() }
|
newSession { TestSession() }
|
||||||
superloginServer(TestServerTraits)
|
superloginServer(TestServerTraits)
|
||||||
on(api.loginName) {
|
on(api.loginName) {
|
||||||
@ -80,11 +97,10 @@ internal class WsServerKtTest {
|
|||||||
}
|
}
|
||||||
}.start(wait = false)
|
}.start(wait = false)
|
||||||
|
|
||||||
val client = Parsec3WSClient("ws://localhost:8080/api/p3", SuperloginServerApi<WithAdapter>()) {
|
val client = Parsec3WSClient("ws://localhost:8080/api/p3")
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
|
val api = TestApiServer<WithAdapter>()
|
||||||
val slc = SuperloginClient<TestData, WithAdapter>(client)
|
val slc = SuperloginClient<TestData, WithAdapter>(client)
|
||||||
assertEquals(LoginState.LoggedOut, slc.state.value)
|
assertEquals(LoginState.LoggedOut, slc.state.value)
|
||||||
var rt = slc.register("foo", "passwd", TestData("bar!"))
|
var rt = slc.register("foo", "passwd", TestData("bar!"))
|
||||||
@ -94,7 +110,7 @@ internal class WsServerKtTest {
|
|||||||
println(rt.secret)
|
println(rt.secret)
|
||||||
assertEquals("bar!", rt.data<TestData>()?.foo)
|
assertEquals("bar!", rt.data<TestData>()?.foo)
|
||||||
|
|
||||||
assertEquals("foo", slc.call(TestApiServer.loginName))
|
assertEquals("foo", slc.call(api.loginName))
|
||||||
|
|
||||||
val s = slc.state.value
|
val s = slc.state.value
|
||||||
assertIs<LoginState.LoggedIn<TestData>>(s)
|
assertIs<LoginState.LoggedIn<TestData>>(s)
|
||||||
@ -105,12 +121,15 @@ internal class WsServerKtTest {
|
|||||||
}
|
}
|
||||||
slc.logout()
|
slc.logout()
|
||||||
assertIs<LoginState.LoggedOut>(slc.state.value)
|
assertIs<LoginState.LoggedOut>(slc.state.value)
|
||||||
assertEquals(null, slc.call(TestApiServer.loginName))
|
assertEquals(null, slc.call(api.loginName))
|
||||||
|
|
||||||
rt = slc.register("foo", "passwd", TestData("nobar"))
|
rt = slc.register("foo", "passwd", TestData("nobar"))
|
||||||
assertIs<Registration.Result.InvalidLogin>(rt)
|
assertIs<Registration.Result.InvalidLogin>(rt)
|
||||||
|
|
||||||
// slc.loginByToken()
|
var ar = slc.loginByToken(token)
|
||||||
|
assertNotNull(ar)
|
||||||
|
assertEquals("bar!", ar.data?.foo)
|
||||||
|
assertEquals("foo", slc.call(api.loginName))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user