mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-13 12:50:37 -05:00
Don't block UI while executing long runnig actions
The previous approach had the problem of losing any action internal state changes in the created copy. Revert "Fix temp var values of actions not being accessible" This reverts commitdf42538319. Revert "Don't block UI while running actions" This reverts commita01d26e25d.
This commit is contained in:
@@ -167,24 +167,6 @@ bool MacroSegment::IsTempVarInUse(const std::string &id) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void MacroSegment::CopyTempVarValuesFrom(const MacroSegment &other)
|
||||
{
|
||||
for (const auto &src : other._tempVariables) {
|
||||
for (auto &dst : _tempVariables) {
|
||||
if (dst.ID() != src.ID()) {
|
||||
continue;
|
||||
}
|
||||
auto value = src.Value();
|
||||
if (value) {
|
||||
dst.SetValue(*value);
|
||||
} else {
|
||||
dst.InvalidateValue();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MacroSegment::SetTempVarValue(const std::string &id,
|
||||
const std::string &value)
|
||||
{
|
||||
|
||||
@@ -57,7 +57,6 @@ protected:
|
||||
|
||||
bool IsTempVarInUse(const std::string &id) const;
|
||||
void SetTempVarValue(const std::string &id, const std::string &value);
|
||||
void CopyTempVarValuesFrom(const MacroSegment &other);
|
||||
|
||||
template<typename T, typename = std::enable_if_t<
|
||||
std::is_same<std::decay_t<T>, bool>::value>>
|
||||
|
||||
@@ -428,13 +428,9 @@ bool Macro::RunActionsHelper(
|
||||
}
|
||||
if (action->Enabled()) {
|
||||
action->LogAction();
|
||||
std::shared_ptr<MacroAction> actionCopy;
|
||||
action->WithLock([&action, &actionCopy]() {
|
||||
actionCopy = action->Copy();
|
||||
});
|
||||
bool actionResult = actionCopy->PerformAction();
|
||||
action->WithLock([&action, &actionCopy]() {
|
||||
action->CopyTempVarValuesFrom(*actionCopy);
|
||||
bool actionResult = false;
|
||||
action->WithLock([&action, &actionResult]() {
|
||||
actionResult = action->PerformAction();
|
||||
});
|
||||
actionsExecutedSuccessfully =
|
||||
actionsExecutedSuccessfully && actionResult;
|
||||
|
||||
@@ -66,4 +66,15 @@ void Lockable::WithLock(const std::function<void()> &func)
|
||||
func();
|
||||
}
|
||||
|
||||
SuspendLock::SuspendLock(Lockable &lockable)
|
||||
: _mtx(static_cast<std::mutex &>(lockable._mtx))
|
||||
{
|
||||
_mtx.unlock();
|
||||
}
|
||||
|
||||
SuspendLock::~SuspendLock()
|
||||
{
|
||||
_mtx.lock();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -51,6 +51,24 @@ public:
|
||||
|
||||
private:
|
||||
PerInstanceMutex _mtx;
|
||||
|
||||
friend class SuspendLock;
|
||||
};
|
||||
|
||||
// RAII guard that temporarily releases a Lockable's per-segment lock.
|
||||
// Use this inside PerformAction() / CheckCondition() to unblock the UI
|
||||
// during long-running operations while still running on the original segment.
|
||||
// The caller MUST be holding the lock (i.e. be inside WithLock) when
|
||||
// constructing this object; the lock is re-acquired on destruction.
|
||||
class EXPORT SuspendLock {
|
||||
public:
|
||||
SuspendLock(Lockable &lockable);
|
||||
~SuspendLock();
|
||||
SuspendLock(const SuspendLock &) = delete;
|
||||
SuspendLock &operator=(const SuspendLock &) = delete;
|
||||
|
||||
private:
|
||||
std::mutex &_mtx;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -95,7 +95,7 @@ static void waitHelper(std::unique_lock<std::mutex> *lock, Macro *macro,
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionMedia::PerformActionHelper(obs_source_t *source) const
|
||||
void MacroActionMedia::PerformActionHelper(obs_source_t *source)
|
||||
{
|
||||
obs_media_state state = obs_source_media_get_state(source);
|
||||
|
||||
@@ -130,6 +130,7 @@ void MacroActionMedia::PerformActionHelper(obs_source_t *source) const
|
||||
SeekToPercentage(source);
|
||||
break;
|
||||
case Action::WAIT_FOR_PLAYBACK_STOP: {
|
||||
SuspendLock suspendLock(*this);
|
||||
std::unique_lock<std::mutex> lock(*GetMutex());
|
||||
waitHelper(&lock, GetMacro(), source);
|
||||
break;
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
SceneSelection _scene;
|
||||
|
||||
private:
|
||||
void PerformActionHelper(obs_source_t *) const;
|
||||
void PerformActionHelper(obs_source_t *);
|
||||
void SeekToPercentage(obs_source_t *source) const;
|
||||
|
||||
static bool _registered;
|
||||
|
||||
@@ -159,7 +159,10 @@ bool MacroActionPlayAudio::PerformAction()
|
||||
|
||||
if (_waitForCompletion) {
|
||||
SetMacroAbortWait(false);
|
||||
waitForPlaybackToEnd(GetMacro(), source, maxMs);
|
||||
{
|
||||
SuspendLock suspendLock(*this);
|
||||
waitForPlaybackToEnd(GetMacro(), source, maxMs);
|
||||
}
|
||||
deactivatePlayback(source, wantsOutput);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -15,9 +15,20 @@ bool MacroActionRun::_registered = MacroActionFactory::Register(
|
||||
bool MacroActionRun::PerformAction()
|
||||
{
|
||||
if (_wait) {
|
||||
_procConfig.StartProcessAndWait(_timeout.Milliseconds());
|
||||
SetTempVarValues();
|
||||
|
||||
// Snapshot config before releasing the lock for the blocking wait
|
||||
auto procConfig = _procConfig;
|
||||
const auto timeout = _timeout.Milliseconds();
|
||||
{
|
||||
SuspendLock suspendLock(*this);
|
||||
procConfig.StartProcessAndWait(timeout);
|
||||
}
|
||||
SetTempVarValue("process.id", procConfig.GetProcessId());
|
||||
SetTempVarValue("process.exitCode",
|
||||
procConfig.GetProcessExitCode());
|
||||
SetTempVarValue("process.stream.output",
|
||||
procConfig.GetProcessOutputStream());
|
||||
SetTempVarValue("process.stream.error",
|
||||
procConfig.GetProcessErrorStream());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,8 +57,11 @@ bool MacroActionWait::PerformAction()
|
||||
std::chrono::milliseconds((int)(sleepDuration * 1000));
|
||||
|
||||
SetMacroAbortWait(false);
|
||||
std::unique_lock<std::mutex> lock(*GetMutex());
|
||||
waitHelper(&lock, GetMacro(), time);
|
||||
{
|
||||
SuspendLock suspendLock(*this);
|
||||
std::unique_lock<std::mutex> lock(*GetMutex());
|
||||
waitHelper(&lock, GetMacro(), time);
|
||||
}
|
||||
|
||||
return !MacroWaitShouldAbort();
|
||||
}
|
||||
|
||||
@@ -112,48 +112,56 @@ static URLInfo getURLInfo(const std::string &input, bool keepParams)
|
||||
|
||||
bool MacroActionHttp::PerformAction()
|
||||
{
|
||||
// Capture all config while holding the segment lock
|
||||
const auto [host, path] = getURLInfo(_url, !_setParams);
|
||||
|
||||
httplib::Client cli(host);
|
||||
setTimeout(cli, _timeout);
|
||||
const auto params = _setParams ? getParams(_params) : httplib::Params();
|
||||
const auto headers = _setHeaders ? getHeaders(_headers)
|
||||
: httplib::Headers();
|
||||
const auto method = _method;
|
||||
const std::string body = _body;
|
||||
const std::string contentType = _contentType;
|
||||
|
||||
// Release the segment lock for the blocking network call
|
||||
httplib::Result response;
|
||||
switch (_method) {
|
||||
case MacroActionHttp::Method::GET:
|
||||
response = cli.Get(path, params, headers);
|
||||
break;
|
||||
case MacroActionHttp::Method::POST: {
|
||||
const auto pathWithParam =
|
||||
httplib::append_query_params(path, params);
|
||||
response =
|
||||
cli.Post(pathWithParam, headers, _body, _contentType);
|
||||
break;
|
||||
}
|
||||
case MacroActionHttp::Method::PUT: {
|
||||
const auto pathWithParam =
|
||||
httplib::append_query_params(path, params);
|
||||
response = cli.Put(pathWithParam, headers, _body, _contentType);
|
||||
break;
|
||||
}
|
||||
case MacroActionHttp::Method::PATCH: {
|
||||
const auto pathWithParam =
|
||||
httplib::append_query_params(path, params);
|
||||
response =
|
||||
cli.Patch(pathWithParam, headers, _body, _contentType);
|
||||
break;
|
||||
}
|
||||
case MacroActionHttp::Method::DELETE: {
|
||||
const auto pathWithParam =
|
||||
httplib::append_query_params(path, params);
|
||||
response =
|
||||
cli.Delete(pathWithParam, headers, _body, _contentType);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
{
|
||||
SuspendLock suspendLock(*this);
|
||||
switch (method) {
|
||||
case MacroActionHttp::Method::GET:
|
||||
response = cli.Get(path, params, headers);
|
||||
break;
|
||||
case MacroActionHttp::Method::POST: {
|
||||
const auto pathWithParam =
|
||||
httplib::append_query_params(path, params);
|
||||
response = cli.Post(pathWithParam, headers, body,
|
||||
contentType);
|
||||
break;
|
||||
}
|
||||
case MacroActionHttp::Method::PUT: {
|
||||
const auto pathWithParam =
|
||||
httplib::append_query_params(path, params);
|
||||
response = cli.Put(pathWithParam, headers, body,
|
||||
contentType);
|
||||
break;
|
||||
}
|
||||
case MacroActionHttp::Method::PATCH: {
|
||||
const auto pathWithParam =
|
||||
httplib::append_query_params(path, params);
|
||||
response = cli.Patch(pathWithParam, headers, body,
|
||||
contentType);
|
||||
break;
|
||||
}
|
||||
case MacroActionHttp::Method::DELETE: {
|
||||
const auto pathWithParam =
|
||||
httplib::append_query_params(path, params);
|
||||
response = cli.Delete(pathWithParam, headers, body,
|
||||
contentType);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (VerboseLoggingEnabled() && !response) {
|
||||
|
||||
@@ -35,6 +35,7 @@ bool MacroActionScript::PerformAction()
|
||||
return true;
|
||||
}
|
||||
|
||||
SuspendLock suspendLock(static_cast<MacroAction &>(*this));
|
||||
(void)SendTriggerSignal();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ bool MacroConditionScript::CheckCondition()
|
||||
return false;
|
||||
}
|
||||
|
||||
SuspendLock suspendLock(static_cast<MacroCondition &>(*this));
|
||||
return SendTriggerSignal();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user