webserver_service.hpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #pragma once
  2. #include <memory>
  3. #include <mutex>
  4. #include <set>
  5. #include "http_server.hpp"
  6. #include "websocket_server.hpp"
  7. #include "auth/jwt_utils.hpp"
  8. #include "auth/auth_store.hpp"
  9. #include "auth/auth_middleware.hpp"
  10. #include "runners/runner_registry.hpp"
  11. #include "runners/load_balancer.hpp"
  12. #include "storage/storage_client.hpp"
  13. #include "config/config_loader.hpp"
  14. #include "scheduler/workflow_scheduler.hpp"
  15. #include "scheduler/database_watcher.hpp"
  16. #include "api/project_controller.hpp"
  17. #include "auth/access.hpp"
  18. #include "retention/retention_service.hpp"
  19. #include "settings/settings_store.hpp"
  20. #include "settings/settings_accessor.hpp"
  21. namespace smartbotic::webserver::nodes {
  22. class NodeStore;
  23. }
  24. namespace smartbotic::webserver::grpc {
  25. class NodeSyncServer;
  26. class CredentialServer;
  27. class WorkflowControlServiceImpl;
  28. }
  29. namespace smartbotic::credentials {
  30. class CredentialStore;
  31. }
  32. namespace smartbotic::webserver::api {
  33. class AuthController;
  34. class UserController;
  35. class WorkflowController;
  36. class WorkflowGroupController;
  37. class ExecutionController;
  38. class FileController;
  39. class ProxyController;
  40. class NodeController;
  41. class RunnerController;
  42. class WebhookController;
  43. class DatabaseController;
  44. class CredentialController;
  45. class CertificateController;
  46. class SettingsController;
  47. }
  48. namespace smartbotic::webserver {
  49. // Server-side projection of the executions collection. The list endpoint reads
  50. // this instead of the collection so the database never sends nodeExecutions,
  51. // which carry base64 images and dwarf every other field.
  52. inline constexpr const char* kExecutionsSummaryView = "executions_summary";
  53. struct CredentialsConfig {
  54. std::string master_key = "dev-key-change-in-production";
  55. int pbkdf2_iterations = 100000;
  56. };
  57. struct WebServerServiceConfig {
  58. int http_port = 8080;
  59. int node_sync_port = 9002; // gRPC port for node sync service
  60. int credential_service_port = 9003; // gRPC port for credential service
  61. std::string static_files_path = "./webui/dist";
  62. std::string database_address = "localhost:9004";
  63. std::string database_project = "smartbotic-automation";
  64. int max_upload_mb = 32;
  65. // Bounds WebhookController's dispatch pool, which runs immediate-mode
  66. // form submissions off the request thread. The form endpoint is public
  67. // and unauthenticated by design, so these keep a burst of submissions
  68. // from spawning without limit.
  69. int form_dispatch_threads = 4;
  70. int form_dispatch_queue_capacity = 32;
  71. // Bounds WorkflowController's dispatch pool, which runs the editor's
  72. // "Execute" button off the request thread for the same reason the form
  73. // pool above exists - the runner's ExecuteWorkflow RPC is synchronous
  74. // regardless of wait_for_completion. This path is authenticated, so the
  75. // exhaustion risk is lower than the form pool's, but bounding it still
  76. // costs nothing.
  77. int workflow_dispatch_threads = 4;
  78. int workflow_dispatch_queue_capacity = 32;
  79. runners::RunnerRegistryConfig runner_config;
  80. runners::LoadBalancerConfig load_balancer_config;
  81. auth::JwtUtils::Config jwt_config;
  82. CredentialsConfig credentials_config;
  83. };
  84. class WebServerService {
  85. public:
  86. explicit WebServerService(const WebServerServiceConfig& config);
  87. ~WebServerService();
  88. static WebServerServiceConfig loadConfig(const std::filesystem::path& path);
  89. void start();
  90. void stop();
  91. // Access components
  92. auth::AuthStore& authStore() { return *auth_store_; }
  93. runners::RunnerRegistry& runnerRegistry() { return *runner_registry_; }
  94. WebSocketServer& wsServer() { return *ws_server_; }
  95. WorkflowScheduler& scheduler() { return *scheduler_; }
  96. private:
  97. void setupRoutes();
  98. void loadScheduledWorkflows();
  99. void ensureExecutionsSummaryView();
  100. void executeScheduledWorkflow(const std::string& workflow_id,
  101. const std::string& trigger_node_id,
  102. const std::string& trigger_type,
  103. const nlohmann::json& extra_trigger_data = nlohmann::json::object());
  104. // Runs the workflow a failing workflow nominates as its error handler, if
  105. // it names one. Called when an execution reports failure.
  106. // Count how many times in a row a workflow has failed, and switch it off
  107. // when that passes what its settings allow. The count lives on the workflow
  108. // rather than in memory: a restart must not forgive a workflow that has
  109. // been failing for an hour, and the number is worth being able to see.
  110. void noteExecutionOutcome(const std::string& workflow_id,
  111. const std::string& execution_id,
  112. bool failed,
  113. const std::string& error);
  114. // Close executions a runner cannot possibly still be running. A runner
  115. // holds what it is executing in memory, so anything recorded as running
  116. // against one that has just come up has nobody left to finish it - and
  117. // would sit at "running" until somebody noticed and pressed Stop.
  118. void reconcileOrphanedExecutions(const std::string& runner_id,
  119. const std::string& address);
  120. void runErrorWorkflow(const std::string& failed_workflow_id,
  121. const std::string& failed_execution_id,
  122. const std::string& error_message);
  123. WebServerServiceConfig config_;
  124. // Core components
  125. std::unique_ptr<storage::StorageClient> storage_;
  126. // Built right after storage_ and before anything that reads a live
  127. // setting - a live accessor handed out before this exists would be a
  128. // reference to nothing.
  129. std::unique_ptr<settings::SettingsStore> settings_store_;
  130. std::unique_ptr<settings::SettingsAccessor> settings_;
  131. std::unique_ptr<auth::JwtUtils> jwt_;
  132. std::unique_ptr<auth::AuthStore> auth_store_;
  133. std::unique_ptr<auth::AuthMiddleware> auth_middleware_;
  134. std::unique_ptr<runners::RunnerRegistry> runner_registry_;
  135. std::unique_ptr<runners::LoadBalancer> load_balancer_;
  136. std::unique_ptr<nodes::NodeStore> node_store_;
  137. std::unique_ptr<retention::RetentionService> retention_;
  138. std::unique_ptr<credentials::CredentialStore> credential_store_;
  139. // Servers
  140. std::unique_ptr<HttpServer> http_server_;
  141. std::unique_ptr<WebSocketServer> ws_server_;
  142. std::unique_ptr<grpc::NodeSyncServer> node_sync_server_;
  143. std::unique_ptr<grpc::CredentialServer> credential_server_;
  144. std::unique_ptr<grpc::WorkflowControlServiceImpl> workflow_control_service_;
  145. // Scheduler
  146. std::unique_ptr<WorkflowScheduler> scheduler_;
  147. std::unique_ptr<DatabaseWatcher> db_watcher_;
  148. std::unique_ptr<auth::AccessControl> access_;
  149. std::unique_ptr<api::ProjectController> project_ctrl_;
  150. // Controllers (must outlive httplib::Server callbacks)
  151. std::unique_ptr<api::AuthController> auth_ctrl_;
  152. std::unique_ptr<api::UserController> user_ctrl_;
  153. std::unique_ptr<api::WorkflowController> workflow_ctrl_;
  154. std::unique_ptr<api::WorkflowGroupController> workflow_group_ctrl_;
  155. std::unique_ptr<api::ExecutionController> execution_ctrl_;
  156. std::unique_ptr<api::FileController> file_ctrl_;
  157. std::unique_ptr<api::ProxyController> proxy_ctrl_;
  158. // Execution events can arrive more than once for the same execution, so a
  159. // failure is remembered briefly to keep one failure from starting the error
  160. // workflow twice.
  161. std::mutex handled_failures_mutex_;
  162. std::set<std::string> handled_failures_;
  163. std::unique_ptr<api::NodeController> node_ctrl_;
  164. std::unique_ptr<api::RunnerController> runner_ctrl_;
  165. std::unique_ptr<api::WebhookController> webhook_ctrl_;
  166. std::unique_ptr<api::DatabaseController> database_ctrl_;
  167. std::unique_ptr<api::CredentialController> credential_ctrl_;
  168. std::unique_ptr<api::CertificateController> certificate_ctrl_;
  169. std::unique_ptr<api::SettingsController> settings_ctrl_;
  170. };
  171. } // namespace smartbotic::webserver