fixed downloading galleris with long title, [wip] transfer data
This commit is contained in:
@@ -343,7 +343,7 @@ class DownloadService : Service() {
|
||||
return@launch
|
||||
}
|
||||
|
||||
notification[galleryID]?.setContentTitle(galleryInfo.title?.ellipsize(30))
|
||||
notification[galleryID]?.setContentTitle(galleryInfo.title.ellipsize(32))
|
||||
notify(galleryID)
|
||||
|
||||
val queued = mutableSetOf<Int>()
|
||||
@@ -408,7 +408,7 @@ class DownloadService : Service() {
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
|
||||
startForeground(R.id.downloader_notification_id, serviceNotification.build())
|
||||
} else {
|
||||
startForeground(R.id.downloader_notification_id, serviceNotification.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE)
|
||||
startForeground(R.id.downloader_notification_id, serviceNotification.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC)
|
||||
}
|
||||
|
||||
when (intent?.getStringExtra(KEY_COMMAND)) {
|
||||
@@ -433,7 +433,7 @@ class DownloadService : Service() {
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
|
||||
startForeground(R.id.downloader_notification_id, serviceNotification.build())
|
||||
} else {
|
||||
startForeground(R.id.downloader_notification_id, serviceNotification.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE)
|
||||
startForeground(R.id.downloader_notification_id, serviceNotification.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC)
|
||||
}
|
||||
interceptors[Tag::class] = interceptor
|
||||
}
|
||||
|
||||
@@ -12,18 +12,21 @@ import io.ktor.network.selector.SelectorManager
|
||||
import io.ktor.network.sockets.aSocket
|
||||
import io.ktor.network.sockets.openReadChannel
|
||||
import io.ktor.network.sockets.openWriteChannel
|
||||
import io.ktor.utils.io.writeStringUtf8
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.trySendBlocking
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import xyz.quaver.pupil.R
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
class TransferClientService : Service() {
|
||||
private val selectorManager = SelectorManager(Dispatchers.IO)
|
||||
private val channel = Channel<String>()
|
||||
private val channel = Channel<Pair<TransferPacket, Continuation<TransferPacket>>>()
|
||||
private var job: Job? = null
|
||||
|
||||
private fun startForeground() = runCatching {
|
||||
@@ -64,13 +67,28 @@ class TransferClientService : Service() {
|
||||
val writeChannel = socket.openWriteChannel(autoFlush = true)
|
||||
|
||||
runCatching {
|
||||
TransferPacket.Hello().writeToChannel(writeChannel)
|
||||
val handshake = TransferPacket.readFromChannel(readChannel)
|
||||
|
||||
if (handshake !is TransferPacket.Hello || handshake.version != TRANSFER_PROTOCOL_VERSION) {
|
||||
throw IllegalStateException("Invalid handshake")
|
||||
}
|
||||
|
||||
while (true) {
|
||||
val message = channel.receive()
|
||||
Log.d("PUPILD", "Sending message $message!")
|
||||
writeChannel.writeStringUtf8(message)
|
||||
Log.d("PUPILD", readChannel.readUTF8Line(4).toString())
|
||||
val (packet, continuation) = channel.receive()
|
||||
|
||||
Log.d("PUPILD", "Sending packet $packet")
|
||||
|
||||
packet.writeToChannel(writeChannel)
|
||||
|
||||
val response = TransferPacket.readFromChannel(readChannel).also {
|
||||
Log.d("PUPILD", "Received packet $it")
|
||||
}
|
||||
|
||||
continuation.resume(response)
|
||||
}
|
||||
}.onFailure {
|
||||
Log.d("PUPILD", "Connection closed with error $it")
|
||||
socket.close()
|
||||
stopSelf(startId)
|
||||
}
|
||||
@@ -85,9 +103,14 @@ class TransferClientService : Service() {
|
||||
}
|
||||
|
||||
inner class Binder: android.os.Binder() {
|
||||
fun sendMessage(message: String) {
|
||||
Log.d("PUPILD", "Sending message $message")
|
||||
channel.trySendBlocking(message + '\n')
|
||||
|
||||
|
||||
suspend fun sendPacket(packet: TransferPacket): Result<TransferPacket.ListResponse> = runCatching {
|
||||
val response = withTimeout(1000) { suspendCoroutine { continuation ->
|
||||
channel.trySendBlocking(packet to continuation)
|
||||
} }
|
||||
|
||||
response as? TransferPacket.ListResponse ?: throw IllegalStateException("Invalid response")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package xyz.quaver.pupil.services
|
||||
|
||||
import io.ktor.utils.io.ByteReadChannel
|
||||
import io.ktor.utils.io.ByteWriteChannel
|
||||
|
||||
const val TRANSFER_PROTOCOL_VERSION: UByte = 1u
|
||||
|
||||
enum class TransferType(val value: UByte) {
|
||||
INVALID(255u),
|
||||
HELLO(0u),
|
||||
PING(1u),
|
||||
PONG(2u),
|
||||
LIST_REQUEST(3u),
|
||||
LIST_RESPONSE(4u),
|
||||
}
|
||||
|
||||
sealed interface TransferPacket {
|
||||
val type: TransferType
|
||||
|
||||
suspend fun writeToChannel(channel: ByteWriteChannel)
|
||||
|
||||
data class Hello(val version: UByte = TRANSFER_PROTOCOL_VERSION): TransferPacket {
|
||||
override val type = TransferType.HELLO
|
||||
|
||||
override suspend fun writeToChannel(channel: ByteWriteChannel) {
|
||||
channel.writeByte(type.value.toByte())
|
||||
channel.writeByte(version.toByte())
|
||||
}
|
||||
}
|
||||
|
||||
data object Ping: TransferPacket {
|
||||
override val type = TransferType.PING
|
||||
override suspend fun writeToChannel(channel: ByteWriteChannel) {
|
||||
channel.writeByte(type.value.toByte())
|
||||
}
|
||||
}
|
||||
|
||||
data object Pong: TransferPacket {
|
||||
override val type = TransferType.PONG
|
||||
override suspend fun writeToChannel(channel: ByteWriteChannel) {
|
||||
channel.writeByte(type.value.toByte())
|
||||
}
|
||||
}
|
||||
|
||||
data object ListRequest: TransferPacket {
|
||||
override val type = TransferType.LIST_REQUEST
|
||||
override suspend fun writeToChannel(channel: ByteWriteChannel) {
|
||||
channel.writeByte(type.value.toByte())
|
||||
}
|
||||
}
|
||||
|
||||
data object Invalid: TransferPacket {
|
||||
override val type = TransferType.INVALID
|
||||
override suspend fun writeToChannel(channel: ByteWriteChannel) {
|
||||
channel.writeByte(type.value.toByte())
|
||||
}
|
||||
}
|
||||
|
||||
data class ListResponse(
|
||||
val favoritesCount: Int,
|
||||
val historyCount: Int,
|
||||
val downloadsCount: Int,
|
||||
): TransferPacket {
|
||||
override val type = TransferType.LIST_RESPONSE
|
||||
|
||||
override suspend fun writeToChannel(channel: ByteWriteChannel) {
|
||||
channel.writeByte(type.value.toByte())
|
||||
channel.writeInt(favoritesCount)
|
||||
channel.writeInt(historyCount)
|
||||
channel.writeInt(downloadsCount)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
suspend fun readFromChannel(channel: ByteReadChannel): TransferPacket {
|
||||
return when(val type = channel.readByte().toUByte()) {
|
||||
TransferType.HELLO.value -> {
|
||||
val version = channel.readByte().toUByte()
|
||||
Hello(version)
|
||||
}
|
||||
TransferType.PING.value -> Ping
|
||||
TransferType.PONG.value -> Pong
|
||||
TransferType.LIST_REQUEST.value -> ListRequest
|
||||
TransferType.LIST_RESPONSE.value -> {
|
||||
val favoritesCount = channel.readInt()
|
||||
val historyCount = channel.readInt()
|
||||
val downloadsCount = channel.readInt()
|
||||
ListResponse(favoritesCount, historyCount, downloadsCount)
|
||||
}
|
||||
else -> throw IllegalArgumentException("Unknown packet type: $type")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,12 +14,15 @@ import io.ktor.network.sockets.Socket
|
||||
import io.ktor.network.sockets.aSocket
|
||||
import io.ktor.network.sockets.openReadChannel
|
||||
import io.ktor.network.sockets.openWriteChannel
|
||||
import io.ktor.utils.io.writeStringUtf8
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.launch
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.favorites
|
||||
import xyz.quaver.pupil.histories
|
||||
import xyz.quaver.pupil.util.downloader.DownloadManager
|
||||
|
||||
class TransferServerService : Service() {
|
||||
private val selectorManager = SelectorManager(Dispatchers.IO)
|
||||
@@ -43,15 +46,33 @@ class TransferServerService : Service() {
|
||||
)
|
||||
}
|
||||
|
||||
private fun generateListResponse(): TransferPacket.ListResponse {
|
||||
val favoritesCount = favorites.size
|
||||
val historyCount = histories.size
|
||||
val downloadsCount = DownloadManager.getInstance(this).downloadFolderMap.size
|
||||
return TransferPacket.ListResponse(favoritesCount, historyCount, downloadsCount)
|
||||
}
|
||||
|
||||
private suspend fun handleConnection(socket: Socket) {
|
||||
val readChannel = socket.openReadChannel()
|
||||
val writeChannel = socket.openWriteChannel(autoFlush = true)
|
||||
|
||||
runCatching {
|
||||
while (true) {
|
||||
if (readChannel.readUTF8Line(8) == "ping") {
|
||||
writeChannel.writeStringUtf8("pong\n")
|
||||
val packet = TransferPacket.readFromChannel(readChannel)
|
||||
|
||||
Log.d("PUPILD", "Received packet $packet")
|
||||
|
||||
binder.channel.trySend(packet)
|
||||
|
||||
val response = when (packet) {
|
||||
is TransferPacket.Hello -> TransferPacket.Hello()
|
||||
is TransferPacket.Ping -> TransferPacket.Pong
|
||||
is TransferPacket.ListRequest -> generateListResponse()
|
||||
else -> TransferPacket.Invalid
|
||||
}
|
||||
|
||||
response.writeToChannel(writeChannel)
|
||||
}
|
||||
}.onFailure {
|
||||
socket.close()
|
||||
@@ -93,7 +114,7 @@ class TransferServerService : Service() {
|
||||
}
|
||||
|
||||
inner class Binder: android.os.Binder() {
|
||||
fun getService() = this@TransferServerService
|
||||
val channel = Channel<TransferPacket>()
|
||||
}
|
||||
|
||||
private val binder = Binder()
|
||||
|
||||
Reference in New Issue
Block a user