multiplatform: default files and directories were changed (#2683)

* multiplatform: default files and directories were changed

* changes in paths and location of declaration

* more renames

* different paths

* update linux paths

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
This commit is contained in:
Stanislav Dmitrenko 2023-07-14 14:00:37 +03:00 committed by GitHub
parent 0bdd96ae8a
commit 8dd90733b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 61 additions and 56 deletions

View File

@ -36,6 +36,7 @@ class SimplexApp: Application(), LifecycleEventObserver {
initHaskell() initHaskell()
initMultiplatform() initMultiplatform()
tmpDir.deleteRecursively() tmpDir.deleteRecursively()
withBGApi { withBGApi {
initChatController() initChatController()
runMigrations() runMigrations()

View File

@ -13,7 +13,13 @@ import java.net.URI
actual val dataDir: File = androidAppContext.dataDir actual val dataDir: File = androidAppContext.dataDir
actual val tmpDir: File = androidAppContext.getDir("temp", Application.MODE_PRIVATE) actual val tmpDir: File = androidAppContext.getDir("temp", Application.MODE_PRIVATE)
actual val cacheDir: File = androidAppContext.cacheDir actual val filesDir: File = File(dataDir.absolutePath + File.separator + "files")
actual val appFilesDir: File = File(filesDir.absolutePath + File.separator + "app_files")
actual val coreTmpDir: File = File(filesDir.absolutePath + File.separator + "temp_files")
actual val dbAbsolutePrefixPath: String = dataDir.absolutePath + File.separator + "files"
actual val chatDatabaseFileName: String = "files_chat.db"
actual val agentDatabaseFileName: String = "files_agent.db"
@Composable @Composable
actual fun rememberFileChooserLauncher(getContent: Boolean, onResult: (URI?) -> Unit): FileChooserLauncher { actual fun rememberFileChooserLauncher(getContent: Boolean, onResult: (URI?) -> Unit): FileChooserLauncher {

View File

@ -43,7 +43,7 @@ val errorBitmap: Bitmap = BitmapFactory.decodeByteArray(errorBitmapBytes, 0, err
class CustomTakePicturePreview(var uri: Uri?, var tmpFile: File?): ActivityResultContract<Void?, Uri?>() { class CustomTakePicturePreview(var uri: Uri?, var tmpFile: File?): ActivityResultContract<Void?, Uri?>() {
@CallSuper @CallSuper
override fun createIntent(context: Context, input: Void?): Intent { override fun createIntent(context: Context, input: Void?): Intent {
tmpFile = File.createTempFile("image", ".bmp", File(getAppFilesDirectory())) tmpFile = File.createTempFile("image", ".bmp", appFilesDir)
// Since the class should return Uri, the file should be deleted somewhere else. And in order to be sure, delegate this to system // Since the class should return Uri, the file should be deleted somewhere else. And in order to be sure, delegate this to system
tmpFile?.deleteOnExit() tmpFile?.deleteOnExit()
uri = FileProvider.getUriForFile(context, "$APPLICATION_ID.provider", tmpFile!!) uri = FileProvider.getUriForFile(context, "$APPLICATION_ID.provider", tmpFile!!)

View File

@ -277,7 +277,7 @@ actual fun getDrawableFromUri(uri: URI, withAlertOnException: Boolean): Any? {
actual suspend fun saveTempImageUncompressed(image: ImageBitmap, asPng: Boolean): File? { actual suspend fun saveTempImageUncompressed(image: ImageBitmap, asPng: Boolean): File? {
return try { return try {
val ext = if (asPng) "png" else "jpg" val ext = if (asPng) "png" else "jpg"
return File(getTempFilesDirectory() + File.separator + generateNewFileName("IMG", ext)).apply { return File(tmpDir.absolutePath + File.separator + generateNewFileName("IMG", ext)).apply {
outputStream().use { out -> outputStream().use { out ->
image.asAndroidBitmap().compress(if (asPng) Bitmap.CompressFormat.PNG else Bitmap.CompressFormat.JPEG, 85, out) image.asAndroidBitmap().compress(if (asPng) Bitmap.CompressFormat.PNG else Bitmap.CompressFormat.JPEG, 85, out)
out.flush() out.flush()

View File

@ -319,8 +319,8 @@ object ChatController {
try { try {
if (chatModel.chatRunning.value == true) return if (chatModel.chatRunning.value == true) return
apiSetNetworkConfig(getNetCfg()) apiSetNetworkConfig(getNetCfg())
apiSetTempFolder(getTempFilesDirectory()) apiSetTempFolder(coreTmpDir.absolutePath)
apiSetFilesFolder(getAppFilesDirectory()) apiSetFilesFolder(appFilesDir.absolutePath)
apiSetXFTPConfig(getXFTPCfg()) apiSetXFTPConfig(getXFTPCfg())
val justStarted = apiStartChat() val justStarted = apiStartChat()
val users = listUsers() val users = listUsers()

View File

@ -30,9 +30,8 @@ val chatController: ChatController = ChatController
suspend fun initChatController(useKey: String? = null, confirmMigrations: MigrationConfirmation? = null, startChat: Boolean = true) { suspend fun initChatController(useKey: String? = null, confirmMigrations: MigrationConfirmation? = null, startChat: Boolean = true) {
val dbKey = useKey ?: DatabaseUtils.useDatabaseKey() val dbKey = useKey ?: DatabaseUtils.useDatabaseKey()
val dbAbsolutePathPrefix = getFilesDirectory()
val confirm = confirmMigrations ?: if (appPreferences.confirmDBUpgrades.get()) MigrationConfirmation.Error else MigrationConfirmation.YesUp val confirm = confirmMigrations ?: if (appPreferences.confirmDBUpgrades.get()) MigrationConfirmation.Error else MigrationConfirmation.YesUp
val migrated: Array<Any> = chatMigrateInit(dbAbsolutePathPrefix, dbKey, confirm.value) val migrated: Array<Any> = chatMigrateInit(dbAbsolutePrefixPath, dbKey, confirm.value)
val res: DBMigrationResult = kotlin.runCatching { val res: DBMigrationResult = kotlin.runCatching {
json.decodeFromString<DBMigrationResult>(migrated[0] as String) json.decodeFromString<DBMigrationResult>(migrated[0] as String)
}.getOrElse { DBMigrationResult.Unknown(migrated[0] as String) } }.getOrElse { DBMigrationResult.Unknown(migrated[0] as String) }

View File

@ -9,7 +9,13 @@ import java.net.URI
expect val dataDir: File expect val dataDir: File
expect val tmpDir: File expect val tmpDir: File
expect val cacheDir: File expect val filesDir: File
expect val appFilesDir: File
expect val coreTmpDir: File
expect val dbAbsolutePrefixPath: String
expect val chatDatabaseFileName: String
expect val agentDatabaseFileName: String
fun copyFileToFile(from: File, to: URI, finally: () -> Unit) { fun copyFileToFile(from: File, to: URI, finally: () -> Unit) {
try { try {
@ -43,21 +49,8 @@ fun copyBytesToFile(bytes: ByteArrayInputStream, to: URI, finally: () -> Unit) {
} }
} }
fun getFilesDirectory(): String {
return dataDir.absolutePath + File.separator + "files"
}
// LALAL
fun getTempFilesDirectory(): String {
return getFilesDirectory() + File.separator + "temp_files"
}
fun getAppFilesDirectory(): String {
return getFilesDirectory() + File.separator + "app_files"
}
fun getAppFilePath(fileName: String): String { fun getAppFilePath(fileName: String): String {
return getAppFilesDirectory() + File.separator + fileName return appFilesDir.absolutePath + File.separator + fileName
} }
fun getLoadedFilePath(file: CIFile?): String? { fun getLoadedFilePath(file: CIFile?): String? {

View File

@ -25,7 +25,7 @@ import java.util.*
@Composable @Composable
fun ChatArchiveView(m: ChatModel, title: String, archiveName: String, archiveTime: Instant) { fun ChatArchiveView(m: ChatModel, title: String, archiveName: String, archiveTime: Instant) {
val archivePath = getFilesDirectory() + File.separator + archiveName val archivePath = filesDir.absolutePath + File.separator + archiveName
val saveArchiveLauncher = rememberFileChooserLauncher(false) { to: URI? -> val saveArchiveLauncher = rememberFileChooserLauncher(false) { to: URI? ->
if (to != null) { if (to != null) {
copyFileToFile(File(archivePath), to) {} copyFileToFile(File(archivePath), to) {}

View File

@ -221,9 +221,8 @@ private fun shouldShowRestoreDbButton(prefs: AppPreferences): Boolean {
val startedAt = prefs.encryptionStartedAt.get() ?: return false val startedAt = prefs.encryptionStartedAt.get() ?: return false
/** Just in case there is any small difference between reported Java's [Clock.System.now] and Linux's time on a file */ /** Just in case there is any small difference between reported Java's [Clock.System.now] and Linux's time on a file */
val safeDiffInTime = 10_000L val safeDiffInTime = 10_000L
// LALAL CHANGE FILENAME val filesChat = File(dataDir.absolutePath + File.separator + "${chatDatabaseFileName}.bak")
val filesChat = File(dataDir.absolutePath + File.separator + "files_chat.db.bak") val filesAgent = File(dataDir.absolutePath + File.separator + "${agentDatabaseFileName}.bak")
val filesAgent = File(dataDir.absolutePath + File.separator + "files_agent.db.bak")
return filesChat.exists() && return filesChat.exists() &&
filesAgent.exists() && filesAgent.exists() &&
startedAt.toEpochMilliseconds() - safeDiffInTime <= filesChat.lastModified() && startedAt.toEpochMilliseconds() - safeDiffInTime <= filesChat.lastModified() &&
@ -231,9 +230,8 @@ private fun shouldShowRestoreDbButton(prefs: AppPreferences): Boolean {
} }
private fun restoreDb(restoreDbFromBackup: MutableState<Boolean>, prefs: AppPreferences) { private fun restoreDb(restoreDbFromBackup: MutableState<Boolean>, prefs: AppPreferences) {
// LALAL CHANGE FILENAME val filesChatBase = dataDir.absolutePath + File.separator + chatDatabaseFileName
val filesChatBase = dataDir.absolutePath + File.separator + "files_chat.db" val filesAgentBase = dataDir.absolutePath + File.separator + agentDatabaseFileName
val filesAgentBase = dataDir.absolutePath + File.separator + "files_agent.db"
try { try {
Files.copy(Path("$filesChatBase.bak"), Path(filesChatBase), StandardCopyOption.REPLACE_EXISTING) Files.copy(Path("$filesChatBase.bak"), Path(filesChatBase), StandardCopyOption.REPLACE_EXISTING)
Files.copy(Path("$filesAgentBase.bak"), Path(filesAgentBase), StandardCopyOption.REPLACE_EXISTING) Files.copy(Path("$filesAgentBase.bak"), Path(filesAgentBase), StandardCopyOption.REPLACE_EXISTING)

View File

@ -54,7 +54,7 @@ fun DatabaseView(
} }
} }
} }
val appFilesCountAndSize = remember { mutableStateOf(directoryFileCountAndSize(getAppFilesDirectory())) } val appFilesCountAndSize = remember { mutableStateOf(directoryFileCountAndSize(appFilesDir.absolutePath)) }
val importArchiveLauncher = rememberFileChooserLauncher(true) { to: URI? -> val importArchiveLauncher = rememberFileChooserLauncher(true) { to: URI? ->
if (to != null) { if (to != null) {
importArchiveAlert(m, to, appFilesCountAndSize, progressIndicator) importArchiveAlert(m, to, appFilesCountAndSize, progressIndicator)
@ -475,8 +475,8 @@ private suspend fun exportChatArchive(
val archiveTime = Clock.System.now() val archiveTime = Clock.System.now()
val ts = SimpleDateFormat("yyyy-MM-dd'T'HHmmss", Locale.US).format(Date.from(archiveTime.toJavaInstant())) val ts = SimpleDateFormat("yyyy-MM-dd'T'HHmmss", Locale.US).format(Date.from(archiveTime.toJavaInstant()))
val archiveName = "simplex-chat.$ts.zip" val archiveName = "simplex-chat.$ts.zip"
val archivePath = "${getFilesDirectory()}${File.separator}$archiveName" val archivePath = "${filesDir.absolutePath}${File.separator}$archiveName"
val config = ArchiveConfig(archivePath, parentTempDirectory = cacheDir.toString()) val config = ArchiveConfig(archivePath, parentTempDirectory = tmpDir.toString())
m.controller.apiExportArchive(config) m.controller.apiExportArchive(config)
deleteOldArchive(m) deleteOldArchive(m)
m.controller.appPrefs.chatArchiveName.set(archiveName) m.controller.appPrefs.chatArchiveName.set(archiveName)
@ -490,7 +490,7 @@ private suspend fun exportChatArchive(
private fun deleteOldArchive(m: ChatModel) { private fun deleteOldArchive(m: ChatModel) {
val chatArchiveName = m.controller.appPrefs.chatArchiveName.get() val chatArchiveName = m.controller.appPrefs.chatArchiveName.get()
if (chatArchiveName != null) { if (chatArchiveName != null) {
val file = File("${getFilesDirectory()}${File.separator}$chatArchiveName") val file = File("${filesDir.absolutePath}${File.separator}$chatArchiveName")
val fileDeleted = file.delete() val fileDeleted = file.delete()
if (fileDeleted) { if (fileDeleted) {
m.controller.appPrefs.chatArchiveName.set(null) m.controller.appPrefs.chatArchiveName.set(null)
@ -529,10 +529,10 @@ private fun importArchive(
try { try {
m.controller.apiDeleteStorage() m.controller.apiDeleteStorage()
try { try {
val config = ArchiveConfig(archivePath, parentTempDirectory = cacheDir.toString()) val config = ArchiveConfig(archivePath, parentTempDirectory = tmpDir.toString())
val archiveErrors = m.controller.apiImportArchive(config) val archiveErrors = m.controller.apiImportArchive(config)
DatabaseUtils.ksDatabasePassword.remove() DatabaseUtils.ksDatabasePassword.remove()
appFilesCountAndSize.value = directoryFileCountAndSize(getAppFilesDirectory()) appFilesCountAndSize.value = directoryFileCountAndSize(appFilesDir.absolutePath)
if (archiveErrors.isEmpty()) { if (archiveErrors.isEmpty()) {
operationEnded(m, progressIndicator) { operationEnded(m, progressIndicator) {
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.chat_database_imported), text = generalGetString(MR.strings.restart_the_app_to_use_imported_chat_database)) AlertManager.shared.showAlertMsg(generalGetString(MR.strings.chat_database_imported), text = generalGetString(MR.strings.restart_the_app_to_use_imported_chat_database))
@ -563,7 +563,7 @@ private fun saveArchiveFromURI(importedArchiveURI: URI): String? {
val inputStream = importedArchiveURI.inputStream() val inputStream = importedArchiveURI.inputStream()
val archiveName = getFileName(importedArchiveURI) val archiveName = getFileName(importedArchiveURI)
if (inputStream != null && archiveName != null) { if (inputStream != null && archiveName != null) {
val archivePath = "$cacheDir${File.separator}$archiveName" val archivePath = "$tmpDir${File.separator}$archiveName"
val destFile = File(archivePath) val destFile = File(archivePath)
Files.copy(inputStream, destFile.toPath()) Files.copy(inputStream, destFile.toPath())
archivePath archivePath
@ -632,7 +632,7 @@ private fun afterSetCiTTL(
appFilesCountAndSize: MutableState<Pair<Int, Long>>, appFilesCountAndSize: MutableState<Pair<Int, Long>>,
) { ) {
progressIndicator.value = false progressIndicator.value = false
appFilesCountAndSize.value = directoryFileCountAndSize(getAppFilesDirectory()) appFilesCountAndSize.value = directoryFileCountAndSize(appFilesDir.absolutePath)
withApi { withApi {
try { try {
val chats = m.controller.apiGetChats() val chats = m.controller.apiGetChats()
@ -655,7 +655,7 @@ private fun deleteFilesAndMediaAlert(appFilesCountAndSize: MutableState<Pair<Int
private fun deleteFiles(appFilesCountAndSize: MutableState<Pair<Int, Long>>) { private fun deleteFiles(appFilesCountAndSize: MutableState<Pair<Int, Long>>) {
deleteAppFiles() deleteAppFiles()
appFilesCountAndSize.value = directoryFileCountAndSize(getAppFilesDirectory()) appFilesCountAndSize.value = directoryFileCountAndSize(appFilesDir.absolutePath)
} }
private fun operationEnded(m: ChatModel, progressIndicator: MutableState<Boolean>, alert: () -> Unit) { private fun operationEnded(m: ChatModel, progressIndicator: MutableState<Boolean>, alert: () -> Unit) {

View File

@ -39,9 +39,8 @@ object DatabaseUtils {
} }
} }
// LALAL CHANGE DB FILE NAME ON DESKTOP
private fun hasDatabase(rootDir: String): Boolean = private fun hasDatabase(rootDir: String): Boolean =
File(rootDir + File.separator + "files_chat.db").exists() && File(rootDir + File.separator + "files_agent.db").exists() File(rootDir + File.separator + chatDatabaseFileName).exists() && File(rootDir + File.separator + agentDatabaseFileName).exists()
fun useDatabaseKey(): String { fun useDatabaseKey(): String {
Log.d(TAG, "useDatabaseKey ${appPreferences.storeDBPassphrase.get()}") Log.d(TAG, "useDatabaseKey ${appPreferences.storeDBPassphrase.get()}")

View File

@ -209,7 +209,7 @@ fun removeFile(fileName: String): Boolean {
} }
fun deleteAppFiles() { fun deleteAppFiles() {
val dir = File(getAppFilesDirectory()) val dir = appFilesDir
try { try {
dir.list()?.forEach { dir.list()?.forEach {
removeFile(it) removeFile(it)

View File

@ -43,10 +43,10 @@ private fun applyAppLocale() {
@Suppress("UnsafeDynamicallyLoadedCode") @Suppress("UnsafeDynamicallyLoadedCode")
actual fun initHaskell() { actual fun initHaskell() {
val libApp = "libapp-lib.${desktopPlatform.libExtension}" val libApp = "libapp-lib.${desktopPlatform.libExtension}"
val tmpDir = Files.createTempDirectory("simplex-native-libs").toFile() val libsTmpDir = File(tmpDir.absolutePath + File.separator + "libs")
tmpDir.deleteOnExit() copyResources(desktopPlatform.libPath, libsTmpDir.toPath())
copyResources(desktopPlatform.libPath, tmpDir.toPath()) System.load(File(libsTmpDir, libApp).absolutePath)
System.load(File(tmpDir, libApp).absolutePath) libsTmpDir.deleteRecursively()
initHS() initHS()
} }

View File

@ -15,9 +15,15 @@ private fun applicationParentPath(): String = try {
"./" "./"
} }
actual val dataDir: File = File(desktopPlatform.configPath) actual val dataDir: File = File(desktopPlatform.dataPath)
actual val tmpDir: File = File(System.getProperty("java.io.tmpdir")) actual val tmpDir: File = File(System.getProperty("java.io.tmpdir") + File.separator + "simplex").also { it.deleteOnExit() }
actual val cacheDir: File = tmpDir actual val filesDir: File = File(dataDir.absolutePath + File.separator + "simplex_v1_files")
actual val appFilesDir: File = filesDir
actual val coreTmpDir: File = File(dataDir.absolutePath + File.separator + "tmp")
actual val dbAbsolutePrefixPath: String = dataDir.absolutePath + File.separator + "simplex_v1"
actual val chatDatabaseFileName: String = "simplex_v1_chat.db"
actual val agentDatabaseFileName: String = "simplex_v1_agent.db"
@Composable @Composable
actual fun rememberFileChooserLauncher(getContent: Boolean, onResult: (URI?) -> Unit): FileChooserLauncher = actual fun rememberFileChooserLauncher(getContent: Boolean, onResult: (URI?) -> Unit): FileChooserLauncher =

View File

@ -4,14 +4,16 @@ import java.io.File
import java.util.* import java.util.*
private val home = System.getProperty("user.home") private val home = System.getProperty("user.home")
private val unixConfigPath = (System.getenv("XDG_CONFIG_HOME") ?: "$home/.config") + "/simplex"
private val unixDataPath = (System.getenv("XDG_DATA_HOME") ?: "$home/.local/share") + "/simplex"
val desktopPlatform = detectDesktopPlatform() val desktopPlatform = detectDesktopPlatform()
enum class DesktopPlatform(val libPath: String, val libExtension: String, val configPath: String) { enum class DesktopPlatform(val libPath: String, val libExtension: String, val configPath: String, val dataPath: String) {
LINUX_X86_64("/libs/linux-x86_64", "so", "$home/.config/simplex"), LINUX_X86_64("/libs/linux-x86_64", "so", unixConfigPath, unixDataPath),
LINUX_AARCH64("/libs/aarch64", "so", "$home/.config/simplex"), LINUX_AARCH64("/libs/aarch64", "so", unixConfigPath, unixDataPath),
WINDOWS_X86_64("/libs/windows-x86_64", "dll", System.getenv("AppData") + File.separator + "simplex"), WINDOWS_X86_64("/libs/windows-x86_64", "dll", System.getenv("AppData") + File.separator + "SimpleX", System.getenv("AppData") + File.separator + "SimpleX"),
MAC_X86_64("/libs/mac-x86_64", "dylib", "$home/.config/simplex"), MAC_X86_64("/libs/mac-x86_64", "dylib", unixConfigPath, unixDataPath),
MAC_AARCH64("/libs/mac-aarch64", "dylib", "$home/.config/simplex"); MAC_AARCH64("/libs/mac-aarch64", "dylib", unixConfigPath, unixDataPath);
} }
private fun detectDesktopPlatform(): DesktopPlatform { private fun detectDesktopPlatform(): DesktopPlatform {

View File

@ -20,7 +20,7 @@ actual fun escapedHtmlToAnnotatedString(text: String, density: Density): Annotat
} }
actual fun getAppFileUri(fileName: String): URI = actual fun getAppFileUri(fileName: String): URI =
URI("file:" + getAppFilesDirectory() + File.separator + fileName) URI("file:" + appFilesDir.absolutePath + File.separator + fileName)
actual fun getLoadedImage(file: CIFile?): ImageBitmap? { actual fun getLoadedImage(file: CIFile?): ImageBitmap? {
val filePath = getLoadedFilePath(file) val filePath = getLoadedFilePath(file)
@ -34,7 +34,7 @@ actual fun getLoadedImage(file: CIFile?): ImageBitmap? {
actual fun getFileName(uri: URI): String? = uri.toPath().toFile().name actual fun getFileName(uri: URI): String? = uri.toPath().toFile().name
actual fun getAppFilePath(uri: URI): String? = getFilesDirectory() + File.separator + "app_files" actual fun getAppFilePath(uri: URI): String? = uri.path
actual fun getFileSize(uri: URI): Long? = uri.toPath().toFile().length() actual fun getFileSize(uri: URI): Long? = uri.toPath().toFile().length()

View File

@ -4,5 +4,6 @@ import chat.simplex.common.showApp
fun main() { fun main() {
initHaskell() initHaskell()
initApp() initApp()
tmpDir.deleteRecursively()
return showApp() return showApp()
} }