mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-30 13:47:41 +00:00
feat(sftp): notify MediaStore on file changes
This commit adds functionality to notify the MediaStore when files are modified via SFTP. This ensures that changes made through SFTP are reflected in the Android media library. Specifically, the MediaStore is notified after file creation, deletion, copying, renaming, and link creation. Additionally, it is notified after closing a file that was opened for writing. This ensures that the MediaStore is kept up-to-date with any changes made to files through SFTP.
This commit is contained in:
parent
167e2c7176
commit
df0f2d651c
@ -7,6 +7,7 @@
|
||||
package org.kde.kdeconnect.Plugins.SftpPlugin
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import org.apache.sshd.common.file.nativefs.NativeFileSystemFactory
|
||||
@ -26,6 +27,7 @@ import org.apache.sshd.sftp.server.SftpFileSystemAccessor
|
||||
import org.apache.sshd.sftp.server.SftpSubsystemFactory
|
||||
import org.apache.sshd.sftp.server.SftpSubsystemProxy
|
||||
import org.kde.kdeconnect.Device
|
||||
import org.kde.kdeconnect.Helpers.MediaStoreHelper
|
||||
import org.kde.kdeconnect.Helpers.RandomHelper
|
||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.RsaHelper
|
||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.constantTimeCompare
|
||||
@ -33,10 +35,13 @@ import org.kde.kdeconnect.Plugins.SftpPlugin.saf.SafFileSystemFactory
|
||||
import org.kde.kdeconnect.Plugins.SftpPlugin.saf.SafPath
|
||||
import org.slf4j.impl.HandroidLoggerAdapter
|
||||
import java.io.IOException
|
||||
import java.nio.channels.Channel
|
||||
import java.nio.channels.SeekableByteChannel
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.CopyOption
|
||||
import java.nio.file.OpenOption
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.StandardOpenOption
|
||||
import java.nio.file.attribute.FileAttribute
|
||||
import java.security.GeneralSecurityException
|
||||
import java.security.KeyPair
|
||||
@ -103,6 +108,17 @@ internal class SimpleSftpServer {
|
||||
sshd.subsystemFactories =
|
||||
listOf<SubsystemFactory>(SftpSubsystemFactory.Builder().apply {
|
||||
withFileSystemAccessor(object : SftpFileSystemAccessor {
|
||||
fun notifyMediaStore(path: Path) {
|
||||
kotlin.runCatching {
|
||||
val uri = Uri.parse(path.toUri().toString())
|
||||
MediaStoreHelper.indexFile(context, uri)
|
||||
uri
|
||||
}.fold(
|
||||
onSuccess = { Log.i(TAG, "Notified media store: $path, $it") },
|
||||
onFailure = { Log.w(TAG, "Failed to notify media store: $path", it) }
|
||||
)
|
||||
}
|
||||
|
||||
override fun openFile(
|
||||
subsystem: SftpSubsystemProxy?,
|
||||
fileHandle: FileHandle?,
|
||||
@ -116,6 +132,61 @@ internal class SimpleSftpServer {
|
||||
}
|
||||
return super.openFile(subsystem, fileHandle, file, handle, options, *attrs)
|
||||
}
|
||||
|
||||
override fun removeFile(
|
||||
subsystem: SftpSubsystemProxy?,
|
||||
path: Path?,
|
||||
isDirectory: Boolean
|
||||
) {
|
||||
super.removeFile(subsystem, path, isDirectory)
|
||||
path?.let { notifyMediaStore(it) }
|
||||
}
|
||||
|
||||
override fun copyFile(
|
||||
subsystem: SftpSubsystemProxy?,
|
||||
src: Path?,
|
||||
dst: Path?,
|
||||
opts: MutableCollection<CopyOption>?
|
||||
) {
|
||||
super.copyFile(subsystem, src, dst, opts)
|
||||
dst?.let { notifyMediaStore(it) }
|
||||
}
|
||||
|
||||
override fun renameFile(
|
||||
subsystem: SftpSubsystemProxy?,
|
||||
oldPath: Path?,
|
||||
newPath: Path?,
|
||||
opts: MutableCollection<CopyOption>?
|
||||
) {
|
||||
super.renameFile(subsystem, oldPath, newPath, opts)
|
||||
oldPath?.let { notifyMediaStore(it) }
|
||||
newPath?.let { notifyMediaStore(it) }
|
||||
}
|
||||
|
||||
override fun createLink(
|
||||
subsystem: SftpSubsystemProxy?,
|
||||
link: Path?,
|
||||
existing: Path?,
|
||||
symLink: Boolean
|
||||
) {
|
||||
super.createLink(subsystem, link, existing, symLink)
|
||||
link?.let { notifyMediaStore(it) }
|
||||
existing?.let { notifyMediaStore(it) }
|
||||
}
|
||||
|
||||
override fun closeFile(
|
||||
subsystem: SftpSubsystemProxy?,
|
||||
fileHandle: FileHandle?,
|
||||
file: Path?,
|
||||
handle: String?,
|
||||
channel: Channel?,
|
||||
options: MutableSet<out OpenOption>?
|
||||
) {
|
||||
super.closeFile(subsystem, fileHandle, file, handle, channel, options)
|
||||
if (options?.contains(StandardOpenOption.WRITE) == true) {
|
||||
file?.let { notifyMediaStore(it) }
|
||||
}
|
||||
}
|
||||
})
|
||||
}.build())
|
||||
|
||||
@ -189,8 +260,9 @@ internal class SimpleSftpServer {
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val PORT_RANGE = 1739..1764
|
||||
private const val TAG = "SimpleSftpServer"
|
||||
|
||||
private val PORT_RANGE = 1739..1764
|
||||
const val USER: String = "kdeconnect"
|
||||
|
||||
init {
|
||||
|
@ -98,7 +98,6 @@ class SafFileSystemProvider(
|
||||
val docFile = parent.createFile(Files.probeContentType(path), path.names.last())
|
||||
?: throw IOException("Failed to create $path")
|
||||
val uri = docFile.uri
|
||||
MediaStoreHelper.indexFile(context, uri)
|
||||
path.safUri = uri
|
||||
return uri
|
||||
}
|
||||
@ -226,7 +225,6 @@ class SafFileSystemProvider(
|
||||
if (!docFile.delete()) {
|
||||
throw IOException("Failed to delete $path")
|
||||
}
|
||||
MediaStoreHelper.indexFile(context, docFile.uri)
|
||||
}
|
||||
|
||||
override fun copy(source: Path, target: Path, vararg options: CopyOption) {
|
||||
@ -272,8 +270,6 @@ class SafFileSystemProvider(
|
||||
if (newUri == null) { // renameDocument returns null on failure
|
||||
return@firstStep
|
||||
}
|
||||
MediaStoreHelper.indexFile(context, sourceUri)
|
||||
MediaStoreHelper.indexFile(context, newUri)
|
||||
source.safUri = newUri
|
||||
return
|
||||
} catch (ignored: FileNotFoundException) {
|
||||
@ -295,8 +291,6 @@ class SafFileSystemProvider(
|
||||
parentUri,
|
||||
destParentUri
|
||||
)
|
||||
MediaStoreHelper.indexFile(context, sourceUri)
|
||||
MediaStoreHelper.indexFile(context, newUri)
|
||||
source.safUri = newUri!!
|
||||
return
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ package org.kde.kdeconnect.Plugins.SftpPlugin.saf
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import org.apache.sshd.common.file.util.BasePath
|
||||
import java.net.URI
|
||||
import java.nio.file.LinkOption
|
||||
|
||||
class SafPath(
|
||||
@ -21,6 +21,10 @@ class SafPath(
|
||||
return this.normalize()
|
||||
}
|
||||
|
||||
override fun toUri(): URI {
|
||||
return URI.create(safUri.toString()) ?: throw IllegalStateException("SafUri is null")
|
||||
}
|
||||
|
||||
fun getDocumentFile(ctx: Context): DocumentFile? {
|
||||
if (safUri == null) return null
|
||||
return DocumentFile.fromTreeUri(ctx, safUri!!)
|
||||
|
Loading…
x
Reference in New Issue
Block a user