mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-09-18 15:32:35 +00:00
Improved V8 locking, comment section on diff thread than video, global mapping of v8runtimes to plugins
This commit is contained in:
parent
33d3d9a29c
commit
c14378b534
7 changed files with 68 additions and 26 deletions
|
@ -5,7 +5,9 @@ import com.caoccao.javet.values.primitive.*
|
||||||
import com.caoccao.javet.values.reference.V8ValueArray
|
import com.caoccao.javet.values.reference.V8ValueArray
|
||||||
import com.caoccao.javet.values.reference.V8ValueObject
|
import com.caoccao.javet.values.reference.V8ValueObject
|
||||||
import com.futo.platformplayer.engine.IV8PluginConfig
|
import com.futo.platformplayer.engine.IV8PluginConfig
|
||||||
|
import com.futo.platformplayer.engine.V8Plugin
|
||||||
import com.futo.platformplayer.engine.exceptions.ScriptImplementationException
|
import com.futo.platformplayer.engine.exceptions.ScriptImplementationException
|
||||||
|
import com.futo.platformplayer.logging.Logger
|
||||||
|
|
||||||
|
|
||||||
//V8
|
//V8
|
||||||
|
@ -24,6 +26,10 @@ fun <R> V8Value?.orDefault(default: R, handler: (V8Value)->R): R {
|
||||||
return handler(this);
|
return handler(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun V8Value.getSourcePlugin(): V8Plugin? {
|
||||||
|
return V8Plugin.getPluginFromRuntime(this.v8Runtime);
|
||||||
|
}
|
||||||
|
|
||||||
inline fun <reified T> V8Value.expectOrThrow(config: IV8PluginConfig, contextName: String): T {
|
inline fun <reified T> V8Value.expectOrThrow(config: IV8PluginConfig, contextName: String): T {
|
||||||
if(this !is T)
|
if(this !is T)
|
||||||
throw ScriptImplementationException(config, "Expected ${contextName} to be of type ${T::class.simpleName}, but found ${this::class.simpleName}");
|
throw ScriptImplementationException(config, "Expected ${contextName} to be of type ${T::class.simpleName}, but found ${this::class.simpleName}");
|
||||||
|
@ -90,6 +96,20 @@ inline fun <reified T> V8ValueArray.expectV8Variants(config: IV8PluginConfig, co
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T> V8Value.expectV8Variant(config: IV8PluginConfig, contextName: String): T {
|
inline fun <reified T> V8Value.expectV8Variant(config: IV8PluginConfig, contextName: String): T {
|
||||||
|
if(false)
|
||||||
|
{
|
||||||
|
this?.getSourcePlugin()?.let {
|
||||||
|
if (!it.isThreadAlreadyBusy()) {
|
||||||
|
val stacktrace = Thread.currentThread().stackTrace;
|
||||||
|
Logger.w("Extensions_V8",
|
||||||
|
"V8 USE OUTSIDE BUSY: " + stacktrace.drop(3)?.firstOrNull().toString() +
|
||||||
|
", " + stacktrace.drop(4)?.firstOrNull().toString() +
|
||||||
|
", " + stacktrace.drop(5)?.firstOrNull()?.toString() +
|
||||||
|
", " + stacktrace.drop(6)?.firstOrNull()?.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return when(T::class) {
|
return when(T::class) {
|
||||||
String::class -> this.expectOrThrow<V8ValueString>(config, contextName).value as T;
|
String::class -> this.expectOrThrow<V8ValueString>(config, contextName).value as T;
|
||||||
Int::class -> {
|
Int::class -> {
|
||||||
|
|
|
@ -59,6 +59,9 @@ import com.futo.platformplayer.states.AnnouncementType
|
||||||
import com.futo.platformplayer.states.StateAnnouncement
|
import com.futo.platformplayer.states.StateAnnouncement
|
||||||
import com.futo.platformplayer.states.StatePlatform
|
import com.futo.platformplayer.states.StatePlatform
|
||||||
import com.futo.platformplayer.states.StatePlugins
|
import com.futo.platformplayer.states.StatePlugins
|
||||||
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
|
import kotlinx.coroutines.Deferred
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import java.time.OffsetDateTime
|
import java.time.OffsetDateTime
|
||||||
|
@ -771,6 +774,13 @@ open class JSClient : IPlatformClient {
|
||||||
return@busy handle();
|
return@busy handle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fun <T> busyBlockingSuspended(handle: suspend ()->T): T {
|
||||||
|
return _plugin.busy {
|
||||||
|
return@busy runBlocking {
|
||||||
|
return@runBlocking handle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun <T> isBusyWith(actionName: String, handle: ()->T): T {
|
fun <T> isBusyWith(actionName: String, handle: ()->T): T {
|
||||||
//val busyId = kotlin.random.Random.nextInt(9999);
|
//val busyId = kotlin.random.Random.nextInt(9999);
|
||||||
|
|
|
@ -32,7 +32,7 @@ open class JSDashManifestRawSource: JSSource, IVideoSource, IJSDashManifestRawSo
|
||||||
override val duration: Long;
|
override val duration: Long;
|
||||||
override val priority: Boolean;
|
override val priority: Boolean;
|
||||||
|
|
||||||
var url: String?;
|
val url: String?;
|
||||||
override var manifest: String?;
|
override var manifest: String?;
|
||||||
|
|
||||||
override val hasGenerate: Boolean;
|
override val hasGenerate: Boolean;
|
||||||
|
|
|
@ -53,43 +53,39 @@ abstract class JSSource {
|
||||||
hasRequestExecutor = _requestExecutor != null || obj.has("getRequestExecutor");
|
hasRequestExecutor = _requestExecutor != null || obj.has("getRequestExecutor");
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getRequestModifier(): IRequestModifier? {
|
fun getRequestModifier(): IRequestModifier? = _plugin.isBusyWith("getRequestModifier") {
|
||||||
if(_requestModifier != null)
|
if(_requestModifier != null)
|
||||||
return AdhocRequestModifier { url, headers ->
|
return@isBusyWith AdhocRequestModifier { url, headers ->
|
||||||
return@AdhocRequestModifier _requestModifier.modify(_plugin, url, headers);
|
return@AdhocRequestModifier _requestModifier.modify(_plugin, url, headers);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!hasRequestModifier || _obj.isClosed)
|
if (!hasRequestModifier || _obj.isClosed)
|
||||||
return null;
|
return@isBusyWith null;
|
||||||
|
|
||||||
val result = _plugin.isBusyWith("getRequestModifier") {
|
val result = V8Plugin.catchScriptErrors<Any>(_config, "[${_config.name}] JSVideoUrlSource", "obj.getRequestModifier()") {
|
||||||
V8Plugin.catchScriptErrors<Any>(_config, "[${_config.name}] JSVideoUrlSource", "obj.getRequestModifier()") {
|
_obj.invoke("getRequestModifier", arrayOf<Any>());
|
||||||
_obj.invoke("getRequestModifier", arrayOf<Any>());
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result !is V8ValueObject)
|
if (result !is V8ValueObject)
|
||||||
return null;
|
return@isBusyWith null;
|
||||||
|
|
||||||
return JSRequestModifier(_plugin, result)
|
return@isBusyWith JSRequestModifier(_plugin, result)
|
||||||
}
|
}
|
||||||
open fun getRequestExecutor(): JSRequestExecutor? {
|
open fun getRequestExecutor(): JSRequestExecutor? = _plugin.isBusyWith("getRequestExecutor") {
|
||||||
if (!hasRequestExecutor || _obj.isClosed)
|
if (!hasRequestExecutor || _obj.isClosed)
|
||||||
return null;
|
return@isBusyWith null;
|
||||||
|
|
||||||
Logger.v("JSSource", "Request executor for [${type}] requesting");
|
Logger.v("JSSource", "Request executor for [${type}] requesting");
|
||||||
val result =_plugin.isBusyWith("getRequestExecutor") {
|
val result = V8Plugin.catchScriptErrors<Any>(_config, "[${_config.name}] JSSource", "obj.getRequestExecutor()") {
|
||||||
V8Plugin.catchScriptErrors<Any>(_config, "[${_config.name}] JSSource", "obj.getRequestExecutor()") {
|
_obj.invoke("getRequestExecutor", arrayOf<Any>());
|
||||||
_obj.invoke("getRequestExecutor", arrayOf<Any>());
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.v("JSSource", "Request executor for [${type}] received");
|
Logger.v("JSSource", "Request executor for [${type}] received");
|
||||||
|
|
||||||
if (result !is V8ValueObject)
|
if (result !is V8ValueObject)
|
||||||
return null;
|
return@isBusyWith null;
|
||||||
|
|
||||||
return JSRequestExecutor(_plugin, result)
|
return@isBusyWith JSRequestExecutor(_plugin, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUnderlyingPlugin(): JSClient? {
|
fun getUnderlyingPlugin(): JSClient? {
|
||||||
|
|
|
@ -49,6 +49,7 @@ class V8Plugin {
|
||||||
private val _clientAuth: ManagedHttpClient;
|
private val _clientAuth: ManagedHttpClient;
|
||||||
private val _clientOthers: ConcurrentHashMap<String, JSHttpClient> = ConcurrentHashMap();
|
private val _clientOthers: ConcurrentHashMap<String, JSHttpClient> = ConcurrentHashMap();
|
||||||
|
|
||||||
|
|
||||||
val httpClient: ManagedHttpClient get() = _client;
|
val httpClient: ManagedHttpClient get() = _client;
|
||||||
val httpClientAuth: ManagedHttpClient get() = _clientAuth;
|
val httpClientAuth: ManagedHttpClient get() = _clientAuth;
|
||||||
val httpClientOthers: Map<String, JSHttpClient> get() = _clientOthers;
|
val httpClientOthers: Map<String, JSHttpClient> get() = _clientOthers;
|
||||||
|
@ -151,6 +152,8 @@ class V8Plugin {
|
||||||
if (!host.isIsolateCreated)
|
if (!host.isIsolateCreated)
|
||||||
throw IllegalStateException("Isolate not created");
|
throw IllegalStateException("Isolate not created");
|
||||||
|
|
||||||
|
_runtimeMap.put(_runtime!!, this);
|
||||||
|
|
||||||
//Setup bridge
|
//Setup bridge
|
||||||
_runtime?.let {
|
_runtime?.let {
|
||||||
it.converter = V8Converter();
|
it.converter = V8Converter();
|
||||||
|
@ -203,6 +206,7 @@ class V8Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
_runtime?.let {
|
_runtime?.let {
|
||||||
|
_runtimeMap.remove(it);
|
||||||
_runtime = null;
|
_runtime = null;
|
||||||
if(!it.isClosed && !it.isDead) {
|
if(!it.isClosed && !it.isDead) {
|
||||||
try {
|
try {
|
||||||
|
@ -222,6 +226,9 @@ class V8Plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isThreadAlreadyBusy(): Boolean {
|
||||||
|
return _busyLock.isHeldByCurrentThread;
|
||||||
|
}
|
||||||
fun <T> busy(handle: ()->T): T {
|
fun <T> busy(handle: ()->T): T {
|
||||||
_busyLock.withLock {
|
_busyLock.withLock {
|
||||||
//Logger.i(TAG, "Entered busy: " + Thread.currentThread().stackTrace.drop(3)?.firstOrNull()?.toString() + ", " + Thread.currentThread().stackTrace.drop(4)?.firstOrNull()?.toString());
|
//Logger.i(TAG, "Entered busy: " + Thread.currentThread().stackTrace.drop(3)?.firstOrNull()?.toString() + ", " + Thread.currentThread().stackTrace.drop(4)?.firstOrNull()?.toString());
|
||||||
|
@ -273,8 +280,14 @@ class V8Plugin {
|
||||||
private val REGEX_EX_FALLBACK = Regex(".*throw.*?[\"](.*)[\"].*");
|
private val REGEX_EX_FALLBACK = Regex(".*throw.*?[\"](.*)[\"].*");
|
||||||
private val REGEX_EX_FALLBACK2 = Regex(".*throw.*?['](.*)['].*");
|
private val REGEX_EX_FALLBACK2 = Regex(".*throw.*?['](.*)['].*");
|
||||||
|
|
||||||
|
private val _runtimeMap = ConcurrentHashMap<V8Runtime, V8Plugin>();
|
||||||
|
|
||||||
val TAG = "V8Plugin";
|
val TAG = "V8Plugin";
|
||||||
|
|
||||||
|
fun getPluginFromRuntime(runtime: V8Runtime): V8Plugin? {
|
||||||
|
return _runtimeMap.getOrDefault(runtime, null);
|
||||||
|
}
|
||||||
|
|
||||||
fun <T: Any?> catchScriptErrors(config: IV8PluginConfig, context: String, code: String? = null, handle: ()->T): T {
|
fun <T: Any?> catchScriptErrors(config: IV8PluginConfig, context: String, code: String? = null, handle: ()->T): T {
|
||||||
var codeStripped = code;
|
var codeStripped = code;
|
||||||
if(codeStripped != null) { //TODO: Improve code stripped
|
if(codeStripped != null) { //TODO: Improve code stripped
|
||||||
|
|
|
@ -958,7 +958,7 @@ class StatePlatform {
|
||||||
//Comments
|
//Comments
|
||||||
fun getComments(content: IPlatformContentDetails): IPager<IPlatformComment> {
|
fun getComments(content: IPlatformContentDetails): IPager<IPlatformComment> {
|
||||||
val client = getContentClient(content.url);
|
val client = getContentClient(content.url);
|
||||||
val pager = content.getComments(client);
|
val pager = null;//content.getComments(client);
|
||||||
|
|
||||||
return pager ?: getComments(content.url);
|
return pager ?: getComments(content.url);
|
||||||
}
|
}
|
||||||
|
@ -969,7 +969,7 @@ class StatePlatform {
|
||||||
return EmptyPager();
|
return EmptyPager();
|
||||||
|
|
||||||
if(!StateApp.instance.privateMode)
|
if(!StateApp.instance.privateMode)
|
||||||
return client.fromPool(_mainClientPool).getComments(url);
|
return client.fromPool(_pagerClientPool).getComments(url);
|
||||||
else
|
else
|
||||||
return client.fromPool(_privateClientPool).getComments(url);
|
return client.fromPool(_privateClientPool).getComments(url);
|
||||||
}
|
}
|
||||||
|
|
|
@ -353,8 +353,10 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
|
||||||
var videoSourceUsed = videoSource;
|
var videoSourceUsed = videoSource;
|
||||||
var audioSourceUsed = audioSource;
|
var audioSourceUsed = audioSource;
|
||||||
if(videoSource is JSDashManifestRawSource && audioSource is JSDashManifestRawAudioSource){
|
if(videoSource is JSDashManifestRawSource && audioSource is JSDashManifestRawAudioSource){
|
||||||
videoSourceUsed = JSDashManifestMergingRawSource(videoSource, audioSource);
|
videoSource.getUnderlyingPlugin()?.busy {
|
||||||
audioSourceUsed = null;
|
videoSourceUsed = JSDashManifestMergingRawSource(videoSource, audioSource);
|
||||||
|
audioSourceUsed = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val didSetVideo = swapSourceInternal(videoSourceUsed, play, resume);
|
val didSetVideo = swapSourceInternal(videoSourceUsed, play, resume);
|
||||||
|
@ -567,8 +569,9 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
|
||||||
findViewTreeLifecycleOwner()?.lifecycle?.coroutineScope?.launch(Dispatchers.IO) {
|
findViewTreeLifecycleOwner()?.lifecycle?.coroutineScope?.launch(Dispatchers.IO) {
|
||||||
var startId = -1;
|
var startId = -1;
|
||||||
try {
|
try {
|
||||||
startId = videoSource?.getUnderlyingPlugin()?.getUnderlyingPlugin()?.runtimeId ?: -1;
|
val plugin = videoSource.getUnderlyingPlugin() ?: return@launch;
|
||||||
val generated = videoSource.generate();
|
startId = plugin.getUnderlyingPlugin()?.runtimeId ?: -1;
|
||||||
|
val generated = plugin.busy { videoSource.generate(); };
|
||||||
if (generated != null) {
|
if (generated != null) {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
val dataSource = if(videoSource is JSSource && (videoSource.requiresCustomDatasource))
|
val dataSource = if(videoSource is JSSource && (videoSource.requiresCustomDatasource))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue