/******************************************************************************
* *
* Copyright (C) 2021 by nekohasekai
*
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see . *
* *
******************************************************************************/
package io.nekohasekai.sagernet.database
import io.nekohasekai.sagernet.GroupType
import io.nekohasekai.sagernet.bg.SubscriptionUpdater
import io.nekohasekai.sagernet.ktx.applyDefaultValues
object GroupManager {
interface Listener {
suspend fun groupAdd(group: ProxyGroup)
suspend fun groupUpdated(group: ProxyGroup)
suspend fun groupRemoved(groupId: Long)
suspend fun groupUpdated(groupId: Long)
}
interface Interface {
suspend fun confirm(message: String): Boolean
suspend fun onUpdateSuccess(
group: ProxyGroup,
changed: Int,
added: List,
updated: Map,
deleted: List,
duplicate: List
)
suspend fun onUpdateFailure(group: ProxyGroup, message: String)
}
private val listeners = ArrayList()
var userInterface: Interface? = null
suspend fun iterator(what: suspend Listener.() -> Unit) {
synchronized(listeners) {
listeners.toList()
}.forEach { listener ->
what(listener)
}
}
fun addListener(listener: Listener) {
synchronized(listeners) {
listeners.add(listener)
}
}
fun removeListener(listener: Listener) {
synchronized(listeners) {
listeners.remove(listener)
}
}
suspend fun clearGroup(groupId: Long) {
if (SagerDatabase.proxyDao.isIdInGroup(DataStore.selectedProxy, groupId) > 0) {
DataStore.selectedProxy = 0L
}
SagerDatabase.proxyDao.deleteAll(groupId)
iterator { groupUpdated(groupId) }
}
fun rearrange(groupId: Long) {
val entities = SagerDatabase.proxyDao.getByGroup(groupId)
for (index in entities.indices) {
entities[index].userOrder = (index + 1).toLong()
}
SagerDatabase.proxyDao.updateProxy(entities)
}
suspend fun postUpdate(group: ProxyGroup) {
iterator { groupUpdated(group) }
}
suspend fun postUpdate(groupId: Long) {
postUpdate(SagerDatabase.groupDao.getById(groupId) ?: return)
}
suspend fun postReload(groupId: Long) {
iterator { groupUpdated(groupId) }
}
suspend fun createGroup(group: ProxyGroup): ProxyGroup {
group.userOrder = SagerDatabase.groupDao.nextOrder() ?: 1
group.id = SagerDatabase.groupDao.createGroup(group.applyDefaultValues())
iterator { groupAdd(group) }
if (group.type == GroupType.SUBSCRIPTION && group.subscription?.autoUpdate == true) {
SubscriptionUpdater.reconfigureUpdater()
}
return group
}
suspend fun updateGroup(group: ProxyGroup, reconfigureUpdater: Boolean = true) {
SagerDatabase.groupDao.updateGroup(group)
iterator { groupUpdated(group) }
if (reconfigureUpdater && group.type == GroupType.SUBSCRIPTION && group.subscription?.autoUpdate == true) {
SubscriptionUpdater.reconfigureUpdater()
}
}
suspend fun deleteGroup(groupId: Long) {
val group = SagerDatabase.groupDao.getById(groupId)
SagerDatabase.groupDao.deleteById(groupId)
SagerDatabase.proxyDao.deleteByGroup(groupId)
iterator { groupRemoved(groupId) }
if (group?.type == GroupType.SUBSCRIPTION && group.subscription?.autoUpdate == true) {
SubscriptionUpdater.reconfigureUpdater()
}
}
suspend fun deleteGroup(group: List) {
SagerDatabase.groupDao.deleteGroup(group)
SagerDatabase.proxyDao.deleteByGroup(group.map { it.id }.toLongArray())
for (proxyGroup in group) iterator { groupRemoved(proxyGroup.id) }
if (group.any { it.type == GroupType.SUBSCRIPTION && it.subscription?.autoUpdate == true }) {
SubscriptionUpdater.reconfigureUpdater()
}
}
}