Compare commits

..

2 Commits

Author SHA1 Message Date
WarmUpTill
ba38b8bf27 Don't block UI while executing long runnig actions
Some checks failed
debian-build / build (push) Has been cancelled
Push to master / Check Formatting 🔍 (push) Has been cancelled
Push to master / Build Project 🧱 (push) Has been cancelled
Push to master / Create Release 🛫 (push) Has been cancelled
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 commit df42538319.
Revert "Don't block UI while running actions"
This reverts commit a01d26e25d.
2026-04-04 21:14:05 +02:00
WarmUpTill
38513735dd Refresh available interactable soruces on show 2026-04-04 21:14:05 +02:00
15 changed files with 111 additions and 68 deletions

View File

@@ -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)
{

View File

@@ -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>>

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -259,6 +259,12 @@ void MacroActionSourceInteractionEdit::AcceptRecorded(
_stepList->SetSteps(_entryData->_steps);
}
void MacroActionSourceInteractionEdit::showEvent(QShowEvent *event)
{
const QSignalBlocker b(this);
UpdateEntryData();
}
void MacroActionSourceInteractionEdit::SetCurrentStepEditor(int row)
{
if (_stepEditor) {

View File

@@ -62,6 +62,9 @@ private slots:
signals:
void HeaderInfoChanged(const QString &);
protected:
void showEvent(QShowEvent *event) override;
private:
void SetCurrentStepEditor(int row);

View File

@@ -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();
}

View File

@@ -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) {

View File

@@ -35,6 +35,7 @@ bool MacroActionScript::PerformAction()
return true;
}
SuspendLock suspendLock(static_cast<MacroAction &>(*this));
(void)SendTriggerSignal();
return true;
}

View File

@@ -36,6 +36,7 @@ bool MacroConditionScript::CheckCondition()
return false;
}
SuspendLock suspendLock(static_cast<MacroCondition &>(*this));
return SendTriggerSignal();
}