1
0
mirror of https://github.com/ultrasonic/ultrasonic synced 2025-02-11 01:00:58 +01:00

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.domain.MusicDirectory
import org.moire.ultrasonic.util.FileUtil
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.util.Util.safeClose
import timber.log.Timber
/**
@ -185,10 +185,10 @@ class ImageLoader(
outputStream = FileOutputStream(file)
outputStream.write(bytes)
} finally {
Util.close(outputStream)
outputStream.safeClose()
}
} finally {
Util.close(inputStream)
inputStream.safeClose()
}
}
}

View File

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

View File

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

View File

@ -27,8 +27,10 @@ import java.util.TreeSet
import java.util.regex.Pattern
import org.moire.ultrasonic.app.UApp
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.util.Util.safeClose
import timber.log.Timber
@Suppress("TooManyFunctions")
object FileUtil {
private val FILE_SYSTEM_UNSAFE = arrayOf("/", "\\", "..", ":", "\"", "?", "*", "<", ">", "|")
@ -416,7 +418,7 @@ object FileUtil {
Timber.w("Failed to serialize object to %s", file)
false
} finally {
Util.close(out)
out.safeClose()
}
}
@ -438,7 +440,7 @@ object FileUtil {
Timber.w(all, "Failed to deserialize object from %s", file)
null
} finally {
Util.close(inStream)
inStream.safeClose()
}
}
@ -466,8 +468,55 @@ object FileUtil {
Timber.w("Failed to save playlist: %s", name)
throw e
} finally {
bw.close()
fw.close()
bw.safeClose()
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 java.io.File
import java.io.PrintWriter
import org.moire.ultrasonic.util.Util.safeClose
import timber.log.Timber
/**
@ -34,7 +35,7 @@ class SubsonicUncaughtExceptionHandler(
} catch (x: Throwable) {
Timber.e(x, "Failed to write stack trace to %s", file)
} finally {
Util.close(printWriter)
printWriter.safeClose()
defaultHandler?.uncaughtException(thread, throwable)
}
}

View File

@ -43,9 +43,6 @@ import androidx.annotation.AnyRes
import androidx.media.utils.MediaConstants
import java.io.Closeable
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.io.UnsupportedEncodingException
import java.security.MessageDigest
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
@JvmOverloads
fun toast(context: Context?, messageId: Int, shortDuration: Boolean = true) {
@ -957,8 +898,22 @@ object Util {
return context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
}
/**
* Small data class to store information about the current network
**/
data class NetworkInfo(
var connected: Boolean = false,
var unmetered: Boolean = false
)
/**
* Closes a Closeable while ignoring any errors.
**/
fun Closeable?.safeClose() {
try {
this?.close()
} catch (_: Exception) {
// Ignored
}
}
}