This commit is contained in:
fwastring 2025-10-13 10:38:50 +02:00
commit ab9a0bd4e2
183 changed files with 20701 additions and 0 deletions

142
src/framework/bridgetask.h Normal file
View file

@ -0,0 +1,142 @@
// Copyright (c) 2019 The Swedish Internet Foundation
// Written by Göran Andersson <initgoran@gmail.com>
#pragma once
#include <string>
#include "task.h"
/// \brief
/// Tasks may use a bridge to communicate with an application running
/// outside the event loop.
///
/// This class provides an abstract interface for a _bridge_ which facilitates
/// communication between a task and code running outside the event loop.
/// The code might run in another process or thread. The actual
/// means of communication might be sockets or pipes, or shared variables in
/// the case of threads, or something else entirely.
///
/// The task running in the event loop is called the _agent_, and the outside
/// aplication is called the _client_.
///
/// To use this class, you must
/// - derive from this class
/// - implement the sendMessageToClient method
/// - implement a way for the client to send messages back, and pass those
/// messages through the sendMsgToAgent method
/// - if you override the start() method, call BridgeTask::start() first
/// - create an agent object and a bridge object
/// - add the bridge object to the event loop
/// The agent task will be aborted when the bridge task is finished.
/// If you need timers (e.g. for polling), you must override the start() method
/// below and your start() method must call BridgeTask::start().
///
/// When there is a message from the client to the agent, the agent's
/// Task::handleExecution method will be called with two parameters:
/// the bridge object and a message.
///
/// Typically, the agent's Task::handleExecution method checks if the
/// first parameter can be cast to a BridgeTask pointer.
/// If so, the second parameter is a message from the client.
/// When the first message from the client arrives, the agent stores
/// the pointer to the bridge in case it needs to send messages back.
class BridgeTask : public Task {
public:
/// \brief
/// Create a bridge to the given agent task.
///
/// If the agent task isn't available yet, it must be added using
/// BridgeTask::setAgent before the bridge is added to the EventLoop.
BridgeTask(Task *agent = nullptr) : Task("Bridge"), the_agent(agent) {
killChildTaskWhenFinished();
}
/// \brief
/// Will add the agent task to the EventLoop.
///
/// *Note!* If you override this method, it should be called explicitly by
/// the overriding method!
double start() override;
/// If the agent dies, a special message will be sent to notify the client.
void taskFinished(Task *task) override {
if (task == the_agent) {
if (!task->result().empty()) {
log() << "Agent terminated";
sendMsgToClient(agentTerminatedMessage(task->result()));
the_agent = nullptr;
}
die();
}
}
/// If the agent task was created after the bridge, it must be added using
/// this method _before_ the bridge is added to the EventLoop.
void setAgent(Task *agent) {
if (!the_agent && !hasStarted())
the_agent = agent;
else
err_log() << "cannot set agent";
}
/// Terminate the bridge task.
void die() {
setResult("");
}
/// The agent will call this to pass messages to the client.
virtual void sendMsgToClient(const std::string &msg) = 0;
/// \brief Format a message to the agent.
///
/// Recommended way to format messages to the agent: a method name,
/// and "arguments" stored in a JSON object.
///
/// *Note!* The method name must not contain any special chararcters.
static std::string msgToAgent(const std::string &method,
const std::string &jsonobj = "{}") {
return "{\"method\": \"" + method + "\", \"args\": " + jsonobj + "}";
}
/// Return true if msg is formatted as a note that the agent has terminated
/// and that there will be no more messages.
static bool isAgentTerminatedMessage(const std::string &msg) {
return (msg.substr(0, 12) == "AGENT EXIT: ");
}
/// Format a message to signal that the Agent is gone.
static std::string agentTerminatedMessage(const std::string &err_msg) {
return "AGENT EXIT: " + err_msg;
}
/// \brief Format a message to the client.
///
/// Recommended way to format messages to the client: an event (or method)
/// name, and "arguments" stored in a JSON object.
///
/// *Note!* The method name must not contain any special chararcters.
void sendMsgToClient(const std::string &method, const std::string &jsonobj) {
sendMsgToClient("{\"event\": \"" + method +
"\", \"args\": " + jsonobj + "}");
}
virtual ~BridgeTask() override;
protected:
/// Send message to the agent.
void sendMsgToAgent(const std::string &msg) {
executeHandler(the_agent, msg);
if (msg.substr(0, terminate_msg.size()) == terminate_msg)
die();
}
/// Format and send message to the agent.
void sendMsgToAgent(const std::string &method, const std::string &jsonobj) {
sendMsgToAgent(msgToAgent(method, jsonobj));
}
private:
Task *the_agent;
//const std::string quit_msg = "quit";
const std::string terminate_msg = "{\"method\": \"terminate\"";
};