Move file methods to FileUtil.kt

This commit is contained in:
tzugen 2021-11-03 14:01:02 +01:00
parent c9e276dc76
commit f73457298d
No known key found for this signature in database
GPG Key ID: 61E9C34BC10EC930
7 changed files with 93 additions and 88 deletions

View File

@ -21,7 +21,7 @@ import org.moire.ultrasonic.api.subsonic.throwOnFailure
import org.moire.ultrasonic.api.subsonic.toStreamResponse import org.moire.ultrasonic.api.subsonic.toStreamResponse
import org.moire.ultrasonic.domain.MusicDirectory import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.util.FileUtil import org.moire.ultrasonic.util.FileUtil
import org.moire.ultrasonic.util.Util import org.moire.ultrasonic.util.Util.safeClose
import timber.log.Timber import timber.log.Timber
/** /**
@ -185,10 +185,10 @@ class ImageLoader(
outputStream = FileOutputStream(file) outputStream = FileOutputStream(file)
outputStream.write(bytes) outputStream.write(bytes)
} finally { } finally {
Util.close(outputStream) outputStream.safeClose()
} }
} finally { } finally {
Util.close(inputStream) inputStream.safeClose()
} }
} }
} }

View File

@ -6,7 +6,6 @@ import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import org.moire.ultrasonic.util.FileUtil import org.moire.ultrasonic.util.FileUtil
import org.moire.ultrasonic.util.Util
import timber.log.Timber import timber.log.Timber
/** /**
@ -38,7 +37,7 @@ class FileLoggerTree : Timber.DebugTree() {
// Using base class DebugTree here, we don't want to try to log this into file // Using base class DebugTree here, we don't want to try to log this into file
super.log(6, TAG, String.format("Failed to write log to %s", file), x) super.log(6, TAG, String.format("Failed to write log to %s", file), x)
} finally { } finally {
if (writer != null) Util.close(writer) writer.safeClose()
} }
} }

View File

@ -28,6 +28,7 @@ import org.moire.ultrasonic.util.CancellableTask
import org.moire.ultrasonic.util.FileUtil import org.moire.ultrasonic.util.FileUtil
import org.moire.ultrasonic.util.Settings import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.util.Util.safeClose
import timber.log.Timber import timber.log.Timber
/** /**
@ -135,9 +136,9 @@ class DownloadFile(
fun delete() { fun delete() {
cancelDownload() cancelDownload()
Util.delete(partialFile) FileUtil.delete(partialFile)
Util.delete(completeFile) FileUtil.delete(completeFile)
Util.delete(saveFile) FileUtil.delete(saveFile)
Util.scanMedia(saveFile) Util.scanMedia(saveFile)
} }
@ -156,11 +157,11 @@ class DownloadFile(
fun cleanup(): Boolean { fun cleanup(): Boolean {
var ok = true var ok = true
if (completeFile.exists() || saveFile.exists()) { if (completeFile.exists() || saveFile.exists()) {
ok = Util.delete(partialFile) ok = FileUtil.delete(partialFile)
} }
if (saveFile.exists()) { if (saveFile.exists()) {
ok = ok and Util.delete(completeFile) ok = ok and FileUtil.delete(completeFile)
} }
return ok return ok
@ -182,14 +183,14 @@ class DownloadFile(
private fun doPendingRename() { private fun doPendingRename() {
try { try {
if (saveWhenDone) { if (saveWhenDone) {
Util.renameFile(completeFile, saveFile) FileUtil.renameFile(completeFile, saveFile)
saveWhenDone = false saveWhenDone = false
} else if (completeWhenDone) { } else if (completeWhenDone) {
if (save) { if (save) {
Util.renameFile(partialFile, saveFile) FileUtil.renameFile(partialFile, saveFile)
Util.scanMedia(saveFile) Util.scanMedia(saveFile)
} else { } else {
Util.renameFile(partialFile, completeFile) FileUtil.renameFile(partialFile, completeFile)
} }
completeWhenDone = false completeWhenDone = false
} }
@ -221,7 +222,7 @@ class DownloadFile(
if (isPlaying) { if (isPlaying) {
saveWhenDone = true saveWhenDone = true
} else { } else {
Util.renameFile(completeFile, saveFile) FileUtil.renameFile(completeFile, saveFile)
} }
} else { } else {
Timber.i("%s already exists. Skipping.", completeFile) Timber.i("%s already exists. Skipping.", completeFile)
@ -291,16 +292,16 @@ class DownloadFile(
completeWhenDone = true completeWhenDone = true
} else { } else {
if (save) { if (save) {
Util.renameFile(partialFile, saveFile) FileUtil.renameFile(partialFile, saveFile)
Util.scanMedia(saveFile) Util.scanMedia(saveFile)
} else { } else {
Util.renameFile(partialFile, completeFile) FileUtil.renameFile(partialFile, completeFile)
} }
} }
} catch (all: Exception) { } catch (all: Exception) {
Util.close(outputStream) outputStream.safeClose()
Util.delete(completeFile) FileUtil.delete(completeFile)
Util.delete(saveFile) FileUtil.delete(saveFile)
if (!isCancelled) { if (!isCancelled) {
isFailed = true isFailed = true
if (retryCount > 1) { if (retryCount > 1) {
@ -313,8 +314,8 @@ class DownloadFile(
Timber.w(all, "Failed to download '%s'.", song) Timber.w(all, "Failed to download '%s'.", song)
} }
} finally { } finally {
Util.close(inputStream) inputStream.safeClose()
Util.close(outputStream) outputStream.safeClose()
CacheCleaner().cleanSpace() CacheCleaner().cleanSpace()
downloader.checkDownloads() downloader.checkDownloads()
} }

View File

@ -41,7 +41,7 @@ import org.moire.ultrasonic.domain.Share
import org.moire.ultrasonic.domain.UserInfo import org.moire.ultrasonic.domain.UserInfo
import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.FileUtil import org.moire.ultrasonic.util.FileUtil
import org.moire.ultrasonic.util.Util import org.moire.ultrasonic.util.Util.safeClose
import timber.log.Timber import timber.log.Timber
// TODO: There are quite a number of deeply nested and complicated functions in this class.. // TODO: There are quite a number of deeply nested and complicated functions in this class..
@ -213,8 +213,8 @@ class OfflineMusicService : MusicService, KoinComponent {
} }
playlist playlist
} finally { } finally {
Util.close(buffer) buffer.safeClose()
Util.close(reader) reader.safeClose()
} }
} }

View File

@ -27,8 +27,10 @@ import java.util.TreeSet
import java.util.regex.Pattern import java.util.regex.Pattern
import org.moire.ultrasonic.app.UApp import org.moire.ultrasonic.app.UApp
import org.moire.ultrasonic.domain.MusicDirectory import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.util.Util.safeClose
import timber.log.Timber import timber.log.Timber
@Suppress("TooManyFunctions")
object FileUtil { object FileUtil {
private val FILE_SYSTEM_UNSAFE = arrayOf("/", "\\", "..", ":", "\"", "?", "*", "<", ">", "|") private val FILE_SYSTEM_UNSAFE = arrayOf("/", "\\", "..", ":", "\"", "?", "*", "<", ">", "|")
@ -416,7 +418,7 @@ object FileUtil {
Timber.w("Failed to serialize object to %s", file) Timber.w("Failed to serialize object to %s", file)
false false
} finally { } finally {
Util.close(out) out.safeClose()
} }
} }
@ -438,7 +440,7 @@ object FileUtil {
Timber.w(all, "Failed to deserialize object from %s", file) Timber.w(all, "Failed to deserialize object from %s", file)
null null
} finally { } finally {
Util.close(inStream) inStream.safeClose()
} }
} }
@ -466,8 +468,55 @@ object FileUtil {
Timber.w("Failed to save playlist: %s", name) Timber.w("Failed to save playlist: %s", name)
throw e throw e
} finally { } finally {
bw.close() bw.safeClose()
fw.close() fw.safeClose()
} }
} }
@Throws(IOException::class)
fun atomicCopy(from: File, to: File) {
val tmp = File(String.format(Locale.ROOT, "%s.tmp", to.path))
val input = FileInputStream(from)
val out = FileOutputStream(tmp)
try {
input.channel.transferTo(0, from.length(), out.channel)
out.close()
if (!tmp.renameTo(to)) {
throw IOException(
String.format(Locale.ROOT, "Failed to rename %s to %s", tmp, to)
)
}
Timber.i("Copied %s to %s", from, to)
} catch (x: IOException) {
out.safeClose()
delete(to)
throw x
} finally {
input.safeClose()
out.safeClose()
delete(tmp)
}
}
@JvmStatic
@Throws(IOException::class)
fun renameFile(from: File, to: File) {
if (from.renameTo(to)) {
Timber.i("Renamed %s to %s", from, to)
} else {
atomicCopy(from, to)
}
}
@JvmStatic
fun delete(file: File?): Boolean {
if (file != null && file.exists()) {
if (!file.delete()) {
Timber.w("Failed to delete file %s", file)
return false
}
Timber.i("Deleted file %s", file)
}
return true
}
} }

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.os.Build import android.os.Build
import java.io.File import java.io.File
import java.io.PrintWriter import java.io.PrintWriter
import org.moire.ultrasonic.util.Util.safeClose
import timber.log.Timber import timber.log.Timber
/** /**
@ -34,7 +35,7 @@ class SubsonicUncaughtExceptionHandler(
} catch (x: Throwable) { } catch (x: Throwable) {
Timber.e(x, "Failed to write stack trace to %s", file) Timber.e(x, "Failed to write stack trace to %s", file)
} finally { } finally {
Util.close(printWriter) printWriter.safeClose()
defaultHandler?.uncaughtException(thread, throwable) defaultHandler?.uncaughtException(thread, throwable)
} }
} }

View File

@ -43,9 +43,6 @@ import androidx.annotation.AnyRes
import androidx.media.utils.MediaConstants import androidx.media.utils.MediaConstants
import java.io.Closeable import java.io.Closeable
import java.io.File import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.io.UnsupportedEncodingException import java.io.UnsupportedEncodingException
import java.security.MessageDigest import java.security.MessageDigest
import java.text.DecimalFormat import java.text.DecimalFormat
@ -114,62 +111,6 @@ object Util {
} }
} }
@Throws(IOException::class)
fun atomicCopy(from: File, to: File) {
val tmp = File(String.format(Locale.ROOT, "%s.tmp", to.path))
val input = FileInputStream(from)
val out = FileOutputStream(tmp)
try {
input.channel.transferTo(0, from.length(), out.channel)
out.close()
if (!tmp.renameTo(to)) {
throw IOException(
String.format(Locale.ROOT, "Failed to rename %s to %s", tmp, to)
)
}
Timber.i("Copied %s to %s", from, to)
} catch (x: IOException) {
close(out)
delete(to)
throw x
} finally {
close(input)
close(out)
delete(tmp)
}
}
@JvmStatic
@Throws(IOException::class)
fun renameFile(from: File, to: File) {
if (from.renameTo(to)) {
Timber.i("Renamed %s to %s", from, to)
} else {
atomicCopy(from, to)
}
}
@JvmStatic
fun close(closeable: Closeable?) {
try {
closeable?.close()
} catch (_: Throwable) {
// Ignored
}
}
@JvmStatic
fun delete(file: File?): Boolean {
if (file != null && file.exists()) {
if (!file.delete()) {
Timber.w("Failed to delete file %s", file)
return false
}
Timber.i("Deleted file %s", file)
}
return true
}
@JvmStatic @JvmStatic
@JvmOverloads @JvmOverloads
fun toast(context: Context?, messageId: Int, shortDuration: Boolean = true) { fun toast(context: Context?, messageId: Int, shortDuration: Boolean = true) {
@ -957,8 +898,22 @@ object Util {
return context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager return context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
} }
/**
* Small data class to store information about the current network
**/
data class NetworkInfo( data class NetworkInfo(
var connected: Boolean = false, var connected: Boolean = false,
var unmetered: Boolean = false var unmetered: Boolean = false
) )
/**
* Closes a Closeable while ignoring any errors.
**/
fun Closeable?.safeClose() {
try {
this?.close()
} catch (_: Exception) {
// Ignored
}
}
} }