diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ChannelConnection.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ChannelConnection.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c467c3b6e15469fa24cebd0b4663bd4f29095f77
--- /dev/null
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ChannelConnection.kt
@@ -0,0 +1,56 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.connection
+
+import de.justjanne.libquassel.protocol.io.ChainedByteBuffer
+import de.justjanne.libquassel.protocol.io.CoroutineChannel
+import java.nio.ByteBuffer
+import javax.net.ssl.SSLContext
+
+class ChannelConnection(
+  private val channel: CoroutineChannel,
+): Connection {
+  private val sizeBuffer = ByteBuffer.allocateDirect(4)
+  private val buffer = ChainedByteBuffer()
+
+  override suspend fun enableTLS(sslContext: SSLContext) = channel.enableTLS(sslContext)
+
+  override suspend fun enableCompression() = channel.enableCompression()
+
+  override suspend fun send(sizePrefix: Boolean, handler: (buffer: ChainedByteBuffer) -> Unit) {
+    handler(buffer)
+    if (sizePrefix) {
+      sizeBuffer.clear()
+      sizeBuffer.putInt(buffer.size)
+      sizeBuffer.flip()
+      channel.write(sizeBuffer)
+      sizeBuffer.clear()
+    }
+    channel.write(buffer)
+    channel.flush()
+    buffer.clear()
+  }
+
+  override suspend fun <T> read(buffer: ByteBuffer, handler: (buffer: ByteBuffer) -> T): T {
+    channel.read(buffer)
+    buffer.flip()
+    return handler(buffer)
+  }
+
+  override suspend fun <T> read(handler: (buffer: ByteBuffer) -> T): T {
+    sizeBuffer.clear()
+    channel.read(sizeBuffer)
+    sizeBuffer.flip()
+    val content = ByteBuffer.allocateDirect(sizeBuffer.getInt())
+    channel.read(content)
+    content.flip()
+    return handler(content)
+  }
+}
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ClientHandshakeHandler.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ClientHandshakeHandler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..46d655dbfd6afcb589a5be2b348deacf7199691c
--- /dev/null
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ClientHandshakeHandler.kt
@@ -0,0 +1,58 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.connection
+
+import de.justjanne.libquassel.protocol.exceptions.HandshakeException
+import de.justjanne.libquassel.protocol.features.FeatureSet
+import de.justjanne.libquassel.protocol.models.HandshakeMessage
+import de.justjanne.libquassel.protocol.serializers.HandshakeMessageSerializer
+
+class ClientHandshakeHandler(
+  private val clientInit: HandshakeMessage.ClientInit,
+  private val clientLogin: HandshakeMessage.ClientLogin,
+) : ConnectionHandler<HandshakeState> {
+  private suspend fun Connection.request(message: HandshakeMessage): HandshakeMessage {
+    send(sizePrefix = true) {
+      HandshakeMessageSerializer.serialize(it, message, FeatureSet.none())
+    }
+    return read { HandshakeMessageSerializer.deserialize(it, FeatureSet.none()) }
+  }
+
+  private suspend fun Connection.clientInit(message: HandshakeMessage.ClientInit): Result<HandshakeMessage.ClientInitAck> =
+    when (val result = request(message)) {
+      is HandshakeMessage.ClientInitAck -> Result.success(result)
+      is HandshakeMessage.ClientInitReject -> Result.failure(HandshakeException.InitException(result.errorString ?: "Unknown error"))
+      else -> Result.failure(HandshakeException.InitException("Unknown error"))
+    }
+
+  private suspend fun Connection.clientLogin(message: HandshakeMessage.ClientLogin): Result<HandshakeMessage.ClientLoginAck> =
+    when (val result = request(message)) {
+      is HandshakeMessage.ClientLoginAck -> Result.success(result)
+      is HandshakeMessage.ClientLoginReject -> Result.failure(HandshakeException.InitException(result.errorString ?: "Unknown error"))
+      else -> Result.failure(HandshakeException.InitException("Unknown error"))
+    }
+
+  private suspend fun Connection.coreSetup(message: HandshakeMessage.CoreSetupData): Result<HandshakeMessage.CoreSetupAck> =
+    when (val result = request(message)) {
+      is HandshakeMessage.CoreSetupAck -> Result.success(result)
+      is HandshakeMessage.CoreSetupReject -> Result.failure(HandshakeException.InitException(result.errorString ?: "Unknown error"))
+      else -> Result.failure(HandshakeException.InitException("Unknown error"))
+    }
+
+  override suspend fun handle(connection: Connection) = runCatching {
+    val init = connection.clientInit(clientInit).getOrThrow()
+    connection.clientLogin(clientLogin).getOrThrow()
+    val sessionInit = when (val result = connection.read { HandshakeMessageSerializer.deserialize(it, FeatureSet.none()) }) {
+      is HandshakeMessage.SessionInit -> Result.success(result)
+      else -> Result.failure(HandshakeException.InitException("Unknown error"))
+    }.getOrThrow()
+    HandshakeState(init, sessionInit)
+  }
+}
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ClientSessionHandler.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ClientSessionHandler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..30e83a8b8b5ea3610cb1eabcba7a8e8f89750573
--- /dev/null
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ClientSessionHandler.kt
@@ -0,0 +1,53 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.connection
+
+import de.justjanne.libquassel.protocol.api.ObjectName
+import de.justjanne.libquassel.protocol.api.dispatcher.RpcDispatcher
+import de.justjanne.libquassel.protocol.api.dispatcher.SyncHandler
+import de.justjanne.libquassel.protocol.models.SignalProxyMessage
+import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.serializers.SignalProxyMessageSerializer
+import de.justjanne.libquassel.protocol.variant.qVariant
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.update
+
+class ClientSessionHandler(
+  private val handshake: HandshakeState,
+  private val sync: SyncHandler,
+  private val rpc: RpcDispatcher,
+) : ConnectionHandler<Unit> {
+  val toInit = MutableStateFlow<List<Pair<String, String>>?>(null)
+
+  override suspend fun handle(connection: Connection) = runCatching {
+    suspend fun Connection.send(message: SignalProxyMessage) = send(true) {
+      SignalProxyMessageSerializer.serialize(it, message, handshake.clientInitAck.featureSet)
+    }
+
+    toInit.value = listOf(
+      Pair("AliasManager", "")
+    )
+    connection.send(SignalProxyMessage.InitRequest("AliasManager", ""))
+
+    while (true) {
+      when (val message = connection.read { SignalProxyMessageSerializer.deserialize(it, handshake.clientInitAck.featureSet) }) {
+        is SignalProxyMessage.HeartBeat -> connection.send(SignalProxyMessage.HeartBeatReply(message.timestamp))
+        is SignalProxyMessage.HeartBeatReply -> Unit
+        is SignalProxyMessage.InitData -> {
+          sync.invoke(message.className, ObjectName(message.objectName), "update", listOf(qVariant(message.initData, QtType.QVariantMap)))
+          toInit.update { it?.minus(Pair(message.className, message.objectName)) }
+        }
+        is SignalProxyMessage.InitRequest -> Unit
+        is SignalProxyMessage.Rpc -> rpc.invoke(message.slotName, message.params)
+        is SignalProxyMessage.Sync -> sync.invoke(message.className, ObjectName(message.objectName), message.slotName, message.params)
+      }
+    }
+  }
+}
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/Connection.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/Connection.kt
new file mode 100644
index 0000000000000000000000000000000000000000..667b009d3f6a95411fd6cef5363b5677afab47aa
--- /dev/null
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/Connection.kt
@@ -0,0 +1,23 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.connection
+
+import de.justjanne.libquassel.protocol.io.ChainedByteBuffer
+import java.nio.ByteBuffer
+import javax.net.ssl.SSLContext
+
+interface Connection {
+  suspend fun enableTLS(sslContext: SSLContext)
+  suspend fun enableCompression()
+
+  suspend fun send(sizePrefix: Boolean, handler: (buffer: ChainedByteBuffer) -> Unit)
+  suspend fun <T> read(buffer: ByteBuffer, handler: (buffer: ByteBuffer) -> T): T
+  suspend fun <T> read(handler: (buffer: ByteBuffer) -> T): T
+}
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ConnectionHandler.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ConnectionHandler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..268146b3cb18dc5c8dbfa13d2c9e1a2dc38f4f34
--- /dev/null
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ConnectionHandler.kt
@@ -0,0 +1,14 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.connection
+
+interface ConnectionHandler<T> {
+  suspend fun handle(connection: Connection): Result<T>
+}
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ConnectionSetupState.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ConnectionSetupState.kt
new file mode 100644
index 0000000000000000000000000000000000000000..afdb6486e80014eb6a46b48ec8425b333a6678be
--- /dev/null
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/ConnectionSetupState.kt
@@ -0,0 +1,16 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.connection
+
+import de.justjanne.libquassel.protocol.connection.CoreHeader
+
+data class ConnectionSetupState(
+  val coreHeader: CoreHeader,
+)
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/HandshakeState.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/HandshakeState.kt
new file mode 100644
index 0000000000000000000000000000000000000000..019a9add5c9a33c855d497bafbe6b36bbc37dd92
--- /dev/null
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/HandshakeState.kt
@@ -0,0 +1,17 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.connection
+
+import de.justjanne.libquassel.protocol.models.HandshakeMessage
+
+data class HandshakeState(
+  val clientInitAck: HandshakeMessage.ClientInitAck,
+  val sessionInit: HandshakeMessage.SessionInit,
+)
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/MagicHandler.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/MagicHandler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..779e191442697da90b7c9769e37c31e66b8296f0
--- /dev/null
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/connection/MagicHandler.kt
@@ -0,0 +1,39 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.connection
+
+import de.justjanne.libquassel.protocol.connection.ClientHeader
+import de.justjanne.libquassel.protocol.connection.ClientHeaderSerializer
+import de.justjanne.libquassel.protocol.connection.CoreHeader
+import de.justjanne.libquassel.protocol.connection.CoreHeaderSerializer
+import de.justjanne.libquassel.protocol.connection.ProtocolFeature
+import de.justjanne.libquassel.protocol.features.FeatureSet
+import java.nio.ByteBuffer
+import javax.net.ssl.SSLContext
+
+class MagicHandler(
+  private val clientHeader: ClientHeader,
+) : ConnectionHandler<ConnectionSetupState> {
+  override suspend fun handle(connection: Connection) = runCatching {
+    connection.send(sizePrefix = false) {
+      ClientHeaderSerializer.serialize(it, clientHeader, FeatureSet.none())
+    }
+    val protocol: CoreHeader = connection.read(ByteBuffer.allocateDirect(4)) {
+      CoreHeaderSerializer.deserialize(it, FeatureSet.none())
+    }
+    if (protocol.features.contains(ProtocolFeature.TLS)) {
+      connection.enableTLS(SSLContext.getDefault())
+    }
+    if (protocol.features.contains(ProtocolFeature.Compression)) {
+      connection.enableCompression()
+    }
+    ConnectionSetupState(protocol)
+  }
+}
diff --git a/libquassel-client/src/test/kotlin/de/justjanne/libquassel/client/QuasselApiTest.kt b/libquassel-client/src/test/kotlin/de/justjanne/libquassel/client/QuasselApiTest.kt
index 369e2fc22b3ba6889a2ddbeb690f9ca6d078dc60..ac19ec3ac76873b577e121ff8ef1e5150f4114d5 100644
--- a/libquassel-client/src/test/kotlin/de/justjanne/libquassel/client/QuasselApiTest.kt
+++ b/libquassel-client/src/test/kotlin/de/justjanne/libquassel/client/QuasselApiTest.kt
@@ -15,6 +15,7 @@ import dagger.Binds
 import dagger.Component
 import dagger.Module
 import dagger.Provides
+import de.justjanne.bitflags.of
 import de.justjanne.libquassel.backend.AliasManagerPersister
 import de.justjanne.libquassel.backend.BacklogManagerPersister
 import de.justjanne.libquassel.backend.BufferSyncerPersister
@@ -31,8 +32,11 @@ import de.justjanne.libquassel.backend.IrcUserPersister
 import de.justjanne.libquassel.backend.NetworkConfigPersister
 import de.justjanne.libquassel.backend.NetworkPersister
 import de.justjanne.libquassel.backend.RpcPersister
+import de.justjanne.libquassel.connection.ChannelConnection
+import de.justjanne.libquassel.connection.ClientHandshakeHandler
+import de.justjanne.libquassel.connection.ClientSessionHandler
+import de.justjanne.libquassel.connection.MagicHandler
 import de.justjanne.libquassel.persistence.AliasEntity
-import de.justjanne.libquassel.persistence.AliasRepository
 import de.justjanne.libquassel.persistence.AppDatabase
 import de.justjanne.libquassel.protocol.api.ObjectName
 import de.justjanne.libquassel.protocol.api.client.AliasManagerClientApi
@@ -68,7 +72,14 @@ import de.justjanne.libquassel.protocol.api.server.IgnoreListManagerServerApi
 import de.justjanne.libquassel.protocol.api.server.IrcListHelperServerApi
 import de.justjanne.libquassel.protocol.api.server.NetworkConfigServerApi
 import de.justjanne.libquassel.protocol.api.server.NetworkServerApi
+import de.justjanne.libquassel.protocol.connection.ClientHeader
+import de.justjanne.libquassel.protocol.connection.ProtocolFeature
+import de.justjanne.libquassel.protocol.connection.ProtocolMeta
+import de.justjanne.libquassel.protocol.connection.ProtocolVersion
 import de.justjanne.libquassel.protocol.exceptions.RpcInvocationFailedException
+import de.justjanne.libquassel.protocol.features.FeatureSet
+import de.justjanne.libquassel.protocol.io.CoroutineChannel
+import de.justjanne.libquassel.protocol.models.HandshakeMessage
 import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.models.ids.MsgId
 import de.justjanne.libquassel.protocol.models.types.QtType
@@ -77,17 +88,24 @@ import de.justjanne.libquassel.protocol.variant.QVariant_
 import de.justjanne.libquassel.protocol.variant.qVariant
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.TimeoutCancellationException
 import kotlinx.coroutines.cancelAndJoin
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withTimeout
 import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.assertThrows
+import java.net.InetSocketAddress
+import java.nio.channels.ClosedByInterruptException
 import javax.inject.Inject
 import javax.inject.Singleton
 import kotlin.test.assertFails
 import kotlin.test.assertFailsWith
 import kotlin.time.Duration.Companion.milliseconds
+import kotlin.time.Duration.Companion.seconds
 
 @Singleton
 class ProxyImpl @Inject constructor() : Proxy {
@@ -123,6 +141,7 @@ interface ClientModule {
 
 @Module
 class DatabaseModule {
+  @Singleton
   @Provides
   fun database(): AppDatabase =
     Room.inMemoryDatabaseBuilder<AppDatabase>()
@@ -163,7 +182,7 @@ interface ClientComponent {
 
 class QuasselApiTest {
   @Test
-  fun test() = runBlocking{
+  fun test() = runBlocking {
     val client = DaggerClientComponent.builder().build()
     client.sync().invoke(
       "AliasManager",
@@ -191,7 +210,6 @@ class QuasselApiTest {
     client.api().certManager.requestUpdate(ObjectName(""), emptyMap())
     client.api().highlightRuleManager.requestRemoveHighlightRule(5)
     client.api().identity.requestUpdate(ObjectName(""), emptyMap())
-    println("hi!")
   }
 
   @Test
@@ -223,4 +241,38 @@ class QuasselApiTest {
     delay(10.milliseconds)
     job.cancelAndJoin()
   }
+
+  @Test
+  fun testConnection() = runBlocking {
+    val di = DaggerClientComponent.builder().build()
+    val channel = CoroutineChannel()
+    withTimeout(500.milliseconds) {
+      channel.connect(InetSocketAddress("decentralised.chat", 4242), keepAlive = true)
+    }
+    val connection = ChannelConnection(channel)
+    val connectionSetup = withTimeout(500.milliseconds) {
+      MagicHandler(
+        ClientHeader(
+          features = ProtocolFeature.of(ProtocolFeature.Compression, ProtocolFeature.TLS),
+          versions = listOf(ProtocolMeta(ProtocolVersion.Datastream, 0u))
+        ),
+      ).handle(connection)
+    }.getOrThrow()
+    val handshake = withTimeout(500.milliseconds) {
+      ClientHandshakeHandler(
+        HandshakeMessage.ClientInit(clientVersion = "", buildDate = "", featureSet = FeatureSet.none()),
+        HandshakeMessage.ClientLogin(Const.user, Const.pass),
+      ).handle(connection)
+    }.getOrThrow()
+    val sessionHandler = ClientSessionHandler(handshake, di.sync(), di.rpc())
+    withTimeout(2.seconds) {
+      launch {
+        sessionHandler.handle(connection)
+      }
+      sessionHandler.toInit.first { it != null && it.isEmpty() }
+      channel.close()
+    }
+    println(di.db().alias().getAll())
+    Unit
+  }
 }
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/ConnectionHandler.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/ConnectionHandler.kt
deleted file mode 100644
index d4dadc7ff3d87f64960842dac647bfaa28af34a0..0000000000000000000000000000000000000000
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/ConnectionHandler.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * libquassel
- * Copyright (c) 2021 Janne Mareike Koschinski
- *
- * This Source Code Form is subject to the terms of the Mozilla Public License,
- * v. 2.0. If a copy of the MPL was not distributed with this file, You can
- * obtain one at https://mozilla.org/MPL/2.0/.
- */
-
-package de.justjanne.libquassel.protocol.session
-
-import java.nio.ByteBuffer
-
-interface ConnectionHandler {
-  suspend fun init(channel: MessageChannel): Boolean
-
-  suspend fun done()
-
-  suspend fun read(buffer: ByteBuffer): Boolean
-}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/CoreState.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/CoreState.kt
deleted file mode 100644
index 49acd8ffedc22a5092814dc7c09e6fb516724a83..0000000000000000000000000000000000000000
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/CoreState.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * libquassel
- * Copyright (c) 2021 Janne Mareike Koschinski
- *
- * This Source Code Form is subject to the terms of the Mozilla Public License,
- * v. 2.0. If a copy of the MPL was not distributed with this file, You can
- * obtain one at https://mozilla.org/MPL/2.0/.
- */
-
-package de.justjanne.libquassel.protocol.session
-
-import de.justjanne.libquassel.protocol.models.setup.BackendInfo
-
-sealed class CoreState {
-  object Configured : CoreState()
-
-  data class Unconfigured(
-    val databases: List<BackendInfo>,
-    val authenticators: List<BackendInfo>,
-  ) : CoreState()
-}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/HandshakeHandler.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/HandshakeHandler.kt
deleted file mode 100644
index dde3a9f80441396a0a12515e5b07cdf13a665c49..0000000000000000000000000000000000000000
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/HandshakeHandler.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * libquassel
- * Copyright (c) 2021 Janne Mareike Koschinski
- *
- * This Source Code Form is subject to the terms of the Mozilla Public License,
- * v. 2.0. If a copy of the MPL was not distributed with this file, You can
- * obtain one at https://mozilla.org/MPL/2.0/.
- */
-
-package de.justjanne.libquassel.protocol.session
-
-import de.justjanne.libquassel.protocol.exceptions.HandshakeException
-import de.justjanne.libquassel.protocol.features.FeatureSet
-import de.justjanne.libquassel.protocol.variant.QVariantMap
-
-interface HandshakeHandler : ConnectionHandler {
-  /**
-   * Register client and start connection
-   */
-  @Throws(HandshakeException.InitException::class)
-  suspend fun init(
-    /**
-     * Human readable (HTML formatted) version of the client
-     */
-    clientVersion: String,
-    /**
-     * Build timestamp of the client
-     */
-    buildDate: String,
-    /**
-     * Enabled client features for this connection
-     */
-    featureSet: FeatureSet,
-  ): CoreState
-
-  /**
-   * Login to core with authentication data
-   */
-  @Throws(HandshakeException.LoginException::class)
-  suspend fun login(
-    /**
-     * Username of the core account
-     */
-    username: String,
-    /**
-     * Password of the core account
-     */
-    password: String,
-  )
-
-  /**
-   * Configure core for the first time
-   */
-  @Throws(HandshakeException.SetupException::class)
-  suspend fun configureCore(
-    /**
-     * Username of a new core account to be created
-     */
-    adminUsername: String,
-    /**
-     * Password of a new core account to be created
-     */
-    adminPassword: String,
-    /**
-     * Chosen storage backend id
-     */
-    backend: String,
-    /**
-     * Storage backend configuration data
-     */
-    backendConfiguration: QVariantMap,
-    /**
-     * Chosen authenticator backend id
-     */
-    authenticator: String,
-    /**
-     * Authenticator backend configuration data
-     */
-    authenticatorConfiguration: QVariantMap,
-  )
-}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/MessageChannel.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/MessageChannel.kt
deleted file mode 100644
index 8ca8b05838ebd02a09ec933951a4d665e210a39f..0000000000000000000000000000000000000000
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/MessageChannel.kt
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * libquassel
- * Copyright (c) 2021 Janne Mareike Koschinski
- *
- * This Source Code Form is subject to the terms of the Mozilla Public License,
- * v. 2.0. If a copy of the MPL was not distributed with this file, You can
- * obtain one at https://mozilla.org/MPL/2.0/.
- */
-
-package de.justjanne.libquassel.protocol.session
-
-import de.justjanne.libquassel.protocol.features.FeatureSet
-import de.justjanne.libquassel.protocol.io.ChainedByteBuffer
-import de.justjanne.libquassel.protocol.io.CoroutineChannel
-import de.justjanne.libquassel.protocol.models.HandshakeMessage
-import de.justjanne.libquassel.protocol.models.SignalProxyMessage
-import de.justjanne.libquassel.protocol.serializers.HandshakeMessageSerializer
-import de.justjanne.libquassel.protocol.serializers.SignalProxyMessageSerializer
-import de.justjanne.libquassel.protocol.util.log.trace
-import kotlinx.coroutines.coroutineScope
-import org.slf4j.LoggerFactory
-import java.io.Closeable
-import java.nio.ByteBuffer
-
-class MessageChannel(
-  val channel: CoroutineChannel,
-) : Closeable {
-  var negotiatedFeatures = FeatureSet.none()
-
-  private var handlers = mutableListOf<ConnectionHandler>()
-
-  fun register(handler: ConnectionHandler) {
-    handlers.add(handler)
-  }
-
-  private val sendBuffer = ThreadLocal.withInitial(::ChainedByteBuffer)
-  private val sizeBuffer = ThreadLocal.withInitial { ByteBuffer.allocateDirect(4) }
-
-  suspend fun init() {
-    setupHandlers()
-  }
-
-  private suspend fun readAmount(): Int {
-    val sizeBuffer = sizeBuffer.get()
-
-    sizeBuffer.clear()
-    channel.read(sizeBuffer)
-    sizeBuffer.flip()
-    val size = sizeBuffer.int
-    sizeBuffer.clear()
-    return size
-  }
-
-  suspend fun read() {
-    val amount = readAmount()
-    val messageBuffer = ByteBuffer.allocateDirect(minOf(amount, 65 * 1024 * 1024))
-    channel.read(messageBuffer)
-    messageBuffer.flip()
-    dispatch(messageBuffer)
-  }
-
-  private suspend fun setupHandlers(): List<ConnectionHandler> {
-    val removed = mutableListOf<ConnectionHandler>()
-    while (true) {
-      val handler = handlers.firstOrNull()
-      logger.trace { "Setting up handler $handler" }
-      if (handler?.init(this) != true) {
-        break
-      }
-      logger.trace { "Handler $handler is done" }
-      removed.add(handlers.removeFirst())
-    }
-    if (handlers.isEmpty()) {
-      logger.trace { "All handlers done" }
-      channel.close()
-    }
-    return removed
-  }
-
-  private suspend fun dispatch(message: ByteBuffer) {
-    val handlerDone =
-      try {
-        handlers.first().read(message)
-      } catch (e: Exception) {
-        logger.warn("Error while handling message: ", e)
-        false
-      }
-    if (handlerDone) {
-      val removed = listOf(handlers.removeFirst()) + setupHandlers()
-      for (handler in removed) {
-        handler.done()
-      }
-    }
-  }
-
-  suspend fun emit(message: HandshakeMessage) =
-    emit {
-      logger.trace { "Writing handshake message $message" }
-      HandshakeMessageSerializer.serialize(it, message, negotiatedFeatures)
-    }
-
-  suspend fun emit(message: SignalProxyMessage) =
-    emit {
-      logger.trace { "Writing signal proxy message $message" }
-      SignalProxyMessageSerializer.serialize(it, message, negotiatedFeatures)
-    }
-
-  suspend fun emit(
-    sizePrefix: Boolean = true,
-    f: (ChainedByteBuffer) -> Unit,
-  ) = coroutineScope {
-    val sendBuffer = sendBuffer.get()
-    val sizeBuffer = sizeBuffer.get()
-
-    f(sendBuffer)
-    if (sizePrefix) {
-      sizeBuffer.clear()
-      sizeBuffer.putInt(sendBuffer.size)
-      sizeBuffer.flip()
-      channel.write(sizeBuffer)
-      sizeBuffer.clear()
-    }
-    channel.write(sendBuffer)
-    channel.flush()
-    sendBuffer.clear()
-  }
-
-  override fun close() {
-    channel.close()
-  }
-
-  companion object {
-    private val logger = LoggerFactory.getLogger(MessageChannel::class.java)
-  }
-}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/MessageChannelReader.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/MessageChannelReader.kt
deleted file mode 100644
index 28dbe476aa76688fb873269440f940c422cc57cf..0000000000000000000000000000000000000000
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/MessageChannelReader.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * libquassel
- * Copyright (c) 2021 Janne Mareike Koschinski
- *
- * This Source Code Form is subject to the terms of the Mozilla Public License,
- * v. 2.0. If a copy of the MPL was not distributed with this file, You can
- * obtain one at https://mozilla.org/MPL/2.0/.
- */
-
-package de.justjanne.libquassel.protocol.session
-
-import de.justjanne.libquassel.protocol.util.log.info
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.asCoroutineDispatcher
-import kotlinx.coroutines.cancel
-import kotlinx.coroutines.cancelAndJoin
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.runBlocking
-import org.slf4j.LoggerFactory
-import java.io.Closeable
-import java.nio.channels.ClosedChannelException
-import java.util.concurrent.Executors
-
-class MessageChannelReader(
-  private val channel: MessageChannel,
-) : Closeable {
-  private val executor = Executors.newSingleThreadExecutor()
-  private val dispatcher = executor.asCoroutineDispatcher()
-  private val scope = CoroutineScope(dispatcher)
-  private var job: Job? = null
-
-  fun start() {
-    job =
-      scope.launch {
-        try {
-          channel.init()
-          while (isActive && channel.channel.state().connected) {
-            channel.read()
-          }
-        } catch (e: ClosedChannelException) {
-          logger.info { "Channel closed" }
-          close()
-        }
-      }
-  }
-
-  override fun close() {
-    channel.close()
-    runBlocking { job?.cancelAndJoin() }
-    scope.cancel()
-    dispatcher.cancel()
-    executor.shutdown()
-  }
-
-  companion object {
-    private val logger = LoggerFactory.getLogger(MessageChannelReader::class.java)
-  }
-}
diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/ProxyMessageHandler.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/ProxyMessageHandler.kt
deleted file mode 100644
index 9854bd28f0db0d4b1b74f24e5e40fcb816209475..0000000000000000000000000000000000000000
--- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/session/ProxyMessageHandler.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * libquassel
- * Copyright (c) 2021 Janne Mareike Koschinski
- *
- * This Source Code Form is subject to the terms of the Mozilla Public License,
- * v. 2.0. If a copy of the MPL was not distributed with this file, You can
- * obtain one at https://mozilla.org/MPL/2.0/.
- */
-
-package de.justjanne.libquassel.protocol.session
-
-import de.justjanne.libquassel.protocol.models.SignalProxyMessage
-
-interface ProxyMessageHandler : ConnectionHandler {
-  suspend fun emit(message: SignalProxyMessage)
-
-  suspend fun dispatch(message: SignalProxyMessage)
-}