Skip to content
Snippets Groups Projects
Commit dc9cc7b0 authored by Kelvin's avatar Kelvin
Browse files

WIP updating block for subscriptions

parent 965e74c7
No related branches found
No related tags found
No related merge requests found
......@@ -19,6 +19,7 @@ import com.futo.platformplayer.stores.PluginIconStorage
import com.futo.platformplayer.stores.PluginScriptsDirectory
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable
......@@ -47,6 +48,8 @@ class StatePlugins {
private var _updatesAvailableMap: HashSet<String> = hashSetOf();
private val _isUpdating: HashSet<String> = hashSetOf();
fun getPluginIconOrNull(id: String): ImageVariable? {
if(iconsDir.hasIcon(id))
return iconsDir.getIconBinary(id);
......@@ -58,6 +61,38 @@ class StatePlugins {
.load();
}
fun isUpdating(id: String): Boolean{
synchronized(_isUpdating){
return _isUpdating.contains(id);
}
}
fun setIsUpdating(id: String, value: Boolean){
synchronized(_isUpdating){
if(value && !_isUpdating.contains(id)) {
Logger.i(TAG, "PLUGIN [${id}] UPDATING");
_isUpdating.add(id);
}
if(!value && _isUpdating.contains(id)) {
Logger.i(TAG, "PLUGIN [${id}] NOT UPDATING");
_isUpdating.remove(id);
}
}
}
suspend fun whileUpdating(id: String, handle: suspend ()->Unit){
try {
setIsUpdating(id, true);
handle();
}
finally {
setIsUpdating(id, false);
}
}
fun clearUpdating(){
synchronized(_isUpdating) {
_isUpdating.clear();
}
}
suspend fun checkForUpdates(): List<Pair<SourcePluginConfig, SourcePluginConfig>> = withContext(Dispatchers.IO) {
var configs = mutableListOf<Pair<SourcePluginConfig, SourcePluginConfig>>()
......@@ -430,42 +465,49 @@ class StatePlugins {
fun installPluginBackground(context: Context, scope: CoroutineScope, config: SourcePluginConfig, script: String, onProgress: (text: String, progress: Double)->Unit, onConcluded: (ex: Throwable?)->Unit) {
scope.launch(Dispatchers.IO) {
val client = ManagedHttpClient();
try {
whileUpdating(config.id) {
withContext(Dispatchers.Main) {
onProgress.invoke("Validating script", 0.25);
onProgress.invoke("Waiting for plugins to finish", 0.1);
}
delay(500);
val tempDescriptor = SourcePluginDescriptor(config);
val plugin = JSClient(context, tempDescriptor, null, script);
plugin.validate();
val client = ManagedHttpClient();
try {
withContext(Dispatchers.Main) {
onProgress.invoke("Validating script", 0.25);
}
withContext(Dispatchers.Main) {
onProgress.invoke("Downloading Icon", 0.5);
}
val tempDescriptor = SourcePluginDescriptor(config);
val plugin = JSClient(context, tempDescriptor, null, script);
plugin.validate();
val icon = config.absoluteIconUrl?.let { absIconUrl ->
withContext(Dispatchers.Main) {
onProgress.invoke("Saving plugin", 0.75);
onProgress.invoke("Downloading Icon", 0.5);
}
val iconResp = client.get(absIconUrl);
if(iconResp.isOk)
return@let iconResp.body?.byteStream()?.use { it.readBytes() };
return@let null;
}
val installEx = StatePlugins.instance.createPlugin(config, script, icon, true);
if(installEx != null)
throw installEx;
StatePlatform.instance.updateAvailableClients(context);
withContext(Dispatchers.Main) {
onProgress.invoke("Finished", 1.0)
onConcluded.invoke(null);
}
} catch (ex: Exception) {
Logger.e(TAG, ex.message ?: "null", ex);
withContext(Dispatchers.Main) {
onConcluded.invoke(ex);
val icon = config.absoluteIconUrl?.let { absIconUrl ->
withContext(Dispatchers.Main) {
onProgress.invoke("Saving plugin", 0.75);
}
val iconResp = client.get(absIconUrl);
if (iconResp.isOk)
return@let iconResp.body?.byteStream()?.use { it.readBytes() };
return@let null;
}
val installEx = StatePlugins.instance.createPlugin(config, script, icon, true);
if (installEx != null)
throw installEx;
StatePlatform.instance.updateAvailableClients(context);
withContext(Dispatchers.Main) {
onProgress.invoke("Finished", 1.0)
onConcluded.invoke(null);
}
} catch (ex: Exception) {
Logger.e(TAG, ex.message ?: "null", ex);
withContext(Dispatchers.Main) {
onConcluded.invoke(ex);
}
}
}
}
......
......@@ -22,6 +22,7 @@ import com.futo.platformplayer.models.Subscription
import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.states.StateCache
import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.states.StatePlugins
import com.futo.platformplayer.states.StateSubscriptions
import kotlinx.coroutines.CoroutineScope
import java.time.OffsetDateTime
......@@ -138,6 +139,18 @@ abstract class SubscriptionsTaskFetchAlgorithm(
for(task in tasks) {
val forkTask = threadPool.submit<SubscriptionTaskResult> {
if(StatePlugins.instance.isUpdating(task.client.id)){
val isUpdatingException = ScriptCriticalException(task.client.config, "Plugin is updating");
synchronized(failedPlugins) {
//Fail all subscription calls to plugin if it has a critical issue
if(isUpdatingException.config is SourcePluginConfig && !failedPlugins.contains(isUpdatingException.config.id)) {
Logger.w(StateSubscriptions.TAG, "Subscriptions ignoring plugin [${isUpdatingException.config.name}] due to critical exception:\n" + isUpdatingException.message);
failedPlugins.add(isUpdatingException.config.id);
}
}
return@submit SubscriptionTaskResult(task, StateCache.instance.getChannelCachePager(task.sub.channel.url), isUpdatingException);
}
if(task.fromPeek) {
try {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment