2022-07-04 17:31:58 +02:00
|
|
|
/*
|
|
|
|
* ActiveServerProvider.kt
|
|
|
|
* Copyright (C) 2009-2022 Ultrasonic developers
|
|
|
|
*
|
|
|
|
* Distributed under terms of the GNU GPLv3 license.
|
|
|
|
*/
|
|
|
|
|
2020-09-18 09:37:19 +02:00
|
|
|
package org.moire.ultrasonic.data
|
|
|
|
|
2021-06-20 16:31:08 +02:00
|
|
|
import androidx.room.Room
|
2021-10-31 13:07:48 +01:00
|
|
|
import kotlinx.coroutines.CoroutineScope
|
2020-09-18 09:37:19 +02:00
|
|
|
import kotlinx.coroutines.Dispatchers
|
|
|
|
import kotlinx.coroutines.launch
|
|
|
|
import kotlinx.coroutines.runBlocking
|
|
|
|
import kotlinx.coroutines.withContext
|
|
|
|
import org.moire.ultrasonic.R
|
2021-05-09 10:25:04 +02:00
|
|
|
import org.moire.ultrasonic.app.UApp
|
2021-06-20 16:31:08 +02:00
|
|
|
import org.moire.ultrasonic.di.DB_FILENAME
|
2020-09-18 09:37:19 +02:00
|
|
|
import org.moire.ultrasonic.service.MusicServiceFactory.resetMusicService
|
2022-04-08 18:08:56 +02:00
|
|
|
import org.moire.ultrasonic.service.RxBus
|
2020-09-18 09:37:19 +02:00
|
|
|
import org.moire.ultrasonic.util.Constants
|
2021-09-24 18:20:53 +02:00
|
|
|
import org.moire.ultrasonic.util.Settings
|
2020-09-18 09:37:19 +02:00
|
|
|
import org.moire.ultrasonic.util.Util
|
2020-09-30 14:47:59 +02:00
|
|
|
import timber.log.Timber
|
2020-09-18 09:37:19 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This class can be used to retrieve the properties of the Active Server
|
|
|
|
* It caches the settings read up from the DB to improve performance.
|
|
|
|
*/
|
|
|
|
class ActiveServerProvider(
|
2021-05-09 10:25:04 +02:00
|
|
|
private val repository: ServerSettingDao
|
2021-10-31 13:07:48 +01:00
|
|
|
) : CoroutineScope by CoroutineScope(Dispatchers.IO) {
|
2020-09-18 09:37:19 +02:00
|
|
|
private var cachedServer: ServerSetting? = null
|
2021-06-20 16:31:08 +02:00
|
|
|
private var cachedDatabase: MetaDatabase? = null
|
|
|
|
private var cachedServerId: Int? = null
|
2020-09-18 09:37:19 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the settings of the current Active Server
|
|
|
|
* @return The Active Server Settings
|
|
|
|
*/
|
2021-09-12 14:36:33 +02:00
|
|
|
@JvmOverloads
|
|
|
|
fun getActiveServer(serverId: Int = getActiveServerId()): ServerSetting {
|
2022-03-27 13:43:03 +02:00
|
|
|
if (serverId > OFFLINE_DB_ID) {
|
2020-09-18 09:37:19 +02:00
|
|
|
if (cachedServer != null && cachedServer!!.id == serverId) return cachedServer!!
|
|
|
|
|
|
|
|
// Ideally this is the only call where we block the thread while using the repository
|
|
|
|
runBlocking {
|
|
|
|
withContext(Dispatchers.IO) {
|
|
|
|
cachedServer = repository.findById(serverId)
|
|
|
|
}
|
2020-09-30 14:47:59 +02:00
|
|
|
Timber.d(
|
2021-06-09 12:19:34 +02:00
|
|
|
"getActiveServer retrieved from DataBase, id: %s cachedServer: %s",
|
|
|
|
serverId, cachedServer
|
2020-09-22 22:01:33 +02:00
|
|
|
)
|
2020-09-18 09:37:19 +02:00
|
|
|
}
|
|
|
|
|
2021-06-09 12:19:34 +02:00
|
|
|
if (cachedServer != null) {
|
|
|
|
return cachedServer!!
|
|
|
|
}
|
|
|
|
|
2022-03-27 13:43:03 +02:00
|
|
|
// Fallback to Offline
|
2022-04-08 18:08:56 +02:00
|
|
|
setActiveServerById(OFFLINE_DB_ID)
|
2020-09-18 09:37:19 +02:00
|
|
|
}
|
|
|
|
|
2022-03-27 13:43:03 +02:00
|
|
|
return OFFLINE_DB
|
2020-09-18 09:37:19 +02:00
|
|
|
}
|
|
|
|
|
2022-04-08 18:08:56 +02:00
|
|
|
/**
|
|
|
|
* Resolves the index (sort order) of a server to its id (unique)
|
|
|
|
* @param index: The index of the server in the server selector
|
|
|
|
* @return id: The unique id of the server
|
|
|
|
*/
|
|
|
|
fun getServerIdFromIndex(index: Int): Int {
|
|
|
|
if (index <= OFFLINE_DB_INDEX) {
|
|
|
|
// Offline mode is selected
|
|
|
|
return OFFLINE_DB_ID
|
|
|
|
}
|
|
|
|
|
|
|
|
var id: Int
|
|
|
|
|
|
|
|
runBlocking {
|
|
|
|
id = repository.findByIndex(index)?.id ?: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
return id
|
|
|
|
}
|
|
|
|
|
2020-09-18 09:37:19 +02:00
|
|
|
/**
|
|
|
|
* Sets the Active Server by the Server Index in the Server Selector List
|
|
|
|
* @param index: The index of the Active Server in the Server Selector List
|
|
|
|
*/
|
|
|
|
fun setActiveServerByIndex(index: Int) {
|
2020-09-30 14:47:59 +02:00
|
|
|
Timber.d("setActiveServerByIndex $index")
|
2022-03-27 13:43:03 +02:00
|
|
|
if (index <= OFFLINE_DB_INDEX) {
|
2020-09-18 09:37:19 +02:00
|
|
|
// Offline mode is selected
|
2022-04-08 18:08:56 +02:00
|
|
|
setActiveServerById(OFFLINE_DB_ID)
|
2020-09-18 09:37:19 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-10-31 13:07:48 +01:00
|
|
|
launch {
|
2020-09-25 10:43:33 +02:00
|
|
|
val serverId = repository.findByIndex(index)?.id ?: 0
|
2022-04-08 18:08:56 +02:00
|
|
|
setActiveServerById(serverId)
|
2020-09-18 09:37:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-20 16:31:08 +02:00
|
|
|
@Synchronized
|
|
|
|
fun getActiveMetaDatabase(): MetaDatabase {
|
|
|
|
val activeServer = getActiveServerId()
|
|
|
|
|
|
|
|
if (activeServer == cachedServerId && cachedDatabase != null) {
|
|
|
|
return cachedDatabase!!
|
|
|
|
}
|
|
|
|
|
2021-09-12 14:36:33 +02:00
|
|
|
if (activeServer < 1) {
|
|
|
|
return offlineMetaDatabase
|
|
|
|
}
|
|
|
|
|
2021-06-20 16:31:08 +02:00
|
|
|
Timber.i("Switching to new database, id:$activeServer")
|
|
|
|
cachedServerId = activeServer
|
2022-04-18 07:31:06 +02:00
|
|
|
cachedDatabase = initDatabase(activeServer)
|
|
|
|
|
|
|
|
return cachedDatabase!!
|
2021-09-12 14:36:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
val offlineMetaDatabase: MetaDatabase by lazy {
|
2022-04-18 07:31:06 +02:00
|
|
|
initDatabase(0)
|
2022-03-27 13:43:03 +02:00
|
|
|
}
|
|
|
|
|
2022-04-18 07:31:06 +02:00
|
|
|
private fun initDatabase(serverId: Int): MetaDatabase {
|
2022-03-27 13:43:03 +02:00
|
|
|
return Room.databaseBuilder(
|
2021-09-12 14:36:33 +02:00
|
|
|
UApp.applicationContext(),
|
|
|
|
MetaDatabase::class.java,
|
2022-04-18 07:31:06 +02:00
|
|
|
METADATA_DB + serverId
|
2022-07-04 17:31:58 +02:00
|
|
|
)
|
|
|
|
.addMigrations(META_MIGRATION_2_3)
|
|
|
|
.fallbackToDestructiveMigrationOnDowngrade()
|
2021-09-12 14:36:33 +02:00
|
|
|
.build()
|
2021-06-20 16:31:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Synchronized
|
|
|
|
fun deleteMetaDatabase(id: Int) {
|
|
|
|
cachedDatabase?.close()
|
|
|
|
UApp.applicationContext().deleteDatabase(METADATA_DB + id)
|
|
|
|
Timber.i("Deleted metadataBase, id:$id")
|
|
|
|
}
|
|
|
|
|
2020-10-13 21:41:01 +02:00
|
|
|
/**
|
|
|
|
* Sets the minimum Subsonic API version of the current server.
|
|
|
|
*/
|
|
|
|
fun setMinimumApiVersion(apiVersion: String) {
|
2021-10-31 13:07:48 +01:00
|
|
|
launch {
|
2020-10-13 21:41:01 +02:00
|
|
|
if (cachedServer != null) {
|
|
|
|
cachedServer!!.minimumApiVersion = apiVersion
|
|
|
|
repository.update(cachedServer!!)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-18 09:37:19 +02:00
|
|
|
/**
|
|
|
|
* Invalidates the Active Server Setting cache
|
|
|
|
* This should be called when the Active Server or one of its properties changes
|
|
|
|
*/
|
|
|
|
fun invalidateCache() {
|
2020-09-30 14:47:59 +02:00
|
|
|
Timber.d("Cache is invalidated")
|
2020-09-18 09:37:19 +02:00
|
|
|
cachedServer = null
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the Rest Url of the Active Server
|
|
|
|
* @param method: The Rest resource to use
|
|
|
|
* @return The Rest Url of the method on the server
|
|
|
|
*/
|
2021-06-09 12:19:34 +02:00
|
|
|
fun getRestUrl(method: String?): String {
|
2020-09-18 09:37:19 +02:00
|
|
|
val builder = StringBuilder(8192)
|
|
|
|
val activeServer = getActiveServer()
|
|
|
|
val serverUrl: String = activeServer.url
|
|
|
|
val username: String = activeServer.userName
|
|
|
|
var password: String = activeServer.password
|
|
|
|
|
|
|
|
// Slightly obfuscate password
|
|
|
|
password = "enc:" + Util.utf8HexEncode(password)
|
|
|
|
builder.append(serverUrl)
|
|
|
|
if (builder[builder.length - 1] != '/') {
|
|
|
|
builder.append('/')
|
|
|
|
}
|
|
|
|
builder.append("rest/").append(method).append(".view")
|
|
|
|
builder.append("?u=").append(username)
|
|
|
|
builder.append("&p=").append(password)
|
|
|
|
builder.append("&v=").append(Constants.REST_PROTOCOL_VERSION)
|
|
|
|
builder.append("&c=").append(Constants.REST_CLIENT_ID)
|
|
|
|
return builder.toString()
|
|
|
|
}
|
|
|
|
|
|
|
|
companion object {
|
2021-06-20 16:31:08 +02:00
|
|
|
const val METADATA_DB = "$DB_FILENAME-meta-"
|
2022-03-27 13:43:03 +02:00
|
|
|
const val OFFLINE_DB_ID = -1
|
|
|
|
const val OFFLINE_DB_INDEX = 0
|
|
|
|
|
|
|
|
val OFFLINE_DB = ServerSetting(
|
|
|
|
id = OFFLINE_DB_ID,
|
|
|
|
index = OFFLINE_DB_INDEX,
|
|
|
|
name = UApp.applicationContext().getString(R.string.main_offline),
|
|
|
|
url = "http://localhost",
|
|
|
|
userName = "",
|
|
|
|
password = "",
|
|
|
|
jukeboxByDefault = false,
|
|
|
|
allowSelfSignedCertificate = false,
|
|
|
|
ldapSupport = false,
|
|
|
|
musicFolderId = "",
|
|
|
|
minimumApiVersion = null
|
|
|
|
)
|
|
|
|
|
2020-09-18 09:37:19 +02:00
|
|
|
/**
|
|
|
|
* Queries if the Active Server is the "Offline" mode of Ultrasonic
|
|
|
|
* @return True, if the "Offline" mode is selected
|
|
|
|
*/
|
2021-05-09 10:25:04 +02:00
|
|
|
fun isOffline(): Boolean {
|
2022-03-27 13:43:03 +02:00
|
|
|
return getActiveServerId() == OFFLINE_DB_ID
|
2020-09-18 09:37:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Queries the Id of the Active Server
|
|
|
|
*/
|
2021-05-09 10:25:04 +02:00
|
|
|
fun getActiveServerId(): Int {
|
2021-10-23 17:25:59 +02:00
|
|
|
return Settings.activeServer
|
2020-09-18 09:37:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-04-08 18:08:56 +02:00
|
|
|
* Sets the Active Server by its unique id
|
|
|
|
* @param serverId: The id of the desired server
|
2020-09-18 09:37:19 +02:00
|
|
|
*/
|
2022-04-08 18:08:56 +02:00
|
|
|
fun setActiveServerById(serverId: Int) {
|
2020-09-18 09:37:19 +02:00
|
|
|
resetMusicService()
|
|
|
|
|
2021-10-23 17:25:59 +02:00
|
|
|
Settings.activeServer = serverId
|
2022-04-08 18:08:56 +02:00
|
|
|
|
|
|
|
Timber.i("setActiveServerById done, new id: %s", serverId)
|
|
|
|
RxBus.activeServerChangePublisher.onNext(serverId)
|
2020-09-18 09:37:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Queries if Scrobbling is enabled
|
|
|
|
*/
|
2021-05-09 10:25:04 +02:00
|
|
|
fun isScrobblingEnabled(): Boolean {
|
|
|
|
if (isOffline()) {
|
2020-09-18 09:37:19 +02:00
|
|
|
return false
|
|
|
|
}
|
2021-09-24 18:20:53 +02:00
|
|
|
val preferences = Settings.preferences
|
2020-09-18 09:37:19 +02:00
|
|
|
return preferences.getBoolean(Constants.PREFERENCES_KEY_SCROBBLE, false)
|
|
|
|
}
|
|
|
|
|
2022-07-06 11:14:46 +02:00
|
|
|
/**
|
|
|
|
* Queries if ID3 tags should be used
|
|
|
|
*/
|
|
|
|
fun isID3Enabled(): Boolean {
|
|
|
|
return Settings.shouldUseId3Tags && (!isOffline() || Settings.useId3TagsOffline)
|
|
|
|
}
|
|
|
|
|
2020-09-18 09:37:19 +02:00
|
|
|
/**
|
|
|
|
* Queries if Server Scaling is enabled
|
|
|
|
*/
|
2021-05-09 10:25:04 +02:00
|
|
|
fun isServerScalingEnabled(): Boolean {
|
|
|
|
if (isOffline()) {
|
2020-09-18 09:37:19 +02:00
|
|
|
return false
|
|
|
|
}
|
2021-10-23 17:25:59 +02:00
|
|
|
return Settings.serverScaling
|
2020-09-18 09:37:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|