diff --git a/app/build.gradle.kts b/app/build.gradle.kts index fd4c5c7756695a0f64ba3216e72b029430d53abc..1dc2ea01cfd9ec00c44d64bee6b54804ea7dd6f3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -3,6 +3,7 @@ import org.gradle.api.Project import org.gradle.kotlin.dsl.* import org.jetbrains.kotlin.gradle.plugin.KaptAnnotationProcessorOptions import org.jetbrains.kotlin.gradle.plugin.KaptExtension +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import java.io.ByteArrayOutputStream import java.util.* @@ -75,8 +76,11 @@ dependencies { implementation(appCompat("cardview-v7")) implementation(appCompat("recyclerview-v7")) + implementation("io.reactivex.rxjava2:rxjava:2.1.3") + implementation(appArch("lifecycle", "runtime", version = "1.0.0")) implementation(appArch("lifecycle", "extensions")) + implementation(appArch("lifecycle", "reactivestreams")) kapt(appArch("lifecycle", "compiler")) implementation(appArch("persistence.room", "runtime")) @@ -104,6 +108,15 @@ dependencies { androidTestImplementation("com.android.support.test:rules:0.5") } +tasks.withType(KotlinCompile::class.java) { + kotlinOptions { + freeCompilerArgs = listOf( + "-Xno-param-assertions", + "-Xno-call-assertions" + ) + } +} + fun cmd(vararg command: String) = try { val stdOut = ByteArrayOutputStream() exec { diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt index 2389a25e90950139447bda99b0bcf0bdb3ff4584..cac39a1da01154a0f5955f07d05dac5ea2cdddbd 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt @@ -1,15 +1,16 @@ package de.kuschku.quasseldroid_ng.service import android.arch.lifecycle.LifecycleService -import android.arch.lifecycle.MutableLiveData -import android.arch.lifecycle.Transformations import android.content.Intent import android.os.Binder +import de.kuschku.libquassel.protocol.* +import de.kuschku.libquassel.session.Backend +import de.kuschku.libquassel.session.CoreConnection +import de.kuschku.libquassel.session.Session +import de.kuschku.libquassel.session.SocketAddress import de.kuschku.quasseldroid_ng.BuildConfig import de.kuschku.quasseldroid_ng.R import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase -import de.kuschku.libquassel.protocol.* -import de.kuschku.libquassel.session.* import de.kuschku.quasseldroid_ng.util.AndroidHandlerService import org.threeten.bp.Instant import java.security.cert.X509Certificate @@ -24,21 +25,14 @@ class QuasselService : LifecycleService() { override fun connect(address: SocketAddress, user: String, pass: String) { disconnect() val handlerService = AndroidHandlerService() - session.coreConnection = CoreConnection(session, address, handlerService) - session.coreConnection?.start() + session.connection.onNext(CoreConnection(session, address, handlerService)) + session.connection.value.start() session.userData = user to pass - connection.postValue(session.coreConnection) } override fun disconnect() { session.cleanUp() - connection.postValue(null) - ABSENT.postValue(ConnectionState.DISCONNECTED) } - - private val connection = MutableLiveData<CoreConnection>() - - val ABSENT = MutableLiveData<ConnectionState>() } private lateinit var database: QuasselDatabase diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MainActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MainActivity.kt index 6fc50d69f9e266b3b51ce40c81848a3f1215eafb..dbaa19a173509158968f3fd22fbbebe94b2cea84 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MainActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MainActivity.kt @@ -1,8 +1,10 @@ package de.kuschku.quasseldroid_ng.ui import android.arch.lifecycle.LiveData +import android.arch.lifecycle.MutableLiveData import android.os.Bundle import android.support.design.widget.Snackbar +import android.util.Log import android.view.Menu import android.view.MenuItem import android.widget.Button @@ -11,16 +13,16 @@ import android.widget.TextView import butterknife.BindView import butterknife.ButterKnife import de.kuschku.libquassel.session.Backend +import de.kuschku.libquassel.session.ConnectionState import de.kuschku.libquassel.session.Session import de.kuschku.libquassel.session.SocketAddress +import de.kuschku.libquassel.util.LoggingHandler import de.kuschku.quasseldroid_ng.R import de.kuschku.quasseldroid_ng.util.helper.stickyMapNotNull -import org.threeten.bp.Instant +import io.reactivex.disposables.Disposable import org.threeten.bp.ZoneOffset +import org.threeten.bp.ZonedDateTime import org.threeten.bp.format.DateTimeFormatter -import java.util.logging.Handler -import java.util.logging.LogManager -import java.util.logging.LogRecord class MainActivity : ServiceBoundActivity() { @BindView(R.id.host) @@ -47,37 +49,33 @@ class MainActivity : ServiceBoundActivity() { @BindView(R.id.errorList) lateinit var errorList: TextView - /* - private val status: LiveData<ConnectionState> - = stickySwitchMapNotNull(backend, Backend::status, - ConnectionState.DISCONNECTED) - */ private val session: LiveData<Session?> = stickyMapNotNull(backend, Backend::session, null) + private var subscription: Disposable? = null + private val state = MutableLiveData<ConnectionState>() private var snackbar: Snackbar? = null private val dateTimeFormatter: DateTimeFormatter = DateTimeFormatter.ISO_TIME - private val handler = object : Handler() { - override fun publish(p0: LogRecord?) { - if (p0 != null) { - runOnUiThread { - errorList.append( - dateTimeFormatter.format(Instant.ofEpochMilli(p0.millis).atZone(ZoneOffset.UTC))) - errorList.append(" ") - errorList.append(p0.loggerName) - errorList.append(": ") - errorList.append(p0.message) + private val handler = object : LoggingHandler() { + override fun log(logLevel: LogLevel, tag: String, message: String?, throwable: Throwable?) { + if (logLevel.ordinal < LogLevel.INFO.ordinal) + return + val time = dateTimeFormatter.format(ZonedDateTime.now(ZoneOffset.UTC)) + runOnUiThread { + errorList.append("$time $tag: ") + if (message != null) { + errorList.append(message) + } + if (throwable != null) { errorList.append("\n") + errorList.append(Log.getStackTraceString(throwable)) } + errorList.append("\n") } } - override fun flush() { - } - - override fun close() { - } + override fun isLoggable(logLevel: LogLevel, tag: String) = true } override fun onCreate(savedInstanceState: Bundle?) { @@ -126,11 +124,11 @@ class MainActivity : ServiceBoundActivity() { override fun onStart() { super.onStart() - LogManager.getLogManager().getLogger("").addHandler(handler) + LoggingHandler.loggingHandlers.add(handler) } override fun onStop() { - LogManager.getLogManager().getLogger("").removeHandler(handler) + LoggingHandler.loggingHandlers.remove(handler) super.onStop() } } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidHandlerService.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidHandlerService.kt index 096cd41ae1cbe565b505cb874c15880e270a0e4a..8c575bc4691f509499178722f03292639e455944 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidHandlerService.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidHandlerService.kt @@ -18,9 +18,9 @@ class AndroidHandlerService : HandlerService { backendHandler.post(f) } - private val parseThread = HandlerThread("parse", Process.THREAD_PRIORITY_BACKGROUND) + private val parseThread = HandlerThread("parse", Process.THREAD_PRIORITY_DISPLAY) private val writeThread = HandlerThread("write", Process.THREAD_PRIORITY_BACKGROUND) - private val backendThread = HandlerThread("backend", Process.THREAD_PRIORITY_BACKGROUND) + private val backendThread = HandlerThread("backend", Process.THREAD_PRIORITY_DISPLAY) private val parseHandler: Handler private val writeHandler: Handler diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidLoggingHandler.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidLoggingHandler.kt index ecc340439cf0d79a49daadb5ae5ff890215a5f52..0e69d331d4bf1a98a1e7c8d0fc936ba5625107c3 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidLoggingHandler.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidLoggingHandler.kt @@ -1,59 +1,32 @@ package de.kuschku.quasseldroid_ng.util import android.util.Log -import java.util.logging.Handler -import java.util.logging.Level -import java.util.logging.LogManager -import java.util.logging.LogRecord - -/** - * Make JUL work on Android. - */ -class AndroidLoggingHandler : Handler() { - override fun close() {} - override fun flush() {} - override fun publish(record: LogRecord) { - if (!super.isLoggable(record)) - return - - val name = record.loggerName - val maxLength = 30 - val tag = if (name.length > maxLength) name.substring(name.length - maxLength) else name - - try { - val level = getAndroidLevel(record.level) - Log.println(level, tag, record.message) - if (record.thrown != null) { - Log.println(level, tag, Log.getStackTraceString(record.thrown)) - } - } catch (e: RuntimeException) { - Log.e("AndroidLoggingHandler", "Error logging message.", e) - } +import de.kuschku.libquassel.util.LoggingHandler +object AndroidLoggingHandler : LoggingHandler() { + override fun isLoggable(logLevel: LogLevel, tag: String): Boolean { + return Log.isLoggable(tag, priority(logLevel)) } - companion object { - fun reset(rootHandler: Handler) { - val rootLogger = LogManager.getLogManager().getLogger("") - val handlers = rootLogger.handlers - for (handler in handlers) { - rootLogger.removeHandler(handler) - } - rootLogger.addHandler(rootHandler) - } + override fun log(logLevel: LogLevel, tag: String, message: String?, throwable: Throwable?) { + val priority = priority(logLevel) + if (message != null) + Log.println(priority, tag, message) + if (throwable != null) + Log.println(priority, tag, Log.getStackTraceString(throwable)) + } - fun init() { - reset(AndroidLoggingHandler()) - } + private fun priority(logLevel: LogLevel): Int = when (logLevel) { + LogLevel.VERBOSE -> Log.VERBOSE + LogLevel.DEBUG -> Log.DEBUG + LogLevel.INFO -> Log.INFO + LogLevel.WARN -> Log.WARN + LogLevel.ERROR -> Log.ERROR + LogLevel.ASSERT -> Log.ASSERT + } - private fun getAndroidLevel(level: Level): Int { - val value = level.intValue() - return when { - value >= 1000 -> Log.ERROR - value >= 900 -> Log.WARN - value >= 800 -> Log.INFO - else -> Log.DEBUG - } - } + fun init() { + LoggingHandler.loggingHandlers.clear() + LoggingHandler.loggingHandlers.add(this) } } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/TransformationsHelper.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/TransformationsHelper.kt index 9c7f06099b7cd9d11bdff08a25334ea7e87e9fa4..c9b9500952590322365ae45e45b05c188fed8766 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/TransformationsHelper.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/TransformationsHelper.kt @@ -5,6 +5,10 @@ import android.arch.lifecycle.LiveData import android.arch.lifecycle.MediatorLiveData import android.arch.lifecycle.Observer import android.support.annotation.MainThread +import io.reactivex.Observable +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import io.reactivex.subjects.BehaviorSubject @MainThread fun <X, Y> stickySwitchMapNotNull( @@ -45,6 +49,93 @@ fun <X, Y> stickySwitchMapNotNull( return result } +@MainThread +inline fun <X, Y> rxStickySwitchMapNotNull( + trigger: LiveData<X?>, + crossinline func: (X) -> BehaviorSubject<Y>?, + defaultValue: Y +): LiveData<Y> { + return stickySwitchMapNotNull(trigger, { + val data = func(it) + if (data != null) + BehaviorSubjectLiveData(data) + else + null + }, defaultValue) +} + +class BehaviorSubjectLiveData<T>(val observable: BehaviorSubject<T>) : LiveData<T>() { + var subscription: Disposable? = null + + override fun getValue(): T? { + return observable.value + } + + override fun setValue(value: T) { + observable.onNext(value) + } + + override fun postValue(value: T) { + observable.onNext(value) + } + + override fun observe(owner: LifecycleOwner?, observer: Observer<T>?) { + super.observe(owner, observer) + if (subscription == null && hasActiveObservers()) { + subscription = observable.subscribeOn(Schedulers.io()).subscribe(this::postValue) + } + } + + override fun observeForever(observer: Observer<T>?) { + super.observeForever(observer) + if (subscription == null && hasActiveObservers()) { + subscription = observable.subscribeOn(Schedulers.io()).subscribe(this::postValue) + } + } + + override fun removeObserver(observer: Observer<T>?) { + super.removeObserver(observer) + if (subscription != null && !hasActiveObservers()) { + subscription?.dispose() + } + } + + override fun removeObservers(owner: LifecycleOwner?) { + super.removeObservers(owner) + if (subscription != null && !hasActiveObservers()) { + subscription?.dispose() + } + } +} + +@MainThread +fun <X, Y> rxSwitchMap( + trigger: LiveData<X?>, + func: (X) -> Observable<Y>?, + defaultValue: Y +): LiveData<Y> { + val result = object : MediatorLiveData<Y>() { + override fun observe(owner: LifecycleOwner?, observer: Observer<Y>?) { + super.observe(owner, observer) + observer?.onChanged(value ?: defaultValue) + } + + override fun observeForever(observer: Observer<Y>?) { + super.observeForever(observer) + observer?.onChanged(value ?: defaultValue) + } + } + result.addSource(trigger, object : Observer<X?> { + internal var mSource: Observable<Y>? = null + + override fun onChanged(x: X?) { + val newLiveData = if (x != null) func(x) else null + + } + }) + return result +} + @MainThread fun <X, Y> stickyMapNotNull( trigger: LiveData<X?>, diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index b8e62b48d421f1634e440870d3b66d5589ddd1bf..064528dddd294cd3d50a27b848ac033f6811f074 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -6,9 +6,11 @@ <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginBottom="8dp" + android:layout_marginTop="8dp" android:orientation="vertical" - android:paddingLeft="16dp" - android:paddingRight="16dp"> + android:paddingLeft="24dp" + android:paddingRight="24dp"> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" @@ -19,8 +21,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Host" - android:singleLine="true" - android:maxLines="1" /> + android:maxLines="1" + android:singleLine="true" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout @@ -33,9 +35,9 @@ android:layout_height="wrap_content" android:hint="Port" android:inputType="number" - android:text="4242" + android:maxLines="1" android:singleLine="true" - android:maxLines="1" /> + android:text="4242" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout @@ -47,8 +49,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Username" - android:singleLine="true" - android:maxLines="1" /> + android:maxLines="1" + android:singleLine="true" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout @@ -61,8 +63,8 @@ android:layout_height="wrap_content" android:hint="Password" android:inputType="textPassword" - android:singleLine="true" - android:maxLines="1" /> + android:maxLines="1" + android:singleLine="true" /> </android.support.design.widget.TextInputLayout> <LinearLayout diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 26af4e8383670249cdcf9b585a6c61c101ca4b91..b6ac7eae9069de9e8065e9ca8af765848544337f 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -3,6 +3,7 @@ import org.gradle.api.Project import org.gradle.api.artifacts.ExternalModuleDependency import org.gradle.kotlin.dsl.* import org.jetbrains.kotlin.gradle.plugin.KaptExtension +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile apply { plugin("kotlin") @@ -23,6 +24,15 @@ dependencies { testImplementation("junit:junit:4.12") } +tasks.withType(KotlinCompile::class.java) { + kotlinOptions { + freeCompilerArgs = listOf( + "-Xno-param-assertions", + "-Xno-call-assertions" + ) + } +} + /** * Builds the dependency notation for the named AppCompat [module] at the given [version]. * diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/HandshakeMessage.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/HandshakeMessage.kt deleted file mode 100644 index aafc0b12e82ec44b085d42f88a0eb7bacb7d3b51..0000000000000000000000000000000000000000 --- a/lib/src/main/java/de/kuschku/libquassel/protocol/HandshakeMessage.kt +++ /dev/null @@ -1,255 +0,0 @@ -package de.kuschku.libquassel.protocol - -import de.kuschku.libquassel.util.Flags - - -sealed class HandshakeMessage { - class ClientInit(val clientVersion: String?, val buildDate: String?, - val clientFeatures: Quassel_Features?) : HandshakeMessage() { - override fun toString(): String { - return "ClientInit(clientVersion=$clientVersion, buildDate=$buildDate, clientFeatures=$clientFeatures)" - } - } - - class ClientInitReject(val errorString: String?) : HandshakeMessage() { - override fun toString(): String { - return "ClientInitReject(errorString=$errorString)" - } - } - - class ClientInitAck(val coreFeatures: Quassel_Features?, val coreConfigured: Boolean?, - val backendInfo: QVariantList?, - val authenticatorInfo: QVariantList?) : HandshakeMessage() { - override fun toString(): String { - return "ClientInitAck(coreFeatures=$coreFeatures, coreConfigured=$coreConfigured, backendInfo=$backendInfo, authenticatorInfo=$authenticatorInfo)" - } - } - - class CoreSetupData(val adminUser: String?, val adminPassword: String?, val backend: String?, - val setupData: QVariantMap?, val authenticator: String?, - val authSetupData: QVariantMap?) : - HandshakeMessage() { - override fun toString(): String { - return "CoreSetupData(adminUser=$adminUser, adminPassword=$adminPassword, backend=$backend, setupData=$setupData, authenticator=$authenticator, authSetupData=$authSetupData)" - } - } - - class CoreSetupReject(val errorString: String?) : HandshakeMessage() { - override fun toString(): String { - return "CoreSetupReject(errorString=$errorString)" - } - } - - class CoreSetupAck : HandshakeMessage() { - override fun toString(): String { - return "CoreSetupAck" - } - } - - class ClientLogin(val user: String?, val password: String?) : HandshakeMessage() { - override fun toString(): String { - return "ClientLogin" - } - } - - class ClientLoginReject(val errorString: String?) : HandshakeMessage() { - override fun toString(): String { - return "ClientLoginReject(errorString=$errorString)" - } - } - - class ClientLoginAck : HandshakeMessage() { - override fun toString(): String { - return "ClientLoginAck" - } - } - - class SessionInit(val identities: QVariantList?, val bufferInfos: QVariantList?, - val networkIds: QVariantList?) : - HandshakeMessage() { - override fun toString(): String { - return "SessionInit(identities=$identities, bufferInfos=$bufferInfos, networkIds=$networkIds)" - } - } - - companion object : HandshakeMessageSerializer<HandshakeMessage> { - override fun serialize(data: HandshakeMessage) = when (data) { - is ClientInit -> ClientInitSerializer.serialize(data) - is ClientInitReject -> ClientInitRejectSerializer.serialize(data) - is ClientInitAck -> ClientInitAckSerializer.serialize(data) - is CoreSetupData -> CoreSetupDataSerializer.serialize(data) - is CoreSetupReject -> CoreSetupRejectSerializer.serialize(data) - is CoreSetupAck -> CoreSetupAckSerializer.serialize(data) - is ClientLogin -> ClientLoginSerializer.serialize(data) - is ClientLoginReject -> ClientLoginRejectSerializer.serialize(data) - is ClientLoginAck -> ClientLoginAckSerializer.serialize(data) - is SessionInit -> SessionInitSerializer.serialize(data) - } - - override fun deserialize(data: QVariantMap): HandshakeMessage { - val msgType = data["MsgType"].value<String?>() - return when (msgType) { - "ClientInit" -> ClientInitSerializer.deserialize(data) - "ClientInitReject" -> ClientInitRejectSerializer.deserialize(data) - "ClientInitAck" -> ClientInitAckSerializer.deserialize(data) - "CoreSetupData" -> CoreSetupDataSerializer.deserialize(data) - "CoreSetupReject" -> CoreSetupRejectSerializer.deserialize(data) - "CoreSetupAck" -> CoreSetupAckSerializer.deserialize(data) - "ClientLogin" -> ClientLoginSerializer.deserialize(data) - "ClientLoginReject" -> ClientLoginRejectSerializer.deserialize(data) - "ClientLoginAck" -> ClientLoginAckSerializer.deserialize(data) - "SessionInit" -> SessionInitSerializer.deserialize(data) - else -> throw IllegalArgumentException( - "Invalid MsgType: $msgType" - ) - } - } - - } -} - -object ClientInitSerializer : HandshakeMessageSerializer<HandshakeMessage.ClientInit> { - override fun serialize(data: HandshakeMessage.ClientInit) = mapOf( - "MsgType" to QVariant_(data::class.java.simpleName, Type.QString), - "ClientVersion" to QVariant_(data.clientVersion, Type.QString), - "ClientDate" to QVariant_(data.buildDate, Type.QString), - "ClientFeatures" to QVariant_(data.clientFeatures?.toInt(), Type.UInt) - ) - - override fun deserialize(data: QVariantMap) = HandshakeMessage.ClientInit( - clientVersion = data["ClientVersion"].value(), - buildDate = data["ClientDate"].value(), - clientFeatures = Flags.of(data["ClientFeatures"].value(0)) - ) -} - -object ClientInitRejectSerializer : HandshakeMessageSerializer<HandshakeMessage.ClientInitReject> { - override fun serialize(data: HandshakeMessage.ClientInitReject) = mapOf( - "MsgType" to QVariant_(data::class.java.simpleName, Type.QString), - "Error" to QVariant_(data.errorString, Type.QString) - ) - - override fun deserialize(data: QVariantMap) = HandshakeMessage.ClientInitReject( - errorString = data["Error"].value() - ) -} - -object ClientInitAckSerializer : HandshakeMessageSerializer<HandshakeMessage.ClientInitAck> { - override fun serialize(data: HandshakeMessage.ClientInitAck) = mapOf( - "MsgType" to QVariant_(data::class.java.simpleName, Type.QString), - "CoreFeatures" to QVariant_(data.coreFeatures?.toInt(), Type.UInt), - "StorageBackends" to QVariant_(data.backendInfo, Type.QVariantList), - "Authenticator" to QVariant_(data.authenticatorInfo, Type.QVariantList), - "Configured" to QVariant_(data.coreConfigured, Type.Bool) - ) - - override fun deserialize(data: QVariantMap) = HandshakeMessage.ClientInitAck( - coreFeatures = Flags.of(data["CoreFeatures"].value(0)), - backendInfo = data["StorageBackends"].value(), - authenticatorInfo = data["Authenticators"].value(), - coreConfigured = data["Configured"].value() - ) -} - -object CoreSetupDataSerializer : HandshakeMessageSerializer<HandshakeMessage.CoreSetupData> { - override fun serialize(data: HandshakeMessage.CoreSetupData) = mapOf( - "MsgType" to QVariant_(data::class.java.simpleName, Type.QString), - "SetupData" to QVariant_(mapOf( - "AdminUser" to QVariant_(data.adminUser, Type.QString), - "AdminPasswd" to QVariant_(data.adminPassword, Type.QString), - "Backend" to QVariant_(data.backend, Type.QString), - "ConnectionProperties" to QVariant_(data.setupData, Type.QVariantMap), - "Authenticator" to QVariant_(data.authenticator, Type.QString), - "AuthProperties" to QVariant_(data.authSetupData, Type.QVariantMap) - ), Type.QVariantMap) - ) - - override fun deserialize(data: QVariantMap): HandshakeMessage.CoreSetupData { - val setupData = data["SetupData"].value<QVariantMap?>() - return HandshakeMessage.CoreSetupData( - adminUser = setupData?.get("AdminUser").value(), - adminPassword = setupData?.get("AdminPasswd").value(), - backend = setupData?.get("Backend").value(), - setupData = setupData?.get("ConnectionProperties").value(), - authenticator = setupData?.get("Authenticator").value(), - authSetupData = setupData?.get("AuthProperties").value() - ) - } -} - -object CoreSetupRejectSerializer : HandshakeMessageSerializer<HandshakeMessage.CoreSetupReject> { - override fun serialize(data: HandshakeMessage.CoreSetupReject) = mapOf( - "MsgType" to QVariant_(data::class.java.simpleName, Type.QString), - "Error" to QVariant_(data.errorString, Type.QString) - ) - - override fun deserialize(data: QVariantMap) = HandshakeMessage.CoreSetupReject( - errorString = data["Error"].value() - ) -} - -object CoreSetupAckSerializer : HandshakeMessageSerializer<HandshakeMessage.CoreSetupAck> { - override fun serialize(data: HandshakeMessage.CoreSetupAck) = mapOf( - "MsgType" to QVariant_(data::class.java.simpleName, Type.QString) - ) - - override fun deserialize(data: QVariantMap) = HandshakeMessage.CoreSetupAck() -} - -object ClientLoginSerializer : HandshakeMessageSerializer<HandshakeMessage.ClientLogin> { - override fun serialize(data: HandshakeMessage.ClientLogin) = mapOf( - "MsgType" to QVariant_(data::class.java.simpleName, Type.QString), - "User" to QVariant_(data.user, Type.QString), - "Password" to QVariant_(data.password, Type.QString) - ) - - override fun deserialize(data: QVariantMap) = HandshakeMessage.ClientLogin( - user = data["User"].value(), - password = data["Password"].value() - ) -} - -object ClientLoginRejectSerializer : - HandshakeMessageSerializer<HandshakeMessage.ClientLoginReject> { - override fun serialize(data: HandshakeMessage.ClientLoginReject) = mapOf( - "MsgType" to QVariant_(data::class.java.simpleName, Type.QString), - "Error" to QVariant_(data.errorString, Type.QString) - ) - - override fun deserialize(data: QVariantMap) = HandshakeMessage.ClientLoginReject( - errorString = data["Error"].value() - ) -} - -object ClientLoginAckSerializer : HandshakeMessageSerializer<HandshakeMessage.ClientLoginAck> { - override fun serialize(data: HandshakeMessage.ClientLoginAck) = mapOf( - "MsgType" to QVariant_(data::class.java.simpleName, Type.QString) - ) - - override fun deserialize(data: QVariantMap) = HandshakeMessage.ClientLoginAck() -} - -object SessionInitSerializer : HandshakeMessageSerializer<HandshakeMessage.SessionInit> { - override fun serialize(data: HandshakeMessage.SessionInit) = mapOf( - "MsgType" to QVariant_(data::class.java.simpleName, Type.QString), - "SessionState" to QVariant_(mapOf( - "BufferInfos" to QVariant_(data.bufferInfos, Type.QVariantList), - "NetworkIds" to QVariant_(data.networkIds, Type.QVariantList), - "Identities" to QVariant_(data.identities, Type.QVariantList) - ), Type.QVariantMap) - ) - - override fun deserialize(data: QVariantMap): HandshakeMessage.SessionInit { - val setupData = data["SessionState"].value<QVariantMap?>() - return HandshakeMessage.SessionInit( - bufferInfos = setupData?.get("BufferInfos").value(), - networkIds = setupData?.get("NetworkIds").value(), - identities = setupData?.get("Identities").value() - ) - } -} - -interface HandshakeMessageSerializer<T : HandshakeMessage> { - fun serialize(data: T): QVariantMap - fun deserialize(data: QVariantMap): T -} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt index 5ef4a08bf62a82805759eaa89007613c239ad0ff..67c4138a210adbe77e15dd419a540bf496264b3b 100644 --- a/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt @@ -56,4 +56,10 @@ class Message( override fun of(vararg flags: MessageFlag) = Flags.of(*flags) } } + + override fun toString(): String { + return "Message(messageId=$messageId, time=$time, type=$type, flag=$flag, bufferInfo=$bufferInfo, sender='$sender', senderPrefixes='$senderPrefixes', content='$content')" + } + + } diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/SignalProxyMessage.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/SignalProxyMessage.kt deleted file mode 100644 index 33a2bd516f47b20be122e91fc2eb53dacb37f86a..0000000000000000000000000000000000000000 --- a/lib/src/main/java/de/kuschku/libquassel/protocol/SignalProxyMessage.kt +++ /dev/null @@ -1,172 +0,0 @@ -package de.kuschku.libquassel.protocol - -import de.kuschku.libquassel.protocol.primitive.serializer.StringSerializer.UTF8 -import de.kuschku.libquassel.protocol.primitive.serializer.deserializeString -import de.kuschku.libquassel.protocol.primitive.serializer.serializeString -import org.threeten.bp.Instant -import java.nio.ByteBuffer - -enum class RequestType(val value: Int) { - Invalid(0), - Sync(1), - RpcCall(2), - InitRequest(3), - InitData(4), - HeartBeat(5), - HeartBeatReply(6); - - companion object { - private val byId = enumValues<RequestType>().associateBy(RequestType::value) - fun of(value: Int) = byId[value] ?: Invalid - } -} - -sealed class SignalProxyMessage { - class SyncMessage(val className: String, val objectName: String, val slotName: String, - val params: QVariantList) : SignalProxyMessage() { - override fun toString(): String { - return "SyncMessage::$className:${objectName.hashCode()}/$slotName" - } - } - - class RpcCall(val slotName: String, val params: QVariantList) : SignalProxyMessage() { - override fun toString(): String { - return "RpcCall::$slotName" - } - } - - class InitRequest(val className: String, val objectName: String) : SignalProxyMessage() { - override fun toString(): String { - return "InitRequest::$className:${objectName.hashCode()}" - } - } - - class InitData(val className: String, val objectName: String, val initData: QVariantMap) : - SignalProxyMessage() { - override fun toString(): String { - return "InitData::$className:${objectName.hashCode()}" - } - } - - class HeartBeat(val timestamp: Instant) : SignalProxyMessage() { - override fun toString(): String { - return "HeartBeat::$timestamp" - } - } - - class HeartBeatReply(val timestamp: Instant) : SignalProxyMessage() { - override fun toString(): String { - return "HeartBeatReply::$timestamp" - } - } - - companion object : SignalProxyMessageSerializer<SignalProxyMessage> { - override fun serialize(data: SignalProxyMessage) = when (data) { - is SignalProxyMessage.SyncMessage -> SyncMessageSerializer.serialize(data) - is SignalProxyMessage.RpcCall -> RpcCallSerializer.serialize(data) - is SignalProxyMessage.InitRequest -> InitRequestSerializer.serialize(data) - is SignalProxyMessage.InitData -> InitDataSerializer.serialize(data) - is SignalProxyMessage.HeartBeat -> HeartBeatSerializer.serialize(data) - is SignalProxyMessage.HeartBeatReply -> HeartBeatReplySerializer.serialize(data) - } - - override fun deserialize(data: QVariantList): SignalProxyMessage { - val type = data.first().value(-1) - return when (RequestType.of(type)) { - RequestType.Sync -> SyncMessageSerializer.deserialize(data.drop(1)) - RequestType.RpcCall -> RpcCallSerializer.deserialize(data.drop(1)) - RequestType.InitRequest -> InitRequestSerializer.deserialize(data.drop(1)) - RequestType.InitData -> InitDataSerializer.deserialize(data.drop(1)) - RequestType.HeartBeat -> HeartBeatSerializer.deserialize(data.drop(1)) - RequestType.HeartBeatReply -> HeartBeatReplySerializer.deserialize(data.drop(1)) - else -> throw IllegalArgumentException("Invalid MsgType: $type") - } - } - - } -} - -object SyncMessageSerializer : SignalProxyMessageSerializer<SignalProxyMessage.SyncMessage> { - override fun serialize(data: SignalProxyMessage.SyncMessage): QVariantList = listOf( - QVariant_(RequestType.Sync.value, Type.Int), - QVariant_(data.className.serializeString(UTF8), Type.QByteArray), - QVariant_(data.objectName.serializeString(UTF8), Type.QByteArray), - QVariant_(data.slotName.serializeString(UTF8), Type.QByteArray), - *data.params.toTypedArray() - ) - - override fun deserialize(data: QVariantList) = SignalProxyMessage.SyncMessage( - data[0].value<ByteBuffer?>().deserializeString(UTF8) ?: "", - data[1].value<ByteBuffer?>().deserializeString(UTF8) ?: "", - data[2].value<ByteBuffer?>().deserializeString(UTF8) ?: "", - data.drop(3) - ) -} - -object RpcCallSerializer : SignalProxyMessageSerializer<SignalProxyMessage.RpcCall> { - override fun serialize(data: SignalProxyMessage.RpcCall) = listOf( - QVariant_(RequestType.RpcCall.value, Type.Int), - QVariant_(data.slotName.serializeString(UTF8), Type.QByteArray), - *data.params.toTypedArray() - ) - - override fun deserialize(data: QVariantList) = SignalProxyMessage.RpcCall( - data[0].value<ByteBuffer?>().deserializeString(UTF8) ?: "", - data.drop(1) - ) -} - -object InitRequestSerializer : SignalProxyMessageSerializer<SignalProxyMessage.InitRequest> { - override fun serialize(data: SignalProxyMessage.InitRequest) = listOf( - QVariant_(RequestType.InitRequest.value, Type.Int), - QVariant_(data.className.serializeString(UTF8), Type.QByteArray), - QVariant_(data.objectName.serializeString(UTF8), Type.QByteArray) - ) - - override fun deserialize(data: QVariantList) = SignalProxyMessage.InitRequest( - data[0].value<ByteBuffer?>().deserializeString(UTF8) ?: "", - data[1].value<ByteBuffer?>().deserializeString(UTF8) ?: "" - ) -} - -object InitDataSerializer : SignalProxyMessageSerializer<SignalProxyMessage.InitData> { - override fun serialize(data: SignalProxyMessage.InitData) = listOf( - QVariant_(RequestType.InitData.value, Type.Int), - QVariant_(data.className.serializeString(UTF8), Type.QByteArray), - QVariant_(data.objectName.serializeString(UTF8), Type.QByteArray), - QVariant_(data.initData, Type.QVariantMap) - ) - - override fun deserialize(data: QVariantList) = SignalProxyMessage.InitData( - data[0].value<ByteBuffer?>().deserializeString(UTF8) ?: "", - data[1].value<ByteBuffer?>().deserializeString(UTF8) ?: "", - data.drop(2).toVariantMap() - ) -} - -object HeartBeatSerializer : SignalProxyMessageSerializer<SignalProxyMessage.HeartBeat> { - override fun serialize(data: SignalProxyMessage.HeartBeat) = listOf( - QVariant_(RequestType.HeartBeat.value, Type.Int), - QVariant_(data.timestamp, Type.QDateTime) - ) - - override fun deserialize(data: QVariantList) = SignalProxyMessage.HeartBeat( - data[0].value(Instant.EPOCH) - ) -} - -object HeartBeatReplySerializer : SignalProxyMessageSerializer<SignalProxyMessage.HeartBeatReply> { - override fun serialize(data: SignalProxyMessage.HeartBeatReply) = listOf( - QVariant_(RequestType.HeartBeatReply.value, Type.Int), - QVariant_(data.timestamp, Type.QDateTime) - ) - - override fun deserialize(data: QVariantList) = SignalProxyMessage.HeartBeatReply( - data[0].value(Instant.EPOCH) - ) -} - -interface SignalProxyMessageSerializer<T : SignalProxyMessage> { - fun serialize(data: T): QVariantList - fun deserialize(data: QVariantList): T -} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitAckSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitAckSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..c8b2c597098d7dc7aa518b1860e40512cb75e40f --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitAckSerializer.kt @@ -0,0 +1,24 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantMap +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type +import de.kuschku.libquassel.protocol.value +import de.kuschku.libquassel.util.Flags + +object ClientInitAckSerializer : HandshakeMessageSerializer<HandshakeMessage.ClientInitAck> { + override fun serialize(data: HandshakeMessage.ClientInitAck) = mapOf( + "MsgType" to QVariant_("ClientInitAck", Type.QString), + "CoreFeatures" to QVariant_(data.coreFeatures?.toInt(), Type.UInt), + "StorageBackends" to QVariant_(data.backendInfo, Type.QVariantList), + "Authenticator" to QVariant_(data.authenticatorInfo, Type.QVariantList), + "Configured" to QVariant_(data.coreConfigured, Type.Bool) + ) + + override fun deserialize(data: QVariantMap) = HandshakeMessage.ClientInitAck( + coreFeatures = Flags.Companion.of(data["CoreFeatures"].value(0)), + backendInfo = data["StorageBackends"].value(), + authenticatorInfo = data["Authenticators"].value(), + coreConfigured = data["Configured"].value() + ) +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitRejectSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitRejectSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..41da7bf3fcb2091c390615e10c6f33cf92a4610e --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitRejectSerializer.kt @@ -0,0 +1,17 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantMap +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type +import de.kuschku.libquassel.protocol.value + +object ClientInitRejectSerializer : HandshakeMessageSerializer<HandshakeMessage.ClientInitReject> { + override fun serialize(data: HandshakeMessage.ClientInitReject) = mapOf( + "MsgType" to QVariant_("ClientInitReject", Type.QString), + "Error" to QVariant_(data.errorString, Type.QString) + ) + + override fun deserialize(data: QVariantMap) = HandshakeMessage.ClientInitReject( + errorString = data["Error"].value() + ) +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..9431e2815e5ade23f87107749263836b11cb4a20 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitSerializer.kt @@ -0,0 +1,22 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantMap +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type +import de.kuschku.libquassel.protocol.value +import de.kuschku.libquassel.util.Flags + +object ClientInitSerializer : HandshakeMessageSerializer<HandshakeMessage.ClientInit> { + override fun serialize(data: HandshakeMessage.ClientInit) = mapOf( + "MsgType" to QVariant_("ClientInit", Type.QString), + "ClientVersion" to QVariant_(data.clientVersion, Type.QString), + "ClientDate" to QVariant_(data.buildDate, Type.QString), + "ClientFeatures" to QVariant_(data.clientFeatures?.toInt(), Type.UInt) + ) + + override fun deserialize(data: QVariantMap) = HandshakeMessage.ClientInit( + clientVersion = data["ClientVersion"].value(), + buildDate = data["ClientDate"].value(), + clientFeatures = Flags.Companion.of(data["ClientFeatures"].value(0)) + ) +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientLoginAckSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientLoginAckSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..ee42806e4a0f46101113c13517b84b10a585ad68 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientLoginAckSerializer.kt @@ -0,0 +1,13 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantMap +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type + +object ClientLoginAckSerializer : HandshakeMessageSerializer<HandshakeMessage.ClientLoginAck> { + override fun serialize(data: HandshakeMessage.ClientLoginAck) = mapOf( + "MsgType" to QVariant_("ClientLoginAck", Type.QString) + ) + + override fun deserialize(data: QVariantMap) = HandshakeMessage.ClientLoginAck() +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientLoginRejectSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientLoginRejectSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..11dd2b7fb4025be01c88812ca506e29a5e5b9013 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientLoginRejectSerializer.kt @@ -0,0 +1,18 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantMap +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type +import de.kuschku.libquassel.protocol.value + +object ClientLoginRejectSerializer : + HandshakeMessageSerializer<HandshakeMessage.ClientLoginReject> { + override fun serialize(data: HandshakeMessage.ClientLoginReject) = mapOf( + "MsgType" to QVariant_("ClientLoginReject", Type.QString), + "Error" to QVariant_(data.errorString, Type.QString) + ) + + override fun deserialize(data: QVariantMap) = HandshakeMessage.ClientLoginReject( + errorString = data["Error"].value() + ) +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientLoginSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientLoginSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..35fdc7c70c9c09f4486106f3bfc710d07d58b061 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientLoginSerializer.kt @@ -0,0 +1,19 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantMap +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type +import de.kuschku.libquassel.protocol.value + +object ClientLoginSerializer : HandshakeMessageSerializer<HandshakeMessage.ClientLogin> { + override fun serialize(data: HandshakeMessage.ClientLogin) = mapOf( + "MsgType" to QVariant_("ClientLogin", Type.QString), + "User" to QVariant_(data.user, Type.QString), + "Password" to QVariant_(data.password, Type.QString) + ) + + override fun deserialize(data: QVariantMap) = HandshakeMessage.ClientLogin( + user = data["User"].value(), + password = data["Password"].value() + ) +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/CoreSetupAckSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/CoreSetupAckSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..8f92d8a5842e5d75a73449fb84a3a458e2722ec6 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/CoreSetupAckSerializer.kt @@ -0,0 +1,13 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantMap +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type + +object CoreSetupAckSerializer : HandshakeMessageSerializer<HandshakeMessage.CoreSetupAck> { + override fun serialize(data: HandshakeMessage.CoreSetupAck) = mapOf( + "MsgType" to QVariant_("CoreSetupAck", Type.QString) + ) + + override fun deserialize(data: QVariantMap) = HandshakeMessage.CoreSetupAck() +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/CoreSetupDataSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/CoreSetupDataSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..33fbc4cd84ba60be81d7f6424e78e258e57f62a6 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/CoreSetupDataSerializer.kt @@ -0,0 +1,32 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantMap +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type +import de.kuschku.libquassel.protocol.value + +object CoreSetupDataSerializer : HandshakeMessageSerializer<HandshakeMessage.CoreSetupData> { + override fun serialize(data: HandshakeMessage.CoreSetupData) = mapOf( + "MsgType" to QVariant_("CoreSetupData", Type.QString), + "SetupData" to QVariant_(mapOf( + "AdminUser" to QVariant_(data.adminUser, Type.QString), + "AdminPasswd" to QVariant_(data.adminPassword, Type.QString), + "Backend" to QVariant_(data.backend, Type.QString), + "ConnectionProperties" to QVariant_(data.setupData, Type.QVariantMap), + "Authenticator" to QVariant_(data.authenticator, Type.QString), + "AuthProperties" to QVariant_(data.authSetupData, Type.QVariantMap) + ), Type.QVariantMap) + ) + + override fun deserialize(data: QVariantMap): HandshakeMessage.CoreSetupData { + val setupData = data["SetupData"].value<QVariantMap?>() + return HandshakeMessage.CoreSetupData( + adminUser = setupData?.get("AdminUser").value(), + adminPassword = setupData?.get("AdminPasswd").value(), + backend = setupData?.get("Backend").value(), + setupData = setupData?.get("ConnectionProperties").value(), + authenticator = setupData?.get("Authenticator").value(), + authSetupData = setupData?.get("AuthProperties").value() + ) + } +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/CoreSetupRejectSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/CoreSetupRejectSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..e6c732a941bb1c47b656d058b6050e54a8c02f48 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/CoreSetupRejectSerializer.kt @@ -0,0 +1,17 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantMap +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type +import de.kuschku.libquassel.protocol.value + +object CoreSetupRejectSerializer : HandshakeMessageSerializer<HandshakeMessage.CoreSetupReject> { + override fun serialize(data: HandshakeMessage.CoreSetupReject) = mapOf( + "MsgType" to QVariant_("CoreSetupReject", Type.QString), + "Error" to QVariant_(data.errorString, Type.QString) + ) + + override fun deserialize(data: QVariantMap) = HandshakeMessage.CoreSetupReject( + errorString = data["Error"].value() + ) +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/HandshakeMessage.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/HandshakeMessage.kt new file mode 100644 index 0000000000000000000000000000000000000000..44b24598f80af49d5c30ff4318194da371272358 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/HandshakeMessage.kt @@ -0,0 +1,113 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantList +import de.kuschku.libquassel.protocol.QVariantMap +import de.kuschku.libquassel.protocol.Quassel_Features +import de.kuschku.libquassel.protocol.value + + +sealed class HandshakeMessage { + class ClientInit(val clientVersion: String?, val buildDate: String?, + val clientFeatures: Quassel_Features?) : HandshakeMessage() { + override fun toString(): String { + return "ClientInit(clientVersion=$clientVersion, buildDate=$buildDate, clientFeatures=$clientFeatures)" + } + } + + class ClientInitReject(val errorString: String?) : HandshakeMessage() { + override fun toString(): String { + return "ClientInitReject(errorString=$errorString)" + } + } + + class ClientInitAck(val coreFeatures: Quassel_Features?, val coreConfigured: Boolean?, + val backendInfo: QVariantList?, + val authenticatorInfo: QVariantList?) : HandshakeMessage() { + override fun toString(): String { + return "ClientInitAck(coreFeatures=$coreFeatures, coreConfigured=$coreConfigured, backendInfo=$backendInfo, authenticatorInfo=$authenticatorInfo)" + } + } + + class CoreSetupData(val adminUser: String?, val adminPassword: String?, val backend: String?, + val setupData: QVariantMap?, val authenticator: String?, + val authSetupData: QVariantMap?) : + HandshakeMessage() { + override fun toString(): String { + return "CoreSetupData" + } + } + + class CoreSetupReject(val errorString: String?) : HandshakeMessage() { + override fun toString(): String { + return "CoreSetupReject(errorString=$errorString)" + } + } + + class CoreSetupAck : HandshakeMessage() { + override fun toString(): String { + return "CoreSetupAck" + } + } + + class ClientLogin(val user: String?, val password: String?) : HandshakeMessage() { + override fun toString(): String { + return "ClientLogin" + } + } + + class ClientLoginReject(val errorString: String?) : HandshakeMessage() { + override fun toString(): String { + return "ClientLoginReject(errorString=$errorString)" + } + } + + class ClientLoginAck : HandshakeMessage() { + override fun toString(): String { + return "ClientLoginAck" + } + } + + class SessionInit(val identities: QVariantList?, val bufferInfos: QVariantList?, + val networkIds: QVariantList?) : + HandshakeMessage() { + override fun toString(): String { + return "SessionInit" + } + } + + companion object : + HandshakeMessageSerializer<HandshakeMessage> { + override fun serialize(data: HandshakeMessage) = when (data) { + is ClientInit -> ClientInitSerializer.serialize(data) + is ClientInitReject -> ClientInitRejectSerializer.serialize(data) + is ClientInitAck -> ClientInitAckSerializer.serialize(data) + is CoreSetupData -> CoreSetupDataSerializer.serialize(data) + is CoreSetupReject -> CoreSetupRejectSerializer.serialize(data) + is CoreSetupAck -> CoreSetupAckSerializer.serialize(data) + is ClientLogin -> ClientLoginSerializer.serialize(data) + is ClientLoginReject -> ClientLoginRejectSerializer.serialize(data) + is ClientLoginAck -> ClientLoginAckSerializer.serialize(data) + is SessionInit -> SessionInitSerializer.serialize(data) + } + + override fun deserialize(data: QVariantMap): HandshakeMessage { + val msgType = data["MsgType"].value<String?>() + return when (msgType) { + "ClientInit" -> ClientInitSerializer.deserialize(data) + "ClientInitReject" -> ClientInitRejectSerializer.deserialize(data) + "ClientInitAck" -> ClientInitAckSerializer.deserialize(data) + "CoreSetupData" -> CoreSetupDataSerializer.deserialize(data) + "CoreSetupReject" -> CoreSetupRejectSerializer.deserialize(data) + "CoreSetupAck" -> CoreSetupAckSerializer.deserialize(data) + "ClientLogin" -> ClientLoginSerializer.deserialize(data) + "ClientLoginReject" -> ClientLoginRejectSerializer.deserialize(data) + "ClientLoginAck" -> ClientLoginAckSerializer.deserialize(data) + "SessionInit" -> SessionInitSerializer.deserialize(data) + else -> throw IllegalArgumentException( + "Invalid MsgType: $msgType" + ) + } + } + + } +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/HandshakeMessageSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/HandshakeMessageSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..1d9be1bb4fa758152328bc15e9c66e6e499453e6 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/HandshakeMessageSerializer.kt @@ -0,0 +1,8 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantMap + +interface HandshakeMessageSerializer<T : HandshakeMessage> { + fun serialize(data: T): QVariantMap + fun deserialize(data: QVariantMap): T +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/HeartBeatReplySerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/HeartBeatReplySerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..2340c29f949957d47e2046bf66aea463564aaaaf --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/HeartBeatReplySerializer.kt @@ -0,0 +1,18 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantList +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type +import de.kuschku.libquassel.protocol.value +import org.threeten.bp.Instant + +object HeartBeatReplySerializer : SignalProxyMessageSerializer<SignalProxyMessage.HeartBeatReply> { + override fun serialize(data: SignalProxyMessage.HeartBeatReply) = listOf( + QVariant_(RequestType.HeartBeatReply.value, Type.Int), + QVariant_(data.timestamp, Type.QDateTime) + ) + + override fun deserialize(data: QVariantList) = SignalProxyMessage.HeartBeatReply( + data[0].value(Instant.EPOCH) + ) +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/HeartBeatSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/HeartBeatSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..f17071c7f15b101a1d51da47e9d14344108889fe --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/HeartBeatSerializer.kt @@ -0,0 +1,18 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantList +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type +import de.kuschku.libquassel.protocol.value +import org.threeten.bp.Instant + +object HeartBeatSerializer : SignalProxyMessageSerializer<SignalProxyMessage.HeartBeat> { + override fun serialize(data: SignalProxyMessage.HeartBeat) = listOf( + QVariant_(RequestType.HeartBeat.value, Type.Int), + QVariant_(data.timestamp, Type.QDateTime) + ) + + override fun deserialize(data: QVariantList) = SignalProxyMessage.HeartBeat( + data[0].value(Instant.EPOCH) + ) +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/InitDataSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/InitDataSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..286892e6f073092a455a6d3691ddbe2c0b052bf8 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/InitDataSerializer.kt @@ -0,0 +1,22 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.* +import de.kuschku.libquassel.protocol.primitive.serializer.StringSerializer +import de.kuschku.libquassel.protocol.primitive.serializer.deserializeString +import de.kuschku.libquassel.protocol.primitive.serializer.serializeString +import java.nio.ByteBuffer + +object InitDataSerializer : SignalProxyMessageSerializer<SignalProxyMessage.InitData> { + override fun serialize(data: SignalProxyMessage.InitData) = listOf( + QVariant_(RequestType.InitData.value, Type.Int), + QVariant_(data.className.serializeString(StringSerializer.UTF8), Type.QByteArray), + QVariant_(data.objectName.serializeString(StringSerializer.UTF8), Type.QByteArray), + QVariant_(data.initData, Type.QVariantMap) + ) + + override fun deserialize(data: QVariantList) = SignalProxyMessage.InitData( + data[0].value<ByteBuffer?>().deserializeString(StringSerializer.UTF8) ?: "", + data[1].value<ByteBuffer?>().deserializeString(StringSerializer.UTF8) ?: "", + data.drop(2).toVariantMap() + ) +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/InitRequestSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/InitRequestSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..439de03911592767650850b0d0834623573fac51 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/InitRequestSerializer.kt @@ -0,0 +1,23 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantList +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type +import de.kuschku.libquassel.protocol.primitive.serializer.StringSerializer +import de.kuschku.libquassel.protocol.primitive.serializer.deserializeString +import de.kuschku.libquassel.protocol.primitive.serializer.serializeString +import de.kuschku.libquassel.protocol.value +import java.nio.ByteBuffer + +object InitRequestSerializer : SignalProxyMessageSerializer<SignalProxyMessage.InitRequest> { + override fun serialize(data: SignalProxyMessage.InitRequest) = listOf( + QVariant_(RequestType.InitRequest.value, Type.Int), + QVariant_(data.className.serializeString(StringSerializer.UTF8), Type.QByteArray), + QVariant_(data.objectName.serializeString(StringSerializer.UTF8), Type.QByteArray) + ) + + override fun deserialize(data: QVariantList) = SignalProxyMessage.InitRequest( + data[0].value<ByteBuffer?>().deserializeString(StringSerializer.UTF8) ?: "", + data[1].value<ByteBuffer?>().deserializeString(StringSerializer.UTF8) ?: "" + ) +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/RequestType.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/RequestType.kt new file mode 100644 index 0000000000000000000000000000000000000000..3fcc834c292cbe1b36f941a5beed0bddb430fb3a --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/RequestType.kt @@ -0,0 +1,18 @@ +package de.kuschku.libquassel.protocol.message + +enum class RequestType(val value: Int) { + Invalid(0), + Sync(1), + RpcCall(2), + InitRequest(3), + InitData(4), + HeartBeat(5), + HeartBeatReply(6); + + companion object { + private val byId = enumValues<RequestType>().associateBy( + RequestType::value) + + fun of(value: Int) = byId[value] ?: Invalid + } +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/RpcCallSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/RpcCallSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..33e1bab0f8e421074aa4f49909f73ad1a1635cf2 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/RpcCallSerializer.kt @@ -0,0 +1,23 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantList +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type +import de.kuschku.libquassel.protocol.primitive.serializer.StringSerializer +import de.kuschku.libquassel.protocol.primitive.serializer.deserializeString +import de.kuschku.libquassel.protocol.primitive.serializer.serializeString +import de.kuschku.libquassel.protocol.value +import java.nio.ByteBuffer + +object RpcCallSerializer : SignalProxyMessageSerializer<SignalProxyMessage.RpcCall> { + override fun serialize(data: SignalProxyMessage.RpcCall) = listOf( + QVariant_(RequestType.RpcCall.value, Type.Int), + QVariant_(data.slotName.serializeString(StringSerializer.UTF8), Type.QByteArray), + *data.params.toTypedArray() + ) + + override fun deserialize(data: QVariantList) = SignalProxyMessage.RpcCall( + data[0].value<ByteBuffer?>().deserializeString(StringSerializer.UTF8) ?: "", + data.drop(1) + ) +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/SessionInitSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/SessionInitSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..fd2981f5db642ef13d425fcaa47f80d909ca6f05 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/SessionInitSerializer.kt @@ -0,0 +1,26 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantMap +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type +import de.kuschku.libquassel.protocol.value + +object SessionInitSerializer : HandshakeMessageSerializer<HandshakeMessage.SessionInit> { + override fun serialize(data: HandshakeMessage.SessionInit) = mapOf( + "MsgType" to QVariant_("SessionInit", Type.QString), + "SessionState" to QVariant_(mapOf( + "BufferInfos" to QVariant_(data.bufferInfos, Type.QVariantList), + "NetworkIds" to QVariant_(data.networkIds, Type.QVariantList), + "Identities" to QVariant_(data.identities, Type.QVariantList) + ), Type.QVariantMap) + ) + + override fun deserialize(data: QVariantMap): HandshakeMessage.SessionInit { + val setupData = data["SessionState"].value<QVariantMap?>() + return HandshakeMessage.SessionInit( + bufferInfos = setupData?.get("BufferInfos").value(), + networkIds = setupData?.get("NetworkIds").value(), + identities = setupData?.get("Identities").value() + ) + } +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/SignalProxyMessage.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/SignalProxyMessage.kt new file mode 100644 index 0000000000000000000000000000000000000000..f9beac7863d065f623afd554ec197b586f18a13c --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/SignalProxyMessage.kt @@ -0,0 +1,73 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantList +import de.kuschku.libquassel.protocol.QVariantMap +import de.kuschku.libquassel.protocol.value +import org.threeten.bp.Instant + +sealed class SignalProxyMessage { + class SyncMessage(val className: String, val objectName: String, val slotName: String, + val params: QVariantList) : SignalProxyMessage() { + override fun toString(): String { + return "SyncMessage::$className:$objectName:$slotName" + } + } + + class RpcCall(val slotName: String, val params: QVariantList) : SignalProxyMessage() { + override fun toString(): String { + return "RpcCall::$slotName" + } + } + + class InitRequest(val className: String, val objectName: String) : SignalProxyMessage() { + override fun toString(): String { + return "InitRequest::$className:$objectName" + } + } + + class InitData(val className: String, val objectName: String, val initData: QVariantMap) : + SignalProxyMessage() { + override fun toString(): String { + return "InitData::$className:$objectName" + } + } + + class HeartBeat(val timestamp: Instant) : SignalProxyMessage() { + override fun toString(): String { + return "HeartBeat::$timestamp" + } + } + + class HeartBeatReply(val timestamp: Instant) : SignalProxyMessage() { + override fun toString(): String { + return "HeartBeatReply::$timestamp" + } + } + + companion object : + SignalProxyMessageSerializer<SignalProxyMessage> { + override fun serialize(data: SignalProxyMessage) = when (data) { + is SyncMessage -> SyncMessageSerializer.serialize(data) + is RpcCall -> RpcCallSerializer.serialize(data) + is InitRequest -> InitRequestSerializer.serialize(data) + is InitData -> InitDataSerializer.serialize(data) + is HeartBeat -> HeartBeatSerializer.serialize(data) + is HeartBeatReply -> HeartBeatReplySerializer.serialize(data) + } + + override fun deserialize(data: QVariantList): SignalProxyMessage { + val type = data.first().value(-1) + return when (RequestType.of(type)) { + RequestType.Sync -> SyncMessageSerializer.deserialize(data.drop(1)) + RequestType.RpcCall -> RpcCallSerializer.deserialize(data.drop(1)) + RequestType.InitRequest -> InitRequestSerializer.deserialize(data.drop(1)) + RequestType.InitData -> InitDataSerializer.deserialize(data.drop(1)) + RequestType.HeartBeat -> HeartBeatSerializer.deserialize(data.drop(1)) + RequestType.HeartBeatReply -> HeartBeatReplySerializer.deserialize(data.drop(1)) + else -> throw IllegalArgumentException("Invalid MsgType: $type") + } + } + + } +} + diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/SignalProxyMessageSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/SignalProxyMessageSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..a437bc2454828c8c8dfd9d726165f66e80863b26 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/SignalProxyMessageSerializer.kt @@ -0,0 +1,8 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantList + +interface SignalProxyMessageSerializer<T : SignalProxyMessage> { + fun serialize(data: T): QVariantList + fun deserialize(data: QVariantList): T +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/SyncMessageSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/SyncMessageSerializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..3af3823515e987a745e8cd284a39ffea99abcdea --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/SyncMessageSerializer.kt @@ -0,0 +1,27 @@ +package de.kuschku.libquassel.protocol.message + +import de.kuschku.libquassel.protocol.QVariantList +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type +import de.kuschku.libquassel.protocol.primitive.serializer.StringSerializer +import de.kuschku.libquassel.protocol.primitive.serializer.deserializeString +import de.kuschku.libquassel.protocol.primitive.serializer.serializeString +import de.kuschku.libquassel.protocol.value +import java.nio.ByteBuffer + +object SyncMessageSerializer : SignalProxyMessageSerializer<SignalProxyMessage.SyncMessage> { + override fun serialize(data: SignalProxyMessage.SyncMessage): QVariantList = listOf( + QVariant_(RequestType.Sync.value, Type.Int), + QVariant_(data.className.serializeString(StringSerializer.UTF8), Type.QByteArray), + QVariant_(data.objectName.serializeString(StringSerializer.UTF8), Type.QByteArray), + QVariant_(data.slotName.serializeString(StringSerializer.UTF8), Type.QByteArray), + *data.params.toTypedArray() + ) + + override fun deserialize(data: QVariantList) = SignalProxyMessage.SyncMessage( + data[0].value<ByteBuffer?>().deserializeString(StringSerializer.UTF8) ?: "", + data[1].value<ByteBuffer?>().deserializeString(StringSerializer.UTF8) ?: "", + data[2].value<ByteBuffer?>().deserializeString(StringSerializer.UTF8) ?: "", + data.drop(3) + ) +} diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DateTimeSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DateTimeSerializer.kt index 9fc981523f494e416efa653af5c5ed450fc95020..fd14d529fb850546da2eeced64d0ddbf9b04ad84 100644 --- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DateTimeSerializer.kt +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DateTimeSerializer.kt @@ -57,16 +57,14 @@ object DateTimeSerializer : Serializer<Temporal> { return Instant.EPOCH return when (timeSpec) { TimeSpec.LocalTime -> - LocalDateTime.now() + Instant.EPOCH.atZone(ZoneOffset.systemDefault()) .with(JulianFields.JULIAN_DAY, julianDay) .with(ChronoField.MILLI_OF_DAY, milliOfDay) - .atZone(ZoneOffset.systemDefault()) .toInstant() else -> - OffsetDateTime.now() + Instant.EPOCH.atOffset(ZoneOffset.UTC) .with(JulianFields.JULIAN_DAY, julianDay) .with(ChronoField.MILLI_OF_DAY, milliOfDay) - .withOffsetSameLocal(ZoneOffset.UTC) .toInstant() } } diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringListSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringListSerializer.kt index 680638163b03afce415e6c479a042209b2619455..80589df3b4bde5b25f026a0061be7bb688ebc2a5 100644 --- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringListSerializer.kt +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringListSerializer.kt @@ -15,9 +15,11 @@ object StringListSerializer : Serializer<QStringList?> { } override fun deserialize(buffer: ByteBuffer, features: Quassel_Features): QStringList { - return (0 until IntSerializer.deserialize(buffer, features)).map { - StringSerializer.UTF16.deserialize(buffer, features) - }.toMutableList() + val size = IntSerializer.deserialize(buffer, features) + val res = ArrayList<String?>(size) + for (i in 0 until size) { + res.add(StringSerializer.UTF16.deserialize(buffer, features)) + } + return res } - } diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringSerializer.kt index 96aa39ac88907554dcf23f4b357d884012f7394d..7ea7209f6d44e0031bb21186a404338f6a4d4bc4 100644 --- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringSerializer.kt +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/StringSerializer.kt @@ -2,7 +2,6 @@ package de.kuschku.libquassel.protocol.primitive.serializer import de.kuschku.libquassel.protocol.QVariant import de.kuschku.libquassel.protocol.Quassel_Features -import de.kuschku.libquassel.util.helpers.copyTo import de.kuschku.libquassel.util.nio.ChainedByteBuffer import java.nio.ByteBuffer import java.nio.CharBuffer @@ -26,15 +25,29 @@ abstract class StringSerializer( } ) + private val charBuffer = ThreadLocal<CharBuffer>() + object UTF16 : StringSerializer(Charsets.UTF_16BE) object UTF8 : StringSerializer(Charsets.UTF_8) object C : StringSerializer(Charsets.ISO_8859_1, trailingNullByte = true) + private inline fun charBuffer(len: Int): CharBuffer { + if (charBuffer.get() == null) + charBuffer.set(CharBuffer.allocate(1024)) + val buf = if (len >= 1024) + CharBuffer.allocate(len) + else + charBuffer.get() + buf.clear() + buf.limit(len) + return buf + } + override fun serialize(buffer: ChainedByteBuffer, data: String?, features: Quassel_Features) { if (data == null) { IntSerializer.serialize(buffer, -1, features) } else { - val charBuffer = CharBuffer.allocate(data.length) + val charBuffer = charBuffer(data.length) charBuffer.put(data) charBuffer.flip() val byteBuffer = encoder.encode(charBuffer) @@ -48,7 +61,7 @@ abstract class StringSerializer( fun serialize(data: String?): ByteBuffer = if (data == null) { ByteBuffer.allocate(0) } else { - val charBuffer = CharBuffer.allocate(data.length) + val charBuffer = charBuffer(data.length) charBuffer.put(data) charBuffer.flip() encoder.encode(charBuffer) @@ -59,11 +72,15 @@ abstract class StringSerializer( return if (len == -1) { null } else { - val byteBuffer = ByteBuffer.allocate(len) - buffer.copyTo(byteBuffer) - byteBuffer.clear() - byteBuffer.limit(byteBuffer.limit() - trailingNullBytes) - decoder.decode(byteBuffer).toString() + val limit = buffer.limit() + buffer.limit(buffer.position() + len - trailingNullBytes) + val charBuffer = charBuffer(len) + decoder.reset() + decoder.decode(buffer, charBuffer, true) + buffer.limit(limit) + buffer.position(buffer.position() + trailingNullBytes) + charBuffer.flip() + charBuffer.toString() } } @@ -72,11 +89,15 @@ abstract class StringSerializer( return if (len == -1) { null } else { - val byteBuffer = ByteBuffer.allocate(len) - buffer.copyTo(byteBuffer) - byteBuffer.clear() - byteBuffer.limit(byteBuffer.limit() - trailingNullBytes) - decoder.decode(byteBuffer).toString() + val limit = buffer.limit() + buffer.limit(buffer.position() + len - trailingNullBytes) + val charBuffer = charBuffer(len) + decoder.reset() + decoder.decode(buffer, charBuffer, true) + buffer.limit(limit) + buffer.position(buffer.position() + trailingNullBytes) + charBuffer.flip() + charBuffer.toString() } } } diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/Network.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/Network.kt index 035d12abd44f75785e9eef5163e1b1fcafd8c1c1..f428b5d468803a3a099ad6f1f73220ef188b2686 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/Network.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/Network.kt @@ -733,20 +733,29 @@ class Network constructor( override fun initSetIrcUsersAndChannels(usersAndChannels: QVariantMap) { if (initialized) throw IllegalArgumentException("Received init data for network ${networkId()} after init") - usersAndChannels["Users"] - ?.valueOr<Map<String, QVariant_>>(::emptyMap) - ?.entries?.map { (key, value) -> key to value.valueOr<List<QVariant_>>(::emptyList) }?.toMap() - ?.transpose() - ?.forEach { - newIrcUser(it["nick"].value(""), it) + val users: Map<String, QVariant_> = usersAndChannels["Users"].valueOr(::emptyMap) + val userKeys = users.keys + users["nick"].valueOr<QVariantList>(::emptyList).forEachIndexed { index, nick -> + val data = mutableMapOf<String, QVariant_>() + for (it in userKeys) { + val value = users[it].value<QVariantList>()?.get(index) + if (value != null) + data[it] = value } - usersAndChannels["Channels"] - ?.valueOr<Map<String, QVariant_>>(::emptyMap) - ?.entries?.map { (key, value) -> key to value.valueOr<List<QVariant_>>(::emptyList) }?.toMap() - ?.transpose() - ?.forEach { - newIrcChannel(it["name"].value(""), it) + newIrcUser(nick.value(""), data) + } + + val channels: Map<String, QVariant_> = usersAndChannels["Channels"].valueOr(::emptyMap) + val channelKeys = channels.keys + channels["name"].valueOr<QVariantList>(::emptyList).forEachIndexed { index, nick -> + val data = mutableMapOf<String, QVariant_>() + for (it in channelKeys) { + val value = channels[it].value<QVariantList>()?.get(index) + if (value != null) + data[it] = value } + newIrcChannel(nick.value(""), data) + } } override fun initSetProperties(properties: QVariantMap) { diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/RpcHandler.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/RpcHandler.kt index 4a721f9a632f0c89d1208dfafe51a71c65e7b59c..609d8bc078224848f20feb2aa583a261a829e552 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/RpcHandler.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/RpcHandler.kt @@ -65,4 +65,10 @@ class RpcHandler(override val proxy: SignalProxy) : IRpcHandler { RPC("2sendInput(BufferInfo,QString)", ARG(bufferInfo, QType.BufferInfo), ARG(message, Type.QString)) } + + inline fun RPC(function: String, vararg arg: QVariant_) { + // Don’t transmit calls back that we just got from the network + if (proxy.shouldRpc(function)) + proxy.callRpc(function, arg.toList()) + } } diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/SyncableObject.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/SyncableObject.kt index 03e0cfa823bc7d343490a573c0c6aa8825414964..91fa2511423ca450d3c04e8e9fcd2fa9cb24b4be 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/SyncableObject.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/SyncableObject.kt @@ -1,11 +1,10 @@ package de.kuschku.libquassel.quassel.syncables -import de.kuschku.libquassel.protocol.QVariant_ import de.kuschku.libquassel.quassel.syncables.interfaces.ISyncableObject import de.kuschku.libquassel.session.SignalProxy abstract class SyncableObject( - protected val proxy: SignalProxy, + override val proxy: SignalProxy, final override val className: String ) : ISyncableObject { final override var objectName: String = "" @@ -13,16 +12,6 @@ abstract class SyncableObject( override var identifier: String = "$className:" override var initialized: Boolean = false - override fun SYNC(function: String, vararg arg: QVariant_) { - if (initialized) - proxy.callSync(className, objectName, function, arg.toList()) - } - - override fun REQUEST(function: String, vararg arg: QVariant_) { - if (initialized) - proxy.callSync(className, objectName, function, arg.toList()) - } - protected fun renameObject(newName: String) { val oldName = objectName if (!initialized) { diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IAliasManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IAliasManager.kt index 6ca110d250e58c937efdc74a309a6ecd425bfe52..854b3ed0422e2d9bbbfeacc38ca2577de4a8b347 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IAliasManager.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IAliasManager.kt @@ -4,7 +4,6 @@ import de.kuschku.libquassel.annotations.Slot import de.kuschku.libquassel.annotations.Syncable import de.kuschku.libquassel.protocol.ARG import de.kuschku.libquassel.protocol.QVariantMap -import de.kuschku.libquassel.protocol.SLOT import de.kuschku.libquassel.protocol.Type import de.kuschku.libquassel.quassel.BufferInfo @@ -14,7 +13,7 @@ interface IAliasManager : ISyncableObject { fun initSetAliases(aliases: QVariantMap) @Slot fun addAlias(name: String, expansion: String) { - SYNC(SLOT, ARG(name, Type.QString), ARG(expansion, Type.QString)) + SYNC("addAlias", ARG(name, Type.QString), ARG(expansion, Type.QString)) } @Slot diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBacklogManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBacklogManager.kt index 60d27bbffae6cd001172ba58212e399a97f10752..f142ef4818bc4b79d8ae3b60bc06fd2ad003926b 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBacklogManager.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBacklogManager.kt @@ -10,14 +10,14 @@ interface IBacklogManager : ISyncableObject { @Slot fun requestBacklog(bufferId: BufferId, first: MsgId = -1, last: MsgId = -1, limit: Int = -1, additional: Int = 0) { - REQUEST(SLOT, ARG(bufferId, QType.BufferId), ARG(first, QType.MsgId), + REQUEST("requestBacklog", ARG(bufferId, QType.BufferId), ARG(first, QType.MsgId), ARG(last, QType.MsgId), ARG(limit, Type.Int), ARG(additional, Type.Int)) } @Slot fun requestBacklogAll(first: MsgId = -1, last: MsgId = -1, limit: Int = -1, additional: Int = 0) { - REQUEST(SLOT, ARG(first, QType.MsgId), ARG(last, QType.MsgId), + REQUEST("requestBacklogAll", ARG(first, QType.MsgId), ARG(last, QType.MsgId), ARG(limit, Type.Int), ARG(additional, Type.Int)) } diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBufferSyncer.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBufferSyncer.kt index d6bf1e5420d267f6478882047fc05a32e5f40bb4..b0adef439a8780bc5ab5ebc61940bc5f3dd070d7 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBufferSyncer.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBufferSyncer.kt @@ -16,7 +16,7 @@ interface IBufferSyncer : ISyncableObject { @Slot fun markBufferAsRead(buffer: BufferId) { - SYNC(SLOT, ARG(buffer, QType.BufferId)) + SYNC("markBufferAsRead", ARG(buffer, QType.BufferId)) } @Slot @@ -30,52 +30,53 @@ interface IBufferSyncer : ISyncableObject { @Slot fun requestMarkBufferAsRead(buffer: BufferId) { - REQUEST(SLOT, ARG(buffer, QType.BufferId)) + REQUEST("requestMarkBufferAsRead", ARG(buffer, QType.BufferId)) } @Slot fun requestMergeBuffersPermanently(buffer1: BufferId, buffer2: BufferId) { - REQUEST(SLOT, ARG(buffer1, QType.BufferId), ARG(buffer2, QType.BufferId)) + REQUEST("requestMergeBuffersPermanently", ARG(buffer1, QType.BufferId), + ARG(buffer2, QType.BufferId)) } @Slot fun requestPurgeBufferIds() { - REQUEST(SLOT) + REQUEST("requestPurgeBufferIds") } @Slot fun requestRemoveBuffer(buffer: BufferId) { - REQUEST(SLOT, ARG(buffer, QType.BufferId)) + REQUEST("requestRemoveBuffer", ARG(buffer, QType.BufferId)) } @Slot fun requestRenameBuffer(buffer: BufferId, newName: String) { - REQUEST(SLOT, ARG(buffer, QType.BufferId), ARG(newName, Type.QString)) + REQUEST("requestRenameBuffer", ARG(buffer, QType.BufferId), ARG(newName, Type.QString)) } @Slot fun requestSetLastSeenMsg(buffer: BufferId, msgId: MsgId) { - REQUEST(SLOT, ARG(buffer, QType.BufferId), ARG(msgId, QType.MsgId)) + REQUEST("requestSetLastSeenMsg", ARG(buffer, QType.BufferId), ARG(msgId, QType.MsgId)) } @Slot fun requestSetMarkerLine(buffer: BufferId, msgId: MsgId) { - REQUEST(SLOT, ARG(buffer, QType.BufferId), ARG(msgId, QType.MsgId)) + REQUEST("requestSetMarkerLine", ARG(buffer, QType.BufferId), ARG(msgId, QType.MsgId)) } @Slot fun setBufferActivity(buffer: BufferId, activity: Int) { - SYNC(SLOT, ARG(buffer, QType.BufferId), ARG(activity, Type.Int)) + SYNC("setBufferActivity", ARG(buffer, QType.BufferId), ARG(activity, Type.Int)) } @Slot fun setLastSeenMsg(buffer: BufferId, msgId: MsgId) { - SYNC(SLOT, ARG(buffer, QType.BufferId), ARG(msgId, QType.MsgId)) + SYNC("setLastSeenMsg", ARG(buffer, QType.BufferId), ARG(msgId, QType.MsgId)) } @Slot fun setMarkerLine(buffer: BufferId, msgId: MsgId) { - SYNC(SLOT, ARG(buffer, QType.BufferId), ARG(msgId, QType.MsgId)) + SYNC("setMarkerLine", ARG(buffer, QType.BufferId), ARG(msgId, QType.MsgId)) } @Slot diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBufferViewConfig.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBufferViewConfig.kt index 18ecfce41fd12ad03c89f1f2b2c633d5e08cbd08..78e85efdc2791cfd59b12635e7d1998b3282320b 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBufferViewConfig.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBufferViewConfig.kt @@ -31,77 +31,77 @@ interface IBufferViewConfig : ISyncableObject { @Slot fun requestAddBuffer(bufferId: BufferId, pos: Int) { - REQUEST(SLOT, ARG(bufferId, QType.BufferId), ARG(pos, Type.Int)) + REQUEST("requestAddBuffer", ARG(bufferId, QType.BufferId), ARG(pos, Type.Int)) } @Slot fun requestMoveBuffer(bufferId: BufferId, pos: Int) { - REQUEST(SLOT, ARG(bufferId, QType.BufferId), ARG(pos, Type.Int)) + REQUEST("requestMoveBuffer", ARG(bufferId, QType.BufferId), ARG(pos, Type.Int)) } @Slot fun requestRemoveBuffer(bufferId: BufferId) { - REQUEST(SLOT, ARG(bufferId, QType.BufferId)) + REQUEST("requestRemoveBuffer", ARG(bufferId, QType.BufferId)) } @Slot fun requestRemoveBufferPermanently(bufferId: BufferId) { - REQUEST(SLOT, ARG(bufferId, QType.BufferId)) + REQUEST("requestRemoveBufferPermanently", ARG(bufferId, QType.BufferId)) } @Slot fun requestSetBufferViewName(bufferViewName: String) { - REQUEST(SLOT, ARG(bufferViewName, Type.QString)) + REQUEST("requestSetBufferViewName", ARG(bufferViewName, Type.QString)) } @Slot fun setAddNewBuffersAutomatically(addNewBuffersAutomatically: Boolean) { - SYNC(SLOT, ARG(addNewBuffersAutomatically, Type.Bool)) + SYNC("setAddNewBuffersAutomatically", ARG(addNewBuffersAutomatically, Type.Bool)) } @Slot fun setAllowedBufferTypes(bufferTypes: Int) { - SYNC(SLOT, ARG(bufferTypes, Type.Int)) + SYNC("setAllowedBufferTypes", ARG(bufferTypes, Type.Int)) } @Slot fun setBufferViewName(bufferViewName: String) { - SYNC(SLOT, ARG(bufferViewName, Type.QString)) + SYNC("setBufferViewName", ARG(bufferViewName, Type.QString)) } @Slot fun setDisableDecoration(disableDecoration: Boolean) { - SYNC(SLOT, ARG(disableDecoration, Type.Bool)) + SYNC("setDisableDecoration", ARG(disableDecoration, Type.Bool)) } @Slot fun setHideInactiveBuffers(hideInactiveBuffers: Boolean) { - SYNC(SLOT, ARG(hideInactiveBuffers, Type.Bool)) + SYNC("setHideInactiveBuffers", ARG(hideInactiveBuffers, Type.Bool)) } @Slot fun setHideInactiveNetworks(hideInactiveNetworks: Boolean) { - SYNC(SLOT, ARG(hideInactiveNetworks, Type.Bool)) + SYNC("setHideInactiveNetworks", ARG(hideInactiveNetworks, Type.Bool)) } @Slot fun setMinimumActivity(activity: Int) { - SYNC(SLOT, ARG(activity, Type.Int)) + SYNC("setMinimumActivity", ARG(activity, Type.Int)) } @Slot fun setNetworkId(networkId: NetworkId) { - SYNC(SLOT, ARG(networkId, QType.NetworkId)) + SYNC("setNetworkId", ARG(networkId, QType.NetworkId)) } @Slot fun setShowSearch(showSearch: Boolean) { - SYNC(SLOT, ARG(showSearch, Type.Bool)) + SYNC("setShowSearch", ARG(showSearch, Type.Bool)) } @Slot fun setSortAlphabetically(sortAlphabetically: Boolean) { - SYNC(SLOT, ARG(sortAlphabetically, Type.Bool)) + SYNC("setSortAlphabetically", ARG(sortAlphabetically, Type.Bool)) } @Slot diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBufferViewManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBufferViewManager.kt index 53859d2ea68feb0678a5f9fb7857c497b6599d46..a913ea7d882b309eedfadd1f1788438cac1c3d8b 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBufferViewManager.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IBufferViewManager.kt @@ -2,7 +2,10 @@ package de.kuschku.libquassel.quassel.syncables.interfaces import de.kuschku.libquassel.annotations.Slot import de.kuschku.libquassel.annotations.Syncable -import de.kuschku.libquassel.protocol.* +import de.kuschku.libquassel.protocol.ARG +import de.kuschku.libquassel.protocol.QVariantList +import de.kuschku.libquassel.protocol.QVariantMap +import de.kuschku.libquassel.protocol.Type import de.kuschku.libquassel.quassel.syncables.BufferViewConfig @Syncable(name = "BufferViewManager") @@ -25,22 +28,22 @@ interface IBufferViewManager : ISyncableObject { @Slot fun requestCreateBufferView(properties: QVariantMap) { - REQUEST(SLOT, ARG(properties, Type.QVariantMap)) + REQUEST("requestCreateBufferView", ARG(properties, Type.QVariantMap)) } @Slot fun requestCreateBufferViews(properties: QVariantList) { - REQUEST(SLOT, ARG(properties, Type.QVariantList)) + REQUEST("requestCreateBufferViews", ARG(properties, Type.QVariantList)) } @Slot fun requestDeleteBufferView(bufferViewId: Int) { - REQUEST(SLOT, ARG(bufferViewId, Type.Int)) + REQUEST("requestDeleteBufferView", ARG(bufferViewId, Type.Int)) } @Slot fun requestDeleteBufferViews(bufferViews: QVariantList) { - REQUEST(SLOT, ARG(bufferViews, Type.QVariantList)) + REQUEST("requestDeleteBufferViews", ARG(bufferViews, Type.QVariantList)) } @Slot diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ICertManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ICertManager.kt index 62ea085cb48308a1dbe7deeef2dc0e5f952d1a70..b55ea66af35d72a7f7230704ccb7be304b9770a1 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ICertManager.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ICertManager.kt @@ -4,7 +4,6 @@ import de.kuschku.libquassel.annotations.Slot import de.kuschku.libquassel.annotations.Syncable import de.kuschku.libquassel.protocol.ARG import de.kuschku.libquassel.protocol.QVariantMap -import de.kuschku.libquassel.protocol.SLOT import de.kuschku.libquassel.protocol.Type import java.nio.ByteBuffer @@ -16,12 +15,12 @@ interface ICertManager : ISyncableObject { @Slot fun setSslCert(encoded: ByteBuffer?) { - SYNC(SLOT, ARG(encoded, Type.QByteArray)) + SYNC("setSslCert", ARG(encoded, Type.QByteArray)) } @Slot fun setSslKey(encoded: ByteBuffer?) { - SYNC(SLOT, ARG(encoded, Type.QByteArray)) + SYNC("setSslKey", ARG(encoded, Type.QByteArray)) } @Slot diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ICoreInfo.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ICoreInfo.kt index d330d24761958299a454a948aa3d6828d9927cd9..c3b404ec06acd7a032f74a0ed3b200bb58002af8 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ICoreInfo.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ICoreInfo.kt @@ -4,7 +4,6 @@ import de.kuschku.libquassel.annotations.Slot import de.kuschku.libquassel.annotations.Syncable import de.kuschku.libquassel.protocol.ARG import de.kuschku.libquassel.protocol.QVariantMap -import de.kuschku.libquassel.protocol.SLOT import de.kuschku.libquassel.protocol.Type @Syncable(name = "CoreInfo") @@ -15,7 +14,7 @@ interface ICoreInfo : ISyncableObject { @Slot fun setCoreData(data: QVariantMap) { - SYNC(SLOT, ARG(data, Type.QVariantMap)) + SYNC("setCoreData", ARG(data, Type.QVariantMap)) } @Slot diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IDccConfig.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IDccConfig.kt index f0168dfd5196b71825f125d75b0de0db09354820..0f27dedadca57cdc7efa81dad2547145da7b99bf 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IDccConfig.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IDccConfig.kt @@ -2,9 +2,7 @@ package de.kuschku.libquassel.quassel.syncables.interfaces import de.kuschku.libquassel.annotations.Slot import de.kuschku.libquassel.annotations.Syncable -import de.kuschku.libquassel.protocol.QVariantMap -import de.kuschku.libquassel.protocol.UByte -import de.kuschku.libquassel.protocol.UShort +import de.kuschku.libquassel.protocol.* import java.net.InetAddress @Syncable(name = "DccConfig") @@ -14,34 +12,54 @@ interface IDccConfig : ISyncableObject { fun initSetProperties(properties: QVariantMap) @Slot - fun setDccEnabled(enabled: Boolean) + fun setDccEnabled(enabled: Boolean) { + SYNC("setDccEnabled", ARG(enabled, Type.Bool)) + } @Slot - fun setOutgoingIp(outgoingIp: InetAddress) + fun setOutgoingIp(outgoingIp: InetAddress) { + SYNC("setOutgoingIp", ARG(outgoingIp, QType.QHostAddress)) + } @Slot - fun setIpDetectionMode(ipDetectionMode: IpDetectionMode) + fun setIpDetectionMode(ipDetectionMode: IpDetectionMode) { + SYNC("setIpDetectionMode", ARG(ipDetectionMode, QType.DccConfig_IpDetectionMode)) + } @Slot - fun setPortSelectionMode(portSelectionMode: PortSelectionMode) + fun setPortSelectionMode(portSelectionMode: PortSelectionMode) { + SYNC("setPortSelectionMode", ARG(portSelectionMode, QType.DccConfig_PortSelectionMode)) + } @Slot - fun setMinPort(port: UShort) + fun setMinPort(port: UShort) { + SYNC("setMinPort", ARG(port, Type.UShort)) + } @Slot - fun setMaxPort(port: UShort) + fun setMaxPort(port: UShort) { + SYNC("setMaxPort", ARG(port, Type.UShort)) + } @Slot - fun setChunkSize(chunkSize: Int) + fun setChunkSize(chunkSize: Int) { + SYNC("setChunkSize", ARG(chunkSize, Type.Int)) + } @Slot - fun setSendTimeout(timeout: Int) + fun setSendTimeout(timeout: Int) { + SYNC("setSendTimeout", ARG(timeout, Type.Int)) + } @Slot - fun setUsePassiveDcc(use: Boolean) + fun setUsePassiveDcc(use: Boolean) { + SYNC("setUsePassiveDcc", ARG(use, Type.Bool)) + } @Slot - fun setUseFastSend(use: Boolean) + fun setUseFastSend(use: Boolean) { + SYNC("setUseFastSend", ARG(use, Type.Bool)) + } @Slot override fun update(properties: QVariantMap) { diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIdentity.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIdentity.kt index 408584ce5a5df1edeec4f8e5ee1f1226f90d7ee2..d9314996131b576ae72ab17f95c524959bbea5a1 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIdentity.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIdentity.kt @@ -13,102 +13,102 @@ interface IIdentity : ISyncableObject { @Slot fun copyFrom(other: IIdentity) { - SYNC(SLOT, ARG(other, QType.Identity)) + SYNC("copyFrom", ARG(other, QType.Identity)) } @Slot fun setAutoAwayEnabled(enabled: Boolean) { - SYNC(SLOT, ARG(enabled, Type.Bool)) + SYNC("setAutoAwayEnabled", ARG(enabled, Type.Bool)) } @Slot fun setAutoAwayReason(reason: String) { - SYNC(SLOT, ARG(reason, Type.QString)) + SYNC("setAutoAwayReason", ARG(reason, Type.QString)) } @Slot fun setAutoAwayReasonEnabled(enabled: Boolean) { - SYNC(SLOT, ARG(enabled, Type.Bool)) + SYNC("setAutoAwayReasonEnabled", ARG(enabled, Type.Bool)) } @Slot fun setAutoAwayTime(time: Int) { - SYNC(SLOT, ARG(time, Type.Int)) + SYNC("setAutoAwayTime", ARG(time, Type.Int)) } @Slot fun setAwayNick(awayNick: String) { - SYNC(SLOT, ARG(awayNick, Type.QString)) + SYNC("setAwayNick", ARG(awayNick, Type.QString)) } @Slot fun setAwayNickEnabled(enabled: Boolean) { - SYNC(SLOT, ARG(enabled, Type.Bool)) + SYNC("setAwayNickEnabled", ARG(enabled, Type.Bool)) } @Slot fun setAwayReason(awayReason: String) { - SYNC(SLOT, ARG(awayReason, Type.QString)) + SYNC("setAwayReason", ARG(awayReason, Type.QString)) } @Slot fun setAwayReasonEnabled(enabled: Boolean) { - SYNC(SLOT, ARG(enabled, Type.Bool)) + SYNC("setAwayReasonEnabled", ARG(enabled, Type.Bool)) } @Slot fun setDetachAwayEnabled(enabled: Boolean) { - SYNC(SLOT, ARG(enabled, Type.Bool)) + SYNC("setDetachAwayEnabled", ARG(enabled, Type.Bool)) } @Slot fun setDetachAwayReason(reason: String) { - SYNC(SLOT, ARG(reason, Type.QString)) + SYNC("setDetachAwayReason", ARG(reason, Type.QString)) } @Slot fun setDetachAwayReasonEnabled(enabled: Boolean) { - SYNC(SLOT, ARG(enabled, Type.Bool)) + SYNC("setDetachAwayReasonEnabled", ARG(enabled, Type.Bool)) } @Slot fun setId(id: IdentityId) { - SYNC(SLOT, ARG(id, QType.IdentityId)) + SYNC("setId", ARG(id, QType.IdentityId)) } @Slot fun setIdent(ident: String) { - SYNC(SLOT, ARG(ident, Type.QString)) + SYNC("setIdent", ARG(ident, Type.QString)) } @Slot fun setIdentityName(name: String) { - SYNC(SLOT, ARG(name, Type.QString)) + SYNC("setIdentityName", ARG(name, Type.QString)) } @Slot fun setKickReason(reason: String) { - SYNC(SLOT, ARG(reason, Type.QString)) + SYNC("setKickReason", ARG(reason, Type.QString)) } @Slot fun setNicks(nicks: QStringList) { - SYNC(SLOT, ARG(nicks, Type.QStringList)) + SYNC("setNicks", ARG(nicks, Type.QStringList)) } @Slot fun setPartReason(reason: String) { - SYNC(SLOT, ARG(reason, Type.QString)) + SYNC("setPartReason", ARG(reason, Type.QString)) } @Slot fun setQuitReason(reason: String) { - SYNC(SLOT, ARG(reason, Type.QString)) + SYNC("setQuitReason", ARG(reason, Type.QString)) } @Slot fun setRealName(realName: String) { - SYNC(SLOT, ARG(realName, Type.QString)) + SYNC("setRealName", ARG(realName, Type.QString)) } @Slot diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIgnoreListManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIgnoreListManager.kt index 96339a9c7ca535daccc715c9ece754a2b4182621..f28a4dc26d33b7f2b84415295d105a12432719a0 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIgnoreListManager.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIgnoreListManager.kt @@ -4,7 +4,6 @@ import de.kuschku.libquassel.annotations.Slot import de.kuschku.libquassel.annotations.Syncable import de.kuschku.libquassel.protocol.ARG import de.kuschku.libquassel.protocol.QVariantMap -import de.kuschku.libquassel.protocol.SLOT import de.kuschku.libquassel.protocol.Type @Syncable(name = "IgnoreListManager") @@ -21,19 +20,20 @@ interface IIgnoreListManager : ISyncableObject { @Slot fun requestAddIgnoreListItem(type: Int, ignoreRule: String, isRegEx: Boolean, strictness: Int, scope: Int, scopeRule: String, isActive: Boolean) { - REQUEST(SLOT, ARG(type, Type.Int), ARG(ignoreRule, Type.QString), ARG(isRegEx, Type.Bool), + REQUEST("requestAddIgnoreListItem", ARG(type, Type.Int), ARG(ignoreRule, Type.QString), + ARG(isRegEx, Type.Bool), ARG(strictness, Type.Int), ARG(scope, Type.Int), ARG(scopeRule, Type.QString), ARG(isActive, Type.Bool)) } @Slot fun requestRemoveIgnoreListItem(ignoreRule: String) { - REQUEST(SLOT, ARG(ignoreRule, Type.QString)) + REQUEST("requestRemoveIgnoreListItem", ARG(ignoreRule, Type.QString)) } @Slot fun requestToggleIgnoreRule(ignoreRule: String) { - REQUEST(SLOT, ARG(ignoreRule, Type.QString)) + REQUEST("requestToggleIgnoreRule", ARG(ignoreRule, Type.QString)) } @Slot diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIrcChannel.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIrcChannel.kt index a1c7a79fe43c4e4b185bdaba0e5898faf187554a..18070d0ea9d41b10d9f41f120e41bc708dc79c18 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIrcChannel.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIrcChannel.kt @@ -17,7 +17,7 @@ interface IIrcChannel : ISyncableObject { @Slot fun addChannelMode(mode: Char, value: String) { - SYNC(SLOT, ARG(mode, Type.QChar), ARG(value, Type.QString)) + SYNC("addChannelMode", ARG(mode, Type.QChar), ARG(value, Type.QString)) } fun addUserMode(ircuser: IrcUser?, mode: String) { @@ -25,17 +25,17 @@ interface IIrcChannel : ISyncableObject { @Slot fun addUserMode(nick: String, mode: String) { - SYNC(SLOT, ARG(nick, Type.QString), ARG(mode, Type.QString)) + SYNC("addUserMode", ARG(nick, Type.QString), ARG(mode, Type.QString)) } @Slot fun joinIrcUser(ircuser: IrcUser) { - SYNC(SLOT, ARG(ircuser.toVariantMap(), QType.IrcUser)) + SYNC("joinIrcUser", ARG(ircuser.toVariantMap(), QType.IrcUser)) } @Slot fun joinIrcUsers(nicks: QStringList, modes: QStringList) { - SYNC(SLOT, ARG(nicks, Type.QStringList), ARG(modes, Type.QStringList)) + SYNC("joinIrcUsers", ARG(nicks, Type.QStringList), ARG(modes, Type.QStringList)) } fun part(ircuser: IrcUser?) { @@ -43,12 +43,12 @@ interface IIrcChannel : ISyncableObject { @Slot fun part(nick: String) { - SYNC(SLOT, ARG(nick, Type.QString)) + SYNC("part", ARG(nick, Type.QString)) } @Slot fun removeChannelMode(mode: Char, value: String) { - SYNC(SLOT, ARG(mode, Type.QChar), ARG(value, Type.QString)) + SYNC("removeChannelMode", ARG(mode, Type.QChar), ARG(value, Type.QString)) } fun removeUserMode(ircuser: IrcUser?, mode: String) { @@ -56,31 +56,31 @@ interface IIrcChannel : ISyncableObject { @Slot fun removeUserMode(nick: String, mode: String) { - SYNC(SLOT, ARG(nick, Type.QString), ARG(mode, Type.QString)) + SYNC("removeUserMode", ARG(nick, Type.QString), ARG(mode, Type.QString)) } @Slot fun setEncrypted(encrypted: Boolean) { - SYNC(SLOT, ARG(encrypted, Type.Bool)) + SYNC("setEncrypted", ARG(encrypted, Type.Bool)) } @Slot fun setPassword(password: String) { - SYNC(SLOT, ARG(password, Type.QString)) + SYNC("setPassword", ARG(password, Type.QString)) } @Slot fun setTopic(topic: String) { - SYNC(SLOT, ARG(topic, Type.QString)) + SYNC("setTopic", ARG(topic, Type.QString)) } fun setUserModes(ircuser: IrcUser?, modes: String) { - SYNC(SLOT, ARG(ircuser, QType.IrcUser), ARG(modes, Type.QString)) + SYNC("setUserModes", ARG(ircuser, QType.IrcUser), ARG(modes, Type.QString)) } @Slot fun setUserModes(nick: String, modes: String) { - SYNC(SLOT, ARG(nick, Type.QString), ARG(modes, Type.QString)) + SYNC("setUserModes", ARG(nick, Type.QString), ARG(modes, Type.QString)) } @Slot diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIrcListHelper.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIrcListHelper.kt index b54abede3c7b763eea9c7914789e1e79189585c9..8b8788e9e068fc189efa84f6ed3922d43ed8e43b 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIrcListHelper.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIrcListHelper.kt @@ -9,7 +9,8 @@ import de.kuschku.libquassel.protocol.Type interface IIrcListHelper : ISyncableObject { @Slot fun requestChannelList(netId: NetworkId, channelFilters: QStringList): QVariantList { - REQUEST(SLOT, ARG(netId, QType.NetworkId), ARG(channelFilters, Type.QStringList)) + REQUEST("requestChannelList", ARG(netId, QType.NetworkId), + ARG(channelFilters, Type.QStringList)) return emptyList() } @@ -18,12 +19,12 @@ interface IIrcListHelper : ISyncableObject { @Slot fun reportError(error: String) { - SYNC(SLOT, ARG(error, Type.QString)) + SYNC("reportError", ARG(error, Type.QString)) } @Slot fun reportFinishedList(netId: NetworkId) { - SYNC(SLOT, ARG(netId, QType.NetworkId)) + SYNC("reportFinishedList", ARG(netId, QType.NetworkId)) } @Slot diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIrcUser.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIrcUser.kt index 92ee8d466d35a2c8537b9f0c69bd3c54db8cbdd8..b9aaecfddde4a54e5bb0abbbb88255edb8770939 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIrcUser.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IIrcUser.kt @@ -4,7 +4,6 @@ import de.kuschku.libquassel.annotations.Slot import de.kuschku.libquassel.annotations.Syncable import de.kuschku.libquassel.protocol.ARG import de.kuschku.libquassel.protocol.QVariantMap -import de.kuschku.libquassel.protocol.SLOT import de.kuschku.libquassel.protocol.Type import de.kuschku.libquassel.quassel.syncables.IrcChannel import org.threeten.bp.Instant @@ -17,7 +16,7 @@ interface IIrcUser : ISyncableObject { @Slot fun addUserModes(modes: String) { - SYNC(SLOT, ARG(modes, Type.QString)) + SYNC("addUserModes", ARG(modes, Type.QString)) } fun joinChannel(channel: IrcChannel, skip_channel_join: Boolean = false) { @@ -25,7 +24,7 @@ interface IIrcUser : ISyncableObject { @Slot fun joinChannel(channelname: String) { - SYNC(SLOT, ARG(channelname, Type.QString)) + SYNC("joinChannel", ARG(channelname, Type.QString)) } fun partChannel(channel: IrcChannel) { @@ -33,102 +32,102 @@ interface IIrcUser : ISyncableObject { @Slot fun partChannel(channelname: String) { - SYNC(SLOT, ARG(channelname, Type.QString)) + SYNC("partChannel", ARG(channelname, Type.QString)) } @Slot fun quit() { - SYNC(SLOT) + SYNC("quit") } @Slot fun removeUserModes(modes: String) { - SYNC(SLOT, ARG(modes, Type.QString)) + SYNC("removeUserModes", ARG(modes, Type.QString)) } @Slot fun setAccount(account: String) { - SYNC(SLOT, ARG(account, Type.QString)) + SYNC("setAccount", ARG(account, Type.QString)) } @Slot fun setAway(away: Boolean) { - SYNC(SLOT, ARG(away, Type.Bool)) + SYNC("setAway", ARG(away, Type.Bool)) } @Slot fun setAwayMessage(awayMessage: String) { - SYNC(SLOT, ARG(awayMessage, Type.QString)) + SYNC("setAwayMessage", ARG(awayMessage, Type.QString)) } @Slot fun setEncrypted(encrypted: Boolean) { - SYNC(SLOT, ARG(encrypted, Type.Bool)) + SYNC("setEncrypted", ARG(encrypted, Type.Bool)) } @Slot fun setHost(host: String) { - SYNC(SLOT, ARG(host, Type.QString)) + SYNC("setHost", ARG(host, Type.QString)) } @Slot fun setIdleTime(idleTime: Instant) { - SYNC(SLOT, ARG(idleTime, Type.QDateTime)) + SYNC("setIdleTime", ARG(idleTime, Type.QDateTime)) } @Slot fun setIrcOperator(ircOperator: String) { - SYNC(SLOT, ARG(ircOperator, Type.QString)) + SYNC("setIrcOperator", ARG(ircOperator, Type.QString)) } @Slot fun setLastAwayMessage(lastAwayMessage: Int) { - SYNC(SLOT, ARG(lastAwayMessage, Type.Int)) + SYNC("setLastAwayMessage", ARG(lastAwayMessage, Type.Int)) } @Slot fun setLoginTime(loginTime: Instant) { - SYNC(SLOT, ARG(loginTime, Type.QDateTime)) + SYNC("setLoginTime", ARG(loginTime, Type.QDateTime)) } @Slot fun setNick(nick: String) { - SYNC(SLOT, ARG(nick, Type.QString)) + SYNC("setNick", ARG(nick, Type.QString)) } @Slot fun setRealName(realName: String) { - SYNC(SLOT, ARG(realName, Type.QString)) + SYNC("setRealName", ARG(realName, Type.QString)) } @Slot fun setServer(server: String) { - SYNC(SLOT, ARG(server, Type.QString)) + SYNC("setServer", ARG(server, Type.QString)) } @Slot fun setSuserHost(suserHost: String) { - SYNC(SLOT, ARG(suserHost, Type.QString)) + SYNC("setSuserHost", ARG(suserHost, Type.QString)) } @Slot fun setUser(user: String) { - SYNC(SLOT, ARG(user, Type.QString)) + SYNC("setUser", ARG(user, Type.QString)) } @Slot fun setUserModes(modes: String) { - SYNC(SLOT, ARG(modes, Type.QString)) + SYNC("setUserModes", ARG(modes, Type.QString)) } @Slot fun setWhoisServiceReply(whoisServiceReply: String) { - SYNC(SLOT, ARG(whoisServiceReply, Type.QString)) + SYNC("setWhoisServiceReply", ARG(whoisServiceReply, Type.QString)) } @Slot fun updateHostmask(mask: String) { - SYNC(SLOT, ARG(mask, Type.QString)) + SYNC("updateHostmask", ARG(mask, Type.QString)) } @Slot diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt index 4e7079cd5537deb82029a384b9ccbb960f5091a1..6953f88cff2c43f3c91baf44ed0d88b7f324bbb3 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt @@ -25,37 +25,38 @@ interface INetwork : ISyncableObject { @Slot fun acknowledgeCap(capability: String) { - SYNC(SLOT, ARG(capability, Type.QString)) + SYNC("acknowledgeCap", ARG(capability, Type.QString)) } @Slot fun addCap(capability: String, value: String = "") { - SYNC(SLOT, ARG(capability, Type.QString), ARG(value, Type.QString)) + SYNC("addCap", ARG(capability, Type.QString), ARG(value, Type.QString)) } @Slot fun addIrcChannel(channel: String) { - SYNC(SLOT, ARG(channel, Type.QString)) + SYNC("addIrcChannel", ARG(channel, Type.QString)) } @Slot fun addIrcUser(hostmask: String) { - SYNC(SLOT, ARG(hostmask, Type.QString)) + SYNC("addIrcUser", ARG(hostmask, Type.QString)) } @Slot fun addSupport(param: String, value: String = String()) { - SYNC(SLOT, ARG(param, Type.QString), ARG(value, Type.QString)) + SYNC("addSupport(param: String, value: String = String", ARG(param, Type.QString), + ARG(value, Type.QString)) } @Slot fun clearCaps() { - SYNC(SLOT) + SYNC("clearCaps") } @Slot fun emitConnectionError(error: String) { - SYNC(SLOT, ARG(error, Type.QString)) + SYNC("emitConnectionError", ARG(error, Type.QString)) } @Slot @@ -63,167 +64,167 @@ interface INetwork : ISyncableObject { @Slot fun removeCap(capability: String) { - SYNC(SLOT, ARG(capability, Type.QString)) + SYNC("removeCap", ARG(capability, Type.QString)) } @Slot fun removeSupport(param: String) { - SYNC(SLOT, ARG(param, Type.QString)) + SYNC("removeSupport", ARG(param, Type.QString)) } @Slot fun requestConnect() { - REQUEST(SLOT) + REQUEST("requestConnect") } @Slot fun requestDisconnect() { - REQUEST(SLOT) + REQUEST("requestDisconnect") } @Slot fun requestSetNetworkInfo(info: NetworkInfo) { - REQUEST(SLOT, ARG(info, QType.NetworkInfo)) + REQUEST("requestSetNetworkInfo", ARG(info, QType.NetworkInfo)) } @Slot fun setAutoIdentifyPassword(password: String) { - SYNC(SLOT, ARG(password, Type.QString)) + SYNC("setAutoIdentifyPassword", ARG(password, Type.QString)) } @Slot fun setAutoIdentifyService(service: String) { - SYNC(SLOT, ARG(service, Type.QString)) + SYNC("setAutoIdentifyService", ARG(service, Type.QString)) } @Slot fun setAutoReconnectInterval(interval: UInt) { - SYNC(SLOT, ARG(interval, Type.UInt)) + SYNC("setAutoReconnectInterval", ARG(interval, Type.UInt)) } @Slot fun setAutoReconnectRetries(retries: UShort) { - SYNC(SLOT, ARG(retries, Type.UShort)) + SYNC("setAutoReconnectRetries", ARG(retries, Type.UShort)) } @Slot fun setCodecForDecoding(codecName: ByteBuffer?) { - SYNC(SLOT, ARG(codecName, Type.QByteArray)) + SYNC("setCodecForDecoding", ARG(codecName, Type.QByteArray)) } @Slot fun setCodecForEncoding(codecName: ByteBuffer?) { - SYNC(SLOT, ARG(codecName, Type.QByteArray)) + SYNC("setCodecForEncoding", ARG(codecName, Type.QByteArray)) } @Slot fun setCodecForServer(codecName: ByteBuffer?) { - SYNC(SLOT, ARG(codecName, Type.QByteArray)) + SYNC("setCodecForServer", ARG(codecName, Type.QByteArray)) } @Slot fun setConnected(isConnected: Boolean) { - SYNC(SLOT, ARG(isConnected, Type.Bool)) + SYNC("setConnected", ARG(isConnected, Type.Bool)) } @Slot fun setConnectionState(state: Int) { - SYNC(SLOT, ARG(state, Type.Int)) + SYNC("setConnectionState", ARG(state, Type.Int)) } @Slot fun setCurrentServer(currentServer: String) { - SYNC(SLOT, ARG(currentServer, Type.QString)) + SYNC("setCurrentServer", ARG(currentServer, Type.QString)) } @Slot fun setIdentity(identity: IdentityId) { - SYNC(SLOT, ARG(identity, QType.IdentityId)) + SYNC("setIdentity", ARG(identity, QType.IdentityId)) } @Slot fun setLatency(latency: Int) { - SYNC(SLOT, ARG(latency, Type.Int)) + SYNC("setLatency", ARG(latency, Type.Int)) } @Slot fun setMessageRateBurstSize(burstSize: UInt) { - SYNC(SLOT, ARG(burstSize, Type.UInt)) + SYNC("setMessageRateBurstSize", ARG(burstSize, Type.UInt)) } @Slot fun setMessageRateDelay(messageDelay: UInt) { - SYNC(SLOT, ARG(messageDelay, Type.UInt)) + SYNC("setMessageRateDelay", ARG(messageDelay, Type.UInt)) } @Slot fun setMyNick(mynick: String) { - SYNC(SLOT, ARG(mynick, Type.QString)) + SYNC("setMyNick", ARG(mynick, Type.QString)) } @Slot fun setNetworkName(networkName: String) { - SYNC(SLOT, ARG(networkName, Type.QString)) + SYNC("setNetworkName", ARG(networkName, Type.QString)) } @Slot fun setPerform(perform: QStringList) { - SYNC(SLOT, ARG(perform, Type.QStringList)) + SYNC("setPerform", ARG(perform, Type.QStringList)) } @Slot fun setRejoinChannels(rejoinChannels: Boolean) { - SYNC(SLOT, ARG(rejoinChannels, Type.Bool)) + SYNC("setRejoinChannels", ARG(rejoinChannels, Type.Bool)) } @Slot fun setSaslAccount(account: String) { - SYNC(SLOT, ARG(account, Type.QString)) + SYNC("setSaslAccount", ARG(account, Type.QString)) } @Slot fun setSaslPassword(password: String) { - SYNC(SLOT, ARG(password, Type.QString)) + SYNC("setSaslPassword", ARG(password, Type.QString)) } @Slot fun setServerList(serverList: QVariantList) { - SYNC(SLOT, ARG(serverList, Type.QVariantList)) + SYNC("setServerList", ARG(serverList, Type.QVariantList)) } @Slot fun setUnlimitedMessageRate(unlimitedRate: Boolean) { - SYNC(SLOT, ARG(unlimitedRate, Type.Bool)) + SYNC("setUnlimitedMessageRate", ARG(unlimitedRate, Type.Bool)) } @Slot fun setUnlimitedReconnectRetries(unlimitedRetries: Boolean) { - SYNC(SLOT, ARG(unlimitedRetries, Type.Bool)) + SYNC("setUnlimitedReconnectRetries", ARG(unlimitedRetries, Type.Bool)) } @Slot fun setUseAutoIdentify(autoIdentify: Boolean) { - SYNC(SLOT, ARG(autoIdentify, Type.Bool)) + SYNC("setUseAutoIdentify", ARG(autoIdentify, Type.Bool)) } @Slot fun setUseAutoReconnect(autoReconnect: Boolean) { - SYNC(SLOT, ARG(autoReconnect, Type.Bool)) + SYNC("setUseAutoReconnect", ARG(autoReconnect, Type.Bool)) } @Slot fun setUseCustomMessageRate(useCustomRate: Boolean) { - SYNC(SLOT, ARG(useCustomRate, Type.Bool)) + SYNC("setUseCustomMessageRate", ARG(useCustomRate, Type.Bool)) } @Slot fun setUseRandomServer(randomServer: Boolean) { - SYNC(SLOT, ARG(randomServer, Type.Bool)) + SYNC("setUseRandomServer", ARG(randomServer, Type.Bool)) } @Slot fun setUseSasl(sasl: Boolean) { - SYNC(SLOT, ARG(sasl, Type.Bool)) + SYNC("setUseSasl", ARG(sasl, Type.Bool)) } @Slot diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetworkConfig.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetworkConfig.kt index e8a54254cb07014a382cc5026d7a9517fc464f55..313fd9ec7e74cb732b469b946a6faa431a6b71d6 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetworkConfig.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetworkConfig.kt @@ -4,7 +4,6 @@ import de.kuschku.libquassel.annotations.Slot import de.kuschku.libquassel.annotations.Syncable import de.kuschku.libquassel.protocol.ARG import de.kuschku.libquassel.protocol.QVariantMap -import de.kuschku.libquassel.protocol.SLOT import de.kuschku.libquassel.protocol.Type @Syncable(name = "NetworkConfig") @@ -15,82 +14,82 @@ interface INetworkConfig : ISyncableObject { @Slot fun requestSetAutoWhoDelay(i: Int) { - REQUEST(SLOT, ARG(i, Type.Int)) + REQUEST("requestSetAutoWhoDelay", ARG(i, Type.Int)) } @Slot fun requestSetAutoWhoEnabled(b: Boolean) { - REQUEST(SLOT, ARG(b, Type.Bool)) + REQUEST("requestSetAutoWhoEnabled", ARG(b, Type.Bool)) } @Slot fun requestSetAutoWhoInterval(i: Int) { - REQUEST(SLOT, ARG(i, Type.Int)) + REQUEST("requestSetAutoWhoInterval", ARG(i, Type.Int)) } @Slot fun requestSetAutoWhoNickLimit(i: Int) { - REQUEST(SLOT, ARG(i, Type.Int)) + REQUEST("requestSetAutoWhoNickLimit", ARG(i, Type.Int)) } @Slot fun requestSetMaxPingCount(i: Int) { - REQUEST(SLOT, ARG(i, Type.Int)) + REQUEST("requestSetMaxPingCount", ARG(i, Type.Int)) } @Slot fun requestSetPingInterval(i: Int) { - REQUEST(SLOT, ARG(i, Type.Int)) + REQUEST("requestSetPingInterval", ARG(i, Type.Int)) } @Slot fun requestSetPingTimeoutEnabled(b: Boolean) { - REQUEST(SLOT, ARG(b, Type.Bool)) + REQUEST("requestSetPingTimeoutEnabled", ARG(b, Type.Bool)) } @Slot fun requestSetStandardCtcp(b: Boolean) { - REQUEST(SLOT, ARG(b, Type.Bool)) + REQUEST("requestSetStandardCtcp", ARG(b, Type.Bool)) } @Slot fun setAutoWhoDelay(delay: Int) { - SYNC(SLOT, ARG(delay, Type.Int)) + SYNC("setAutoWhoDelay", ARG(delay, Type.Int)) } @Slot fun setAutoWhoEnabled(enabled: Boolean) { - SYNC(SLOT, ARG(enabled, Type.Bool)) + SYNC("setAutoWhoEnabled", ARG(enabled, Type.Bool)) } @Slot fun setAutoWhoInterval(interval: Int) { - SYNC(SLOT, ARG(interval, Type.Int)) + SYNC("setAutoWhoInterval", ARG(interval, Type.Int)) } @Slot fun setAutoWhoNickLimit(limit: Int) { - SYNC(SLOT, ARG(limit, Type.Int)) + SYNC("setAutoWhoNickLimit", ARG(limit, Type.Int)) } @Slot fun setMaxPingCount(count: Int) { - SYNC(SLOT, ARG(count, Type.Int)) + SYNC("setMaxPingCount", ARG(count, Type.Int)) } @Slot fun setPingInterval(interval: Int) { - SYNC(SLOT, ARG(interval, Type.Int)) + SYNC("setPingInterval", ARG(interval, Type.Int)) } @Slot fun setPingTimeoutEnabled(enabled: Boolean) { - SYNC(SLOT, ARG(enabled, Type.Bool)) + SYNC("setPingTimeoutEnabled", ARG(enabled, Type.Bool)) } @Slot fun setStandardCtcp(standardCtcp: Boolean) { - SYNC(SLOT, ARG(standardCtcp, Type.Bool)) + SYNC("setStandardCtcp", ARG(standardCtcp, Type.Bool)) } @Slot diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IRpcHandler.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IRpcHandler.kt index a6425be5d1bd2cb9709fd564907fdbf01fe65ecd..7c9db97568090e7cd3b73bbc3efa4d77fb51bb30 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IRpcHandler.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/IRpcHandler.kt @@ -2,7 +2,10 @@ package de.kuschku.libquassel.quassel.syncables.interfaces import de.kuschku.libquassel.annotations.Slot import de.kuschku.libquassel.annotations.Syncable -import de.kuschku.libquassel.protocol.* +import de.kuschku.libquassel.protocol.IdentityId +import de.kuschku.libquassel.protocol.Message +import de.kuschku.libquassel.protocol.NetworkId +import de.kuschku.libquassel.protocol.QVariantMap import de.kuschku.libquassel.quassel.BufferInfo import de.kuschku.libquassel.session.SignalProxy import java.nio.ByteBuffer @@ -10,7 +13,6 @@ import java.nio.ByteBuffer @Syncable(name = "RpcHandler") interface IRpcHandler { val proxy: SignalProxy - fun RPC(function: String, vararg arg: QVariant_) = proxy.callRpc(function, arg.toList()) @Slot("__objectRenamed__") fun objectRenamed(classname: ByteBuffer, newname: String, oldname: String) diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ISyncableObject.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ISyncableObject.kt index b5dc4f4e0d3665f1b95b7f115ff838cd9fea696f..fa2d663addeea8ae46d435ed89f1460ac12a88d9 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ISyncableObject.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ISyncableObject.kt @@ -1,21 +1,25 @@ package de.kuschku.libquassel.quassel.syncables.interfaces -import de.kuschku.libquassel.protocol.* +import de.kuschku.libquassel.protocol.ARG +import de.kuschku.libquassel.protocol.QVariantMap +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.Type +import de.kuschku.libquassel.session.SignalProxy interface ISyncableObject { val objectName: String var identifier: String val className: String var initialized: Boolean - fun SYNC(function: String, vararg arg: QVariant_) - fun REQUEST(function: String, vararg arg: QVariant_) + val proxy: SignalProxy + fun requestUpdate(properties: QVariantMap = toVariantMap()) { - REQUEST(SLOT, ARG(properties, Type.QVariantMap)) + REQUEST("requestUpdate", ARG(properties, Type.QVariantMap)) } fun update(properties: QVariantMap) { fromVariantMap(properties) - SYNC(SLOT, ARG(properties, Type.QVariantMap)) + SYNC("update", ARG(properties, Type.QVariantMap)) } fun init() {} @@ -23,3 +27,15 @@ interface ISyncableObject { fun fromVariantMap(properties: QVariantMap) = Unit fun toVariantMap(): QVariantMap = emptyMap() } + +inline fun ISyncableObject.SYNC(function: String, vararg arg: QVariant_) { + // Don’t transmit calls back that we just got from the network + if (initialized && proxy.shouldSync(className, objectName, function)) + proxy.callSync(className, objectName, function, arg.toList()) +} + +inline fun ISyncableObject.REQUEST(function: String, vararg arg: QVariant_) { + // Don’t transmit calls back that we just got from the network + if (initialized && proxy.shouldSync(className, objectName, function)) + proxy.callSync(className, objectName, function, arg.toList()) +} diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ITransfer.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ITransfer.kt index 0573f212c5fd676d21ad633c563d2995460436fa..d4457c83019ccf4d579d6413cd377e6dd443d0ec 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ITransfer.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/ITransfer.kt @@ -2,34 +2,52 @@ package de.kuschku.libquassel.quassel.syncables.interfaces import de.kuschku.libquassel.annotations.Slot import de.kuschku.libquassel.annotations.Syncable +import de.kuschku.libquassel.protocol.ARG import de.kuschku.libquassel.protocol.QVariantMap +import de.kuschku.libquassel.protocol.Type import java.nio.ByteBuffer @Syncable(name = "Transfer") interface ITransfer : ISyncableObject { @Slot - fun accept(savePath: String) + fun accept(savePath: String) { + SYNC("accept", ARG(savePath, Type.QString)) + } @Slot - fun reject() + fun reject() { + SYNC("reject") + } @Slot - fun requestAccepted(peer: Long) + fun requestAccepted(peer: Long) { + TODO() + } @Slot - fun requestRejected(peer: Long) + fun requestRejected(peer: Long) { + TODO() + } @Slot - fun setStatus(status: Status) + fun setStatus(status: Status) { + TODO() + } @Slot - fun setError(errorString: String) + fun setError(errorString: String) { + SYNC("setError", ARG(errorString, Type.QString)) + } @Slot - fun dataReceived(peer: Long, data: ByteBuffer) + fun dataReceived(peer: Long, data: ByteBuffer) { + TODO() + } @Slot - fun cleanUp() + fun cleanUp() { + SYNC("cleanUp") + } @Slot override fun update(properties: QVariantMap) { diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/invokers/Invokers.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/invokers/Invokers.kt index 8e6f17e168b150956362a4bc532e72ac989a0a6a..cbfd8c2060441483e98a33f993d1a40ddde0c2a3 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/invokers/Invokers.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/invokers/Invokers.kt @@ -2,12 +2,11 @@ package de.kuschku.libquassel.quassel.syncables.interfaces.invokers import de.kuschku.libquassel.annotations.Syncable import de.kuschku.libquassel.quassel.syncables.interfaces.* -import java.util.logging.Level -import java.util.logging.Logger +import de.kuschku.libquassel.util.LoggingHandler.LogLevel.DEBUG +import de.kuschku.libquassel.util.LoggingHandler.LogLevel.WARN +import de.kuschku.libquassel.util.log object Invokers { - private val logger = Logger.getLogger("Invokers") - private val registry = mutableMapOf<String, Invoker<*>>() fun get(name: String) = registry[name] @@ -37,7 +36,7 @@ object Invokers { RPC = invoker() - logger.log(Level.FINEST, "$size invokers registered") + log(DEBUG, "Invokers", "$size invokers registered") } private inline fun <reified T> invoker(): Invoker<T>? = getInvoker(T::class.java) @@ -45,7 +44,7 @@ object Invokers { private fun <T> getInvoker(type: Class<T>): Invoker<T>? { val syncable: Syncable? = type.getAnnotation(Syncable::class.java) if (syncable == null) { - logger.log(Level.WARNING, "Invoker not annotated: ${type.canonicalName}") + log(WARN, "Invokers", "Invoker not annotated: ${type.canonicalName}") return null } @@ -54,8 +53,8 @@ object Invokers { val klass = Class.forName("$packageName.$className") val invoker = klass.getDeclaredField("INSTANCE").get(null) if (invoker !is Invoker<*>) { - logger.log(Level.WARNING, - "Invoker not of proper type: ${type.canonicalName} != ${invoker.javaClass.canonicalName}") + log(WARN, "Invokers", + "Invoker not of proper type: ${type.canonicalName} != ${invoker.javaClass.canonicalName}") return null } diff --git a/lib/src/main/java/de/kuschku/libquassel/session/AuthHandler.kt b/lib/src/main/java/de/kuschku/libquassel/session/AuthHandler.kt index 57f76686b124691348cb6f5c21bf1ac5c0f0e043..83a5c75393a4cd8012039ca76809f7cd7ce35c00 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/AuthHandler.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/AuthHandler.kt @@ -1,29 +1,29 @@ package de.kuschku.libquassel.session -import de.kuschku.libquassel.protocol.HandshakeMessage +import de.kuschku.libquassel.protocol.message.HandshakeMessage interface AuthHandler { - fun handle(function: HandshakeMessage.ClientInit) {} - fun handle(function: HandshakeMessage.ClientInitReject) {} - fun handle(function: HandshakeMessage.ClientInitAck) {} - fun handle(function: HandshakeMessage.CoreSetupData) {} - fun handle(function: HandshakeMessage.CoreSetupReject) {} - fun handle(function: HandshakeMessage.CoreSetupAck) {} - fun handle(function: HandshakeMessage.ClientLogin) {} - fun handle(function: HandshakeMessage.ClientLoginReject) {} - fun handle(function: HandshakeMessage.ClientLoginAck) {} - fun handle(function: HandshakeMessage.SessionInit) {} + fun handle(f: HandshakeMessage.ClientInit) = false + fun handle(f: HandshakeMessage.ClientInitReject) = false + fun handle(f: HandshakeMessage.ClientInitAck) = false + fun handle(f: HandshakeMessage.CoreSetupData) = false + fun handle(f: HandshakeMessage.CoreSetupReject) = false + fun handle(f: HandshakeMessage.CoreSetupAck) = false + fun handle(f: HandshakeMessage.ClientLogin) = false + fun handle(f: HandshakeMessage.ClientLoginReject) = false + fun handle(f: HandshakeMessage.ClientLoginAck) = false + fun handle(f: HandshakeMessage.SessionInit) = false - fun handle(function: HandshakeMessage) = when (function) { - is HandshakeMessage.ClientInit -> handle(function) - is HandshakeMessage.ClientInitReject -> handle(function) - is HandshakeMessage.ClientInitAck -> handle(function) - is HandshakeMessage.CoreSetupData -> handle(function) - is HandshakeMessage.CoreSetupReject -> handle(function) - is HandshakeMessage.CoreSetupAck -> handle(function) - is HandshakeMessage.ClientLogin -> handle(function) - is HandshakeMessage.ClientLoginReject -> handle(function) - is HandshakeMessage.ClientLoginAck -> handle(function) - is HandshakeMessage.SessionInit -> handle(function) + fun handle(f: HandshakeMessage): Boolean = when (f) { + is HandshakeMessage.ClientInit -> handle(f) + is HandshakeMessage.ClientInitReject -> handle(f) + is HandshakeMessage.ClientInitAck -> handle(f) + is HandshakeMessage.CoreSetupData -> handle(f) + is HandshakeMessage.CoreSetupReject -> handle(f) + is HandshakeMessage.CoreSetupAck -> handle(f) + is HandshakeMessage.ClientLogin -> handle(f) + is HandshakeMessage.ClientLoginReject -> handle(f) + is HandshakeMessage.ClientLoginAck -> handle(f) + is HandshakeMessage.SessionInit -> handle(f) } } diff --git a/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt b/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt index f780f094139ef5b7e901eb3f99be9f702ade2e58..48777e1a00fbb55c17822c380f9509e2eb01aa90 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt @@ -1,9 +1,9 @@ package de.kuschku.libquassel.session -import de.kuschku.libquassel.protocol.HandshakeMessage import de.kuschku.libquassel.protocol.Quassel_Feature import de.kuschku.libquassel.protocol.Quassel_Features -import de.kuschku.libquassel.protocol.SignalProxyMessage +import de.kuschku.libquassel.protocol.message.HandshakeMessage +import de.kuschku.libquassel.protocol.message.SignalProxyMessage import de.kuschku.libquassel.protocol.primitive.serializer.HandshakeVariantMapSerializer import de.kuschku.libquassel.protocol.primitive.serializer.IntSerializer import de.kuschku.libquassel.protocol.primitive.serializer.ProtocolSerializer @@ -11,43 +11,42 @@ import de.kuschku.libquassel.protocol.primitive.serializer.VariantListSerializer import de.kuschku.libquassel.quassel.ProtocolFeature import de.kuschku.libquassel.util.CompatibilityUtils import de.kuschku.libquassel.util.HandlerService +import de.kuschku.libquassel.util.LoggingHandler.LogLevel.* import de.kuschku.libquassel.util.hasFlag import de.kuschku.libquassel.util.helpers.write +import de.kuschku.libquassel.util.log import de.kuschku.libquassel.util.nio.ChainedByteBuffer import de.kuschku.libquassel.util.nio.WrappedChannel +import io.reactivex.subjects.BehaviorSubject import org.threeten.bp.ZoneOffset import org.threeten.bp.format.DateTimeFormatter import java.lang.Thread.UncaughtExceptionHandler import java.net.Socket import java.net.SocketException import java.nio.ByteBuffer -import java.util.logging.Level -import java.util.logging.Logger class CoreConnection( private val session: Session, private val address: SocketAddress, private val handlerService: HandlerService -) : Thread() { - private val logger = Logger.getLogger("CoreConnection") +) : Thread(), ICoreConnection { + companion object { + private const val TAG = "CoreConnection" + } private val exceptionHandler = UncaughtExceptionHandler { thread, throwable -> - logger.log(Level.WARNING, thread.name, throwable) + log(WARN, TAG, thread.name, throwable) } private val sizeBuffer = ByteBuffer.allocateDirect(4) private val chainedBuffer = ChainedByteBuffer(direct = true) - var state = ConnectionState.DISCONNECTED - set(value) { - field = value - logger.log(Level.FINEST, "Connection state changed to $state") - } + override val state = BehaviorSubject.createDefault(ConnectionState.DISCONNECTED) private var channel: WrappedChannel? = null private fun connect() { - state = ConnectionState.CONNECTING + setState(ConnectionState.CONNECTING) val socket = Socket() if (CompatibilityUtils.supportsKeepAlive) socket.keepAlive = true @@ -56,8 +55,14 @@ class CoreConnection( channel = WrappedChannel.ofSocket(socket) } + override fun setState(value: ConnectionState) { + log(INFO, "CoreConnection", value.name) + state.onNext(value) + } + private fun sendHandshake() { - state = ConnectionState.HANDSHAKE + setState(ConnectionState.HANDSHAKE) + IntSerializer.serialize(chainedBuffer, 0x42b33f00 or session.clientData.protocolFeatures.toInt(), session.coreFeatures) @@ -75,7 +80,7 @@ class CoreConnection( sizeBuffer.flip() val protocol = ProtocolSerializer.deserialize(sizeBuffer, session.coreFeatures) - println(protocol) + log(DEBUG, "Protocol negotiated $protocol") // Wrap socket in SSL context if ssl is enabled if (protocol.flags.hasFlag(ProtocolFeature.TLS)) { @@ -104,21 +109,21 @@ class CoreConnection( } } - fun close() { + override fun close() { interrupt() handlerService.quit() val thread = Thread { try { channel?.close() } catch (e: Throwable) { - logger.log(Level.WARNING, "Error encountered while closing connection", e) + log(WARN, TAG, "Error encountered while closing connection", e) } } thread.start() thread.join() } - fun dispatch(message: HandshakeMessage) { + override fun dispatch(message: HandshakeMessage) { handlerService.parse { try { val data = HandshakeMessage.serialize(message) @@ -127,12 +132,12 @@ class CoreConnection( session.coreFeatures) ) } catch (e: Throwable) { - logger.log(Level.WARNING, "Error encountered while serializing handshake message", e) + log(WARN, TAG, "Error encountered while serializing handshake message", e) } } } - fun dispatch(message: SignalProxyMessage) { + override fun dispatch(message: SignalProxyMessage) { handlerService.parse { try { val data = SignalProxyMessage.serialize(message) @@ -140,7 +145,7 @@ class CoreConnection( MessageRunnable(data, VariantListSerializer, chainedBuffer, channel, session.coreFeatures) ) } catch (e: Throwable) { - logger.log(Level.WARNING, "Error encountered while serializing sigproxy message", e) + log(WARN, TAG, "Error encountered while serializing sigproxy message", e) } } } @@ -163,43 +168,47 @@ class CoreConnection( } dataBuffer.flip() handlerService.parse { - when (state) { - ConnectionState.HANDSHAKE -> { - try { - val msg = HandshakeMessage.deserialize( - HandshakeVariantMapSerializer.deserialize(dataBuffer, session.coreFeatures) - ) - try { - session.handle(msg) - } catch (e: Throwable) { - logger.log(Level.WARNING, "Error encountered while handling handshake message", e) - } - } catch (e: Throwable) { - logger.log(Level.WARNING, "Error encountered while parsing handshake message", e) - } - } - else -> - try { - val msg = SignalProxyMessage.deserialize( - VariantListSerializer.deserialize(dataBuffer, session.coreFeatures) - ) - handlerService.handle { - try { - session.handle(msg) - } catch (e: Throwable) { - logger.log(Level.WARNING, "Error encountered while handling sigproxy message", - e) - } - } - } catch (e: Throwable) { - logger.log(Level.WARNING, "Error encountered while parsing sigproxy message", e) - } + when (state.value) { + ConnectionState.HANDSHAKE -> processHandshake(dataBuffer) + else -> processSigProxy(dataBuffer) } } } } catch (e: Throwable) { - logger.log(Level.WARNING, "Error encountered in connection", e) - state = ConnectionState.DISCONNECTED + log(WARN, TAG, "Error encountered in connection", e) + setState(ConnectionState.DISCONNECTED) + } + } + + private fun processSigProxy(dataBuffer: ByteBuffer) { + try { + val msg = SignalProxyMessage.deserialize( + VariantListSerializer.deserialize(dataBuffer, session.coreFeatures) + ) + handlerService.handle { + try { + session.handle(msg) + } catch (e: Throwable) { + log(WARN, TAG, "Error encountered while handling sigproxy message", e) + } + } + } catch (e: Throwable) { + log(WARN, TAG, "Error encountered while parsing sigproxy message", e) + } + } + + private fun processHandshake(dataBuffer: ByteBuffer) { + try { + val msg = HandshakeMessage.deserialize( + HandshakeVariantMapSerializer.deserialize(dataBuffer, session.coreFeatures) + ) + try { + session.handle(msg) + } catch (e: Throwable) { + log(WARN, TAG, "Error encountered while handling handshake message", e) + } + } catch (e: Throwable) { + log(WARN, TAG, "Error encountered while parsing handshake message", e) } } } diff --git a/lib/src/main/java/de/kuschku/libquassel/session/ICoreConnection.kt b/lib/src/main/java/de/kuschku/libquassel/session/ICoreConnection.kt new file mode 100644 index 0000000000000000000000000000000000000000..11d9ddc140219f5c7616d02efef457f7ba38f38d --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/session/ICoreConnection.kt @@ -0,0 +1,28 @@ +package de.kuschku.libquassel.session + +import de.kuschku.libquassel.protocol.message.HandshakeMessage +import de.kuschku.libquassel.protocol.message.SignalProxyMessage +import io.reactivex.subjects.BehaviorSubject + +interface ICoreConnection { + val state: BehaviorSubject<ConnectionState> + fun close() + fun dispatch(message: HandshakeMessage) + fun dispatch(message: SignalProxyMessage) + fun start() + fun join() + fun setState(value: ConnectionState) + + companion object { + val NULL = object : ICoreConnection { + override fun setState(value: ConnectionState) = Unit + override fun start() = Unit + override fun join() = Unit + override fun close() = Unit + override fun dispatch(message: HandshakeMessage) = Unit + override fun dispatch(message: SignalProxyMessage) = Unit + override val state: BehaviorSubject<ConnectionState> + get() = BehaviorSubject.createDefault(ConnectionState.DISCONNECTED) + } + } +} diff --git a/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt b/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt index e525db9f785a8a69d52528e7763a540cbafa8cbb..e3f2b0eca8e68c3d5679619bd526e3202bf48e37 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt @@ -2,12 +2,12 @@ package de.kuschku.libquassel.session import de.kuschku.libquassel.protocol.Quassel_Features import de.kuschku.libquassel.protocol.primitive.serializer.Serializer +import de.kuschku.libquassel.util.LoggingHandler.LogLevel.WARN import de.kuschku.libquassel.util.helpers.write +import de.kuschku.libquassel.util.log import de.kuschku.libquassel.util.nio.ChainedByteBuffer import de.kuschku.libquassel.util.nio.WrappedChannel import java.nio.ByteBuffer -import java.util.logging.Level -import java.util.logging.Logger class MessageRunnable<T>( private val data: T, @@ -26,7 +26,7 @@ class MessageRunnable<T>( channel?.write(chainedBuffer) channel?.flush() } catch (e: Throwable) { - Logger.getLogger("MessageDispatching").log(Level.WARNING, "", e) + log(WARN, "MessageDispatching", e) } } } diff --git a/lib/src/main/java/de/kuschku/libquassel/session/ObjectStorage.kt b/lib/src/main/java/de/kuschku/libquassel/session/ObjectStorage.kt index 6ded8aeba3ae34aa2a0f28d5b6ca90c56c816111..2bdb870bcbf67684364d8c2f19c29e3134119e9e 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/ObjectStorage.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/ObjectStorage.kt @@ -2,8 +2,8 @@ package de.kuschku.libquassel.session import de.kuschku.libquassel.protocol.QType import de.kuschku.libquassel.protocol.QVariant_ -import de.kuschku.libquassel.protocol.SignalProxyMessage import de.kuschku.libquassel.protocol.Type +import de.kuschku.libquassel.protocol.message.SignalProxyMessage import de.kuschku.libquassel.quassel.exceptions.ObjectNotFoundException import de.kuschku.libquassel.quassel.syncables.interfaces.ISyncableObject @@ -22,7 +22,8 @@ class ObjectStorage(private val proxy: SignalProxy) { fun rename(obj: ISyncableObject, new: String, old: String) { objectTree.put("${obj.className}:$new", obj) objectTree.remove("${obj.className}:$old") - proxy.dispatch(SignalProxyMessage.RpcCall("__objectRenamed__", listOf( + proxy.dispatch( + SignalProxyMessage.RpcCall("__objectRenamed__", listOf( QVariant_(obj.className, Type.QString), QVariant_(new, Type.QString), QVariant_(old, Type.QString)) )) diff --git a/lib/src/main/java/de/kuschku/libquassel/session/ProtocolHandler.kt b/lib/src/main/java/de/kuschku/libquassel/session/ProtocolHandler.kt index 1fb303584d3a8ffae0e31faccf65d63e318e976a..0c331bf1ec48b221dcfe83a3594493b6fe47a120 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/ProtocolHandler.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/ProtocolHandler.kt @@ -1,23 +1,20 @@ package de.kuschku.libquassel.session -import de.kuschku.libquassel.protocol.HandshakeMessage import de.kuschku.libquassel.protocol.QVariant_ -import de.kuschku.libquassel.protocol.SignalProxyMessage +import de.kuschku.libquassel.protocol.message.HandshakeMessage +import de.kuschku.libquassel.protocol.message.SignalProxyMessage import de.kuschku.libquassel.quassel.exceptions.ObjectNotFoundException import de.kuschku.libquassel.quassel.syncables.RpcHandler import de.kuschku.libquassel.quassel.syncables.interfaces.ISyncableObject import de.kuschku.libquassel.quassel.syncables.interfaces.invokers.Invokers +import de.kuschku.libquassel.util.LoggingHandler.LogLevel.DEBUG +import de.kuschku.libquassel.util.LoggingHandler.LogLevel.WARN +import de.kuschku.libquassel.util.log import org.threeten.bp.Instant -import java.util.logging.Level -import java.util.logging.Logger abstract class ProtocolHandler : SignalProxy, AuthHandler { - companion object { - private val logger = Logger.getLogger("ProtocolHandler") - } - private val objectStorage: ObjectStorage = ObjectStorage(this) - protected val rpcHandler: RpcHandler = RpcHandler(this) + private val rpcHandler: RpcHandler = RpcHandler(this) private val toInit = mutableMapOf<ISyncableObject, MutableList<SignalProxyMessage.SyncMessage>>() private val syncQueue = mutableListOf<SignalProxyMessage.SyncMessage>() @@ -30,24 +27,30 @@ abstract class ProtocolHandler : SignalProxy, AuthHandler { abstract fun onInitDone() - override fun handle(f: SignalProxyMessage) { + override fun handle(f: SignalProxyMessage): Boolean { try { - super<SignalProxy>.handle(f) + if (!super<SignalProxy>.handle(f)) { + log(DEBUG, "No receiver registered for $f") + } } catch (e: Throwable) { - logger.log(Level.SEVERE, "Error Handling SignalProxyMessage", e) + log(WARN, "ProtocolHandler", "Error Handling SignalProxyMessage", e) } + return true } - override fun handle(function: HandshakeMessage) { + override fun handle(f: HandshakeMessage): Boolean { try { - super<AuthHandler>.handle(function) + if (!super<AuthHandler>.handle(f)) { + log(DEBUG, "No receiver registered for $f") + } } catch (e: Throwable) { - logger.log(Level.SEVERE, "Error Handling HandshakeMessage", e) + log(WARN, "ProtocolHandler", "Error Handling HandshakeMessage", e) } + return true } - override fun handle(f: SignalProxyMessage.InitData) { - logger.log(Level.FINEST, "< $f") + override fun handle(f: SignalProxyMessage.InitData): Boolean { + log(DEBUG, "ProtocolHandler", "< $f") val obj: ISyncableObject = objectStorage.get(f.className, f.objectName) ?: throw ObjectNotFoundException(f.className, f.objectName) @@ -55,39 +58,43 @@ abstract class ProtocolHandler : SignalProxy, AuthHandler { obj.initialized = true synchronize(obj) checkForInitDone() - toInit.remove(obj)?.forEach(this::handle) + toInit.remove(obj)?.map(this::handle) + return true } private fun checkForInitDone() { if (isInitializing && toInit.isEmpty()) { isInitializing = false - syncQueue.forEach(this::handle) onInitDone() + syncQueue.map { + try { + this.handle(it) + } catch (e: Throwable) { + log(WARN, "ProtocolHandler", e) + } + } } } - override fun handle(f: SignalProxyMessage.SyncMessage) { - val obj = objectStorage.get(f.className, f.objectName) - if (obj == null) { - if (isInitializing) { - syncQueue.add(f) - return - } else { - logger.log(Level.FINEST, "< $f") - throw ObjectNotFoundException(f.className, f.objectName) - } + override fun handle(f: SignalProxyMessage.SyncMessage): Boolean { + val obj = objectStorage.get(f.className, f.objectName) ?: if (isInitializing) { + syncQueue.add(f) + return true + } else { + log(DEBUG, "ProtocolHandler", "< $f") + throw ObjectNotFoundException(f.className, f.objectName) } val initQueue = toInit[obj] if (initQueue != null) { initQueue.add(f) - return + return true } - logger.log(Level.FINEST, f.toString()) + log(DEBUG, "ProtocolHandler", f.toString()) - val invoker = Invokers.get(f.className) ?: throw IllegalArgumentException( - "Invalid classname: ${f.className}") + val invoker = Invokers.get(f.className) + ?: throw IllegalArgumentException("Invalid classname: ${f.className}") currentCallClass = f.className currentCallInstance = f.objectName currentCallSlot = f.slotName @@ -95,33 +102,36 @@ abstract class ProtocolHandler : SignalProxy, AuthHandler { currentCallClass = "" currentCallInstance = "" currentCallSlot = "" + return true } - override fun handle(f: SignalProxyMessage.RpcCall) { - logger.log(Level.FINEST, "< $f") + override fun handle(f: SignalProxyMessage.RpcCall): Boolean { + log(DEBUG, "ProtocolHandler", "< $f") currentCallSlot = f.slotName Invokers.RPC?.invoke(rpcHandler, f.slotName, f.params) currentCallSlot = "" + return true } - override fun handle(f: SignalProxyMessage.HeartBeat) { + override fun handle(f: SignalProxyMessage.HeartBeat): Boolean { dispatch(SignalProxyMessage.HeartBeatReply(f.timestamp)) dispatch(SignalProxyMessage.HeartBeat(Instant.now())) + return true } + override fun shouldSync(type: String, instance: String, slot: String): Boolean + = type != currentCallClass || slot != currentCallSlot || instance != currentCallInstance + override fun callSync(type: String, instance: String, slot: String, params: List<QVariant_>) { - // Don’t transmit calls back that we just got from the network - if (type != currentCallClass || slot != currentCallSlot || instance != currentCallInstance) { - dispatch(SignalProxyMessage.SyncMessage(type, instance, slot, params)) - } + dispatch(SignalProxyMessage.SyncMessage(type, instance, slot, params)) } + override fun shouldRpc(slot: String): Boolean + = slot != currentCallSlot + override fun callRpc(slot: String, params: List<QVariant_>) { - // Don’t transmit calls back that we just got from the network - if (slot != currentCallSlot) { - dispatch(SignalProxyMessage.RpcCall(slot, params)) - } + dispatch(SignalProxyMessage.RpcCall(slot, params)) } override fun renameObject(syncableObject: ISyncableObject, newName: String, oldName: String) { @@ -142,7 +152,8 @@ abstract class ProtocolHandler : SignalProxy, AuthHandler { if (baseInit) { toInit.put(syncableObject, mutableListOf()) } - dispatch(SignalProxyMessage.InitRequest(syncableObject.className, syncableObject.objectName)) + dispatch( + SignalProxyMessage.InitRequest(syncableObject.className, syncableObject.objectName)) } } diff --git a/lib/src/main/java/de/kuschku/libquassel/session/Session.kt b/lib/src/main/java/de/kuschku/libquassel/session/Session.kt index 783bf71e2ac7e550c79b4ea442780e63733171a5..96822c05fdf3696fae49c61411e501c61bb03061 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/Session.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/Session.kt @@ -1,23 +1,23 @@ package de.kuschku.libquassel.session import de.kuschku.libquassel.protocol.* +import de.kuschku.libquassel.protocol.message.HandshakeMessage +import de.kuschku.libquassel.protocol.message.SignalProxyMessage import de.kuschku.libquassel.quassel.QuasselFeature import de.kuschku.libquassel.quassel.syncables.* import de.kuschku.libquassel.quassel.syncables.interfaces.invokers.Invokers +import de.kuschku.libquassel.util.LoggingHandler.LogLevel.DEBUG +import de.kuschku.libquassel.util.LoggingHandler.LogLevel.INFO import de.kuschku.libquassel.util.hasFlag +import de.kuschku.libquassel.util.log +import io.reactivex.subjects.BehaviorSubject import org.threeten.bp.Instant -import java.util.logging.Level -import java.util.logging.Logger import javax.net.ssl.X509TrustManager class Session( val clientData: ClientData, - val trustManager: X509TrustManager, - var coreConnection: CoreConnection? = null + val trustManager: X509TrustManager ) : ProtocolHandler() { - companion object { - private val logger = Logger.getLogger("Session") - } var coreFeatures: Quassel_Features = Quassel_Feature.NONE var userData: Pair<String, String>? = null @@ -35,34 +35,33 @@ class Session( private val networks = mutableMapOf<NetworkId, Network>() private val networkConfig = NetworkConfig(this) + val connection = BehaviorSubject.createDefault(ICoreConnection.NULL) + init { - logger.log(Level.FINEST, "Session created") + log(INFO, "Session", "Session created") // This should preload them Invokers } - override fun handle(function: HandshakeMessage.ClientInitAck) { - coreFeatures = function.coreFeatures ?: Quassel_Feature.NONE + override fun handle(f: HandshakeMessage.ClientInitAck): Boolean { + coreFeatures = f.coreFeatures ?: Quassel_Feature.NONE dispatch(HandshakeMessage.ClientLogin( user = userData?.first, password = userData?.second )) + return true } - override fun handle(function: HandshakeMessage.ClientLoginReject) { - - } - - override fun handle(function: HandshakeMessage.SessionInit) { - coreConnection?.state = ConnectionState.INIT + override fun handle(f: HandshakeMessage.SessionInit): Boolean { + connection.value.state.onNext(ConnectionState.INIT) - function.networkIds?.forEach { + f.networkIds?.forEach { val network = Network(it.value(-1), this) networks.put(network.networkId(), network) } - function.identities?.forEach { + f.identities?.forEach { val identity = Identity(this) identity.fromVariantMap(it.valueOr(::emptyMap)) identity.initialized = true @@ -84,35 +83,38 @@ class Session( synchronize(ignoreListManager, true) synchronize(ircListHelper, true) synchronize(networkConfig, true) + + return true } override fun onInitDone() { - coreConnection?.state = ConnectionState.CONNECTED - logger.log(Level.FINEST, "Initialization finished") + connection.value.setState(ConnectionState.CONNECTED) + log(INFO, "Session", "Initialization finished") } - override fun handle(f: SignalProxyMessage.HeartBeatReply) { + override fun handle(f: SignalProxyMessage.HeartBeatReply): Boolean { val now = Instant.now() val latency = now.toEpochMilli() - f.timestamp.toEpochMilli() - logger.log(Level.FINEST, "Latency of $latency ms") + log(INFO, "Session", "Latency of $latency ms") + return true } override fun dispatch(message: SignalProxyMessage) { - logger.log(Level.FINEST, "< $message") - coreConnection?.dispatch(message) + log(DEBUG, "Session", "> $message") + connection.value.dispatch(message) } override fun dispatch(message: HandshakeMessage) { - logger.log(Level.FINEST, "< $message") - coreConnection?.dispatch(message) + log(DEBUG, "Session", "> $message") + connection.value.dispatch(message) } override fun network(id: NetworkId): Network? = networks[id] override fun identity(id: IdentityId): Identity? = identities[id] override fun cleanUp() { - coreConnection?.close() - coreConnection = null + connection.value.close() + connection.onNext(ICoreConnection.NULL) super.cleanUp() } } diff --git a/lib/src/main/java/de/kuschku/libquassel/session/SignalProxy.kt b/lib/src/main/java/de/kuschku/libquassel/session/SignalProxy.kt index 74bce2ee37e012e54623da5b99908467406bbc0d..47d44a496b4c1590b167e773e2e5a527c4df25e7 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/SignalProxy.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/SignalProxy.kt @@ -1,19 +1,23 @@ package de.kuschku.libquassel.session -import de.kuschku.libquassel.protocol.* +import de.kuschku.libquassel.protocol.IdentityId +import de.kuschku.libquassel.protocol.NetworkId +import de.kuschku.libquassel.protocol.QVariant_ +import de.kuschku.libquassel.protocol.message.HandshakeMessage +import de.kuschku.libquassel.protocol.message.SignalProxyMessage import de.kuschku.libquassel.quassel.syncables.Identity import de.kuschku.libquassel.quassel.syncables.Network import de.kuschku.libquassel.quassel.syncables.interfaces.ISyncableObject interface SignalProxy { - fun handle(f: SignalProxyMessage.SyncMessage) {} - fun handle(f: SignalProxyMessage.RpcCall) {} - fun handle(f: SignalProxyMessage.InitRequest) {} - fun handle(f: SignalProxyMessage.InitData) {} - fun handle(f: SignalProxyMessage.HeartBeat) {} - fun handle(f: SignalProxyMessage.HeartBeatReply) {} - - fun handle(f: SignalProxyMessage) = when (f) { + fun handle(f: SignalProxyMessage.SyncMessage) = false + fun handle(f: SignalProxyMessage.RpcCall) = false + fun handle(f: SignalProxyMessage.InitRequest) = false + fun handle(f: SignalProxyMessage.InitData) = false + fun handle(f: SignalProxyMessage.HeartBeat) = false + fun handle(f: SignalProxyMessage.HeartBeatReply) = false + + fun handle(f: SignalProxyMessage): Boolean = when (f) { is SignalProxyMessage.SyncMessage -> handle(f) is SignalProxyMessage.RpcCall -> handle(f) is SignalProxyMessage.InitRequest -> handle(f) @@ -28,6 +32,9 @@ interface SignalProxy { fun callSync(type: String, instance: String, slot: String, params: List<QVariant_>) fun callRpc(slot: String, params: List<QVariant_>) + fun shouldSync(type: String, instance: String, slot: String): Boolean + fun shouldRpc(slot: String): Boolean + fun network(id: NetworkId): Network? fun identity(id: IdentityId): Identity? diff --git a/lib/src/main/java/de/kuschku/libquassel/util/CompatibilityUtils.kt b/lib/src/main/java/de/kuschku/libquassel/util/CompatibilityUtils.kt index 7b6c9cda2d8fb51ec17455fe334b535ec6301094..a9161802a778311fd22cb83265d2c11a70d205c1 100644 --- a/lib/src/main/java/de/kuschku/libquassel/util/CompatibilityUtils.kt +++ b/lib/src/main/java/de/kuschku/libquassel/util/CompatibilityUtils.kt @@ -5,8 +5,8 @@ import java.util.zip.Deflater import java.util.zip.DeflaterOutputStream object CompatibilityUtils { - var supportsKeepAlive = false - var supportsCompression = false + var supportsKeepAlive = true + var supportsCompression = true /** * Creates a SyncFlush output stream, even if the current device does not support doing so diff --git a/lib/src/main/java/de/kuschku/libquassel/util/JavaHandlerService.kt b/lib/src/main/java/de/kuschku/libquassel/util/JavaHandlerService.kt new file mode 100644 index 0000000000000000000000000000000000000000..4459302fd29da85e613c1fe30bf0b7c18cacb858 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/util/JavaHandlerService.kt @@ -0,0 +1,47 @@ +package de.kuschku.libquassel.util + +import java.util.concurrent.Executors + +class JavaHandlerService : HandlerService { + private val parseExecutor = Executors.newSingleThreadExecutor() + private val writeExecutor = Executors.newSingleThreadExecutor() + private val backendExecutor = Executors.newSingleThreadExecutor() + + override fun parse(f: () -> Unit) { + parseExecutor.submit { + try { + f() + } catch (e: Throwable) { + exceptionHandler?.uncaughtException(Thread.currentThread(), e) + } + } + } + + override fun write(f: () -> Unit) { + writeExecutor.submit { + try { + f() + } catch (e: Throwable) { + exceptionHandler?.uncaughtException(Thread.currentThread(), e) + } + } + } + + override fun handle(f: () -> Unit) { + backendExecutor.submit { + try { + f() + } catch (e: Throwable) { + exceptionHandler?.uncaughtException(Thread.currentThread(), e) + } + } + } + + override fun quit() { + parseExecutor.shutdownNow() + writeExecutor.shutdownNow() + backendExecutor.shutdownNow() + } + + override var exceptionHandler: Thread.UncaughtExceptionHandler? = null +} diff --git a/lib/src/main/java/de/kuschku/libquassel/util/JavaLoggingHandler.kt b/lib/src/main/java/de/kuschku/libquassel/util/JavaLoggingHandler.kt new file mode 100644 index 0000000000000000000000000000000000000000..e6e09148d7edbcd833d6a9a858c30e0747bc0310 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/util/JavaLoggingHandler.kt @@ -0,0 +1,33 @@ +package de.kuschku.libquassel.util + +import java.util.logging.Level +import java.util.logging.Logger + +object JavaLoggingHandler : LoggingHandler() { + override fun isLoggable(logLevel: LogLevel, tag: String): Boolean { + return Logger.getLogger(tag).isLoggable(priority(logLevel)) + } + + override fun log(logLevel: LogLevel, tag: String, message: String?, throwable: Throwable?) { + val priority = priority(logLevel) + val logger = Logger.getLogger(tag) + if (message != null) + logger.log(priority, message) + if (throwable != null) + logger.log(priority, "", throwable) + } + + private fun priority(logLevel: LogLevel): Level = when (logLevel) { + LogLevel.VERBOSE -> Level.FINEST + LogLevel.DEBUG -> Level.FINE + LogLevel.INFO -> Level.INFO + LogLevel.WARN -> Level.WARNING + LogLevel.ERROR -> Level.SEVERE + LogLevel.ASSERT -> Level.SEVERE + } + + fun init() { + LoggingHandler.loggingHandlers.clear() + LoggingHandler.loggingHandlers.add(this) + } +} diff --git a/lib/src/main/java/de/kuschku/libquassel/util/LoggingHandler.kt b/lib/src/main/java/de/kuschku/libquassel/util/LoggingHandler.kt new file mode 100644 index 0000000000000000000000000000000000000000..43e5b29644b7262ab8e9644a51354d2360ce148b --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/util/LoggingHandler.kt @@ -0,0 +1,44 @@ +package de.kuschku.libquassel.util + +abstract class LoggingHandler { + abstract fun log(logLevel: LogLevel, tag: String, message: String? = null, + throwable: Throwable? = null) + + abstract fun isLoggable(logLevel: LogLevel, tag: String): Boolean + inline fun isLoggable(logLevel: LogLevel, tag: String, f: LogContext.() -> Unit) { + if (isLoggable(logLevel, tag)) { + object : LogContext { + override fun log(message: String?, throwable: Throwable?) { + log(logLevel, tag, message, throwable) + } + }.f() + } + } + + interface LogContext { + fun log(message: String? = null, throwable: Throwable? = null) + } + + enum class LogLevel { + VERBOSE, + DEBUG, + INFO, + WARN, + ERROR, + ASSERT + } + + companion object { + val loggingHandlers: MutableSet<LoggingHandler> = mutableSetOf() + } +} + +inline fun log(logLevel: LoggingHandler.LogLevel, tag: String, message: String? = null, + throwable: Throwable? = null) { + for (it in LoggingHandler.loggingHandlers) { + it.log(logLevel, tag, message, throwable) + } +} + +inline fun log(logLevel: LoggingHandler.LogLevel, tag: String, throwable: Throwable? = null) + = log(logLevel, tag, null, throwable) diff --git a/lib/src/test/java/de/kuschku/libquassel/ConnectionUnitTest.kt b/lib/src/test/java/de/kuschku/libquassel/ConnectionUnitTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..6ea74866617dd22a6c1aafe5f75212b38f6c7a59 --- /dev/null +++ b/lib/src/test/java/de/kuschku/libquassel/ConnectionUnitTest.kt @@ -0,0 +1,60 @@ +package de.kuschku.libquassel + +import de.kuschku.libquassel.protocol.ClientData +import de.kuschku.libquassel.protocol.Protocol_Feature +import de.kuschku.libquassel.protocol.Quassel_Feature +import de.kuschku.libquassel.protocol.UShort +import de.kuschku.libquassel.quassel.ProtocolFeature +import de.kuschku.libquassel.quassel.QuasselFeature +import de.kuschku.libquassel.session.CoreConnection +import de.kuschku.libquassel.session.Session +import de.kuschku.libquassel.session.SocketAddress +import de.kuschku.libquassel.util.JavaHandlerService +import de.kuschku.libquassel.util.JavaLoggingHandler +import org.junit.BeforeClass +import org.junit.Test +import org.threeten.bp.Instant +import java.security.cert.X509Certificate +import java.util.logging.LogManager +import javax.net.ssl.X509TrustManager + +class ConnectionUnitTest { + companion object { + @JvmStatic + @BeforeClass + fun before() { + JavaLoggingHandler.init() + LogManager.getLogManager().readConfiguration( + this::class.java.getResourceAsStream("/logging.properties")) + } + } + + @Test + fun testLocal() { + runTest("localhost", 4242, "user", "pass") + } + + private fun runTest(host: String, port: UShort, user: String, pass: String) { + val session = Session(ClientData( + identifier = "libquassel test", + buildDate = Instant.EPOCH, + clientFeatures = Quassel_Feature.of(*QuasselFeature.validValues), + protocolFeatures = Protocol_Feature.of(ProtocolFeature.TLS, ProtocolFeature.Compression), + supportedProtocols = byteArrayOf(0x02) + ), object : X509TrustManager { + override fun checkClientTrusted(p0: Array<out X509Certificate>?, p1: String?) { + } + + override fun checkServerTrusted(p0: Array<out X509Certificate>?, p1: String?) { + } + + override fun getAcceptedIssuers(): Array<X509Certificate> = emptyArray() + }) + session.userData = user to pass + + session.connection.onNext( + CoreConnection(session, SocketAddress(host, port), JavaHandlerService())) + session.connection.value.start() + session.connection.value.join() + } +} diff --git a/lib/src/test/resources/logging.properties b/lib/src/test/resources/logging.properties new file mode 100644 index 0000000000000000000000000000000000000000..1a380bc98f1f3d7ee24ab01a943e3d0c5cb3ac7d --- /dev/null +++ b/lib/src/test/resources/logging.properties @@ -0,0 +1,31 @@ +handlers=java.util.logging.ConsoleHandler +config= +.level=ALL +java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$s %5$s%6$s%n +java.util.logging.FileHandler.level=WARNING +java.util.logging.FileHandler.filter= +java.util.logging.FileHandler.formatter= +java.util.logging.FileHandler.encoding= +java.util.logging.FileHandler.limit= +java.util.logging.FileHandler.count= +java.util.logging.FileHandler.append=false +java.util.logging.FileHandler.pattern=log.%u.%g.txt +java.util.logging.ConsoleHandler.level=FINEST +java.util.logging.ConsoleHandler.filter= +java.util.logging.ConsoleHandler.formatter= +java.util.logging.ConsoleHandler.encoding= +java.util.logging.StreamHandler.level=WARNING +java.util.logging.StreamHandler.filter= +java.util.logging.StreamHandler.formatter= +java.util.logging.StreamHandler.encoding= +java.util.logging.SocketHandler.level=WARNING +java.util.logging.SocketHandler.filter= +java.util.logging.SocketHandler.formatter= +java.util.logging.SocketHandler.encoding= +java.util.logging.SocketHandler.host= +java.util.logging.SocketHandler.port= +java.util.logging.MemoryHandler.level=WARNING +java.util.logging.MemoryHandler.filter= +java.util.logging.MemoryHandler.size= +java.util.logging.MemoryHandler.push= +java.util.logging.MemoryHandler.target=