mrDarker
2025-08-26 43c7dc211f10851480352b12bd01f3443079bb01
SourceCode/Bond/Servo/CControlJob.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,153 @@
#pragma once
#include <string>
#include <vector>
#include <algorithm>
#include <cstdint>
#include <optional>
#include <chrono>
#include <functional>
#include "ProcessJob.h"
// â€”— æ ‡å‡†/项目内约定的属性名(A:40)——
// è¯´æ˜Žï¼šä¸ä»¥ç©ºæ ¼å¼€å¤´/结尾,字符范围 0x20-0x7E,且不能包含 > : ? * ~
inline constexpr const char* CJ_ATTR_CJID = "CJID";       // A:n
inline constexpr const char* CJ_ATTR_PRIORITY = "Priority";   // U1
inline constexpr const char* CJ_ATTR_PRJOBLIST = "PRJOBLIST";  // L:n of A:n (PJID[])
namespace SERVO {
    /// CJ çŠ¶æ€ï¼ˆè´´è¿‘ E40 è¯­ä¹‰ï¼‰
    enum class CJState : uint8_t {
        NoState = 0,
        Queued,
        Executing,
        Paused,
        Completed,
        Aborted,
        Failed
    };
    /// åˆ›å»º/修改结果中的错误项
    struct CJError {
        uint16_t    code;   // è‡ªå®šä¹‰é”™è¯¯ç ï¼ˆä¾‹ï¼š2001=PJ_NOT_FOUND, 2002=NOT_JOINABLE)
        std::string text;   // å»ºè®®åŒ…含定位信息(ATTRID/PJID)
    };
    /// CControlJob:Control Job ç®¡ç†ç±»
    class CControlJob {
    public:
        CControlJob();
        explicit CControlJob(std::string cjId);
        explicit CControlJob(CControlJob& src);
        // â€”— åŸºæœ¬å±žæ€§ â€”— //
        const std::string& id()     const noexcept { return m_cjId; }
        CJState            state()  const noexcept { return m_state; }
        uint8_t            priority() const noexcept { return m_priority; }
        void               setPriority(uint8_t p) noexcept { m_priority = p; }
        std::string getStateText();
        // â€”— PJ åˆ—表维护(去重)—— //
        bool addPJ(const std::string& pjId);                // å·²å­˜åœ¨åˆ™ä¸é‡å¤æ·»åŠ 
        bool addPJs(const std::vector<std::string>& ids);   // è¿”回是否有新增
        bool removePJ(const std::string& pjId);             // å­˜åœ¨åˆ™ç§»é™¤
        bool containsPJ(const std::string& pjId) const;
        const std::vector<std::string>& pjIds() const noexcept { return m_pjIds; }
        bool setPJs(const std::vector<CProcessJob*>& pjs);
        void clearPJs() { m_pjIds.clear(); }
        const std::vector<CProcessJob*>& getPjs() { return m_pjs; };
        // â€”— æ ¡éªŒ â€”— //
        struct ValidationIssue { uint32_t code; std::string text; };
        // æ ¡éªŒ CJ æ˜¯å¦å¯åˆ›å»º/更新(例如:PJ æ˜¯å¦å­˜åœ¨ã€æ˜¯å¦å¯åŠ å…¥ï¼‰
        // getPjExistsFn(pjId)->bool:PJ æ˜¯å¦å­˜åœ¨
        // canJoinFn(pjId)->bool     ï¼šPJ å½“前是否允许加入 CJ(如 PJ çŠ¶æ€ä¸º Queued ç­‰ï¼‰
        bool validateForCreate(
            const std::function<bool(uint32_t& code, std::string& msg)>& canCreateCjFn,
            const std::function<bool(const std::string&)>& getPjExistsFn,
            const std::function<bool(const std::string&)>& canJoinFn
        );
        const std::vector<CControlJob::ValidationIssue>& CControlJob::issues();
        // â€”— S14F9 â†’ S14F10 çš„“应用结果”模型 â€”— //
        struct CreateRequest {
            std::optional<uint8_t>           priority;      // è‹¥æœ‰åˆ™è¦†ç›–
            std::vector<std::string>         requestedPjIds;// æƒ³è¦ç»‘定的 PJ åˆ—表
        };
        struct CreateResult {
            std::vector<std::string> acceptedPjIds; // æˆåŠŸç»‘å®šçš„ PJ(用于回显 PRJOBLIST)
            std::vector<CJError>     errors;        // å¤±è´¥é¡¹ï¼ˆå« PJID è¯´æ˜Žï¼‰
            uint8_t                  objack{ 0 };     // 0=全成功, 1=部分成功, 2=全失败
        };
        // åº”用创建/更新请求:只绑定允许的 PJ,并生成 OBJACK/错误清单
        // getPjExistsFn / canJoinFn åŒä¸Š
        CreateResult applyCreate(
            const CreateRequest& req,
            const std::function<bool(const std::string&)>& getPjExistsFn,
            const std::function<bool(const std::string&)>& canJoinFn
        );
        // â€”— çŠ¶æ€æœº â€”— //
        bool queue();          // NoState -> Queued
        bool start();          // Queued  -> Executing
        bool pause();          // Executing -> Paused
        bool resume();         // Paused -> Executing
        bool complete();       // Executing/Paused -> Completed
        bool abort();          // éžç»ˆæ€ -> Aborted
        bool fail(std::string reason); // ä»»æ„ -> Failed
        const std::string& failReason() const noexcept { return m_failReason; }
        // â€”— æ—¶é—´æˆ³ â€”— //
        std::optional<std::chrono::system_clock::time_point> tQueued() const { return m_tQueued; }
        std::optional<std::chrono::system_clock::time_point> tStart()  const { return m_tStart; }
        std::optional<std::chrono::system_clock::time_point> tEnd()    const { return m_tEnd; }
        // â€”— æ±‡æ€»çŠ¶æ€è¾…åŠ©ï¼ˆå¯é€‰ï¼‰â€”â€” //
        // æ ¹æ®å¤–部提供的“PJ æ˜¯å¦å·²å®Œæˆâ€åˆ¤æ–­ï¼Œå°è¯•把 CJ èšåˆç½®ä¸º Completed。
        // isPjCompletedFn(pjId)->bool
        bool tryAggregateComplete(const std::function<bool(const std::string&)>& isPjCompletedFn);
        // å·¥å…·ï¼šç»Ÿä¸€å­—符串限制
        static void clampString(std::string& s, size_t maxLen);
        static bool asciiPrintable(const std::string& s);
        static constexpr uint32_t CJ_MAGIC = 0x434A5031; // "CJP1"
        static constexpr uint16_t CJ_VERSION = 0x0001;
        void serialize(std::ostream& os) const;
        static bool deserialize(std::istream& is, CControlJob& out, std::string* err = nullptr);
    private:
        void markQueued();
        void markStart();
        void markEnd();
    protected:
        // â€”— æ ‡è¯† & é…ç½® â€”— //
        std::string m_cjId;
        uint8_t     m_priority{ 5 }; // ç¼ºçœä¼˜å…ˆçº§ï¼ˆè‡ªå®šï¼‰
        // â€”— ç»„成 â€”— //
        std::vector<std::string> m_pjIds;
        std::vector<CProcessJob*> m_pjs;
        // â€”— çŠ¶æ€ / æ–‡æœ¬ â€”— //
        CJState     m_state{ CJState::NoState };
        std::string m_failReason;
        // â€”— æ—¶é—´æˆ³ â€”— //
        std::optional<std::chrono::system_clock::time_point> m_tQueued;
        std::optional<std::chrono::system_clock::time_point> m_tStart;
        std::optional<std::chrono::system_clock::time_point> m_tEnd;
        // â€”— ç»Ÿä¸€çº¦æŸ â€”— //
        static constexpr size_t MAX_ID_LEN = 64; // CJID / PJID ç­‰
        // é”™è¯¯åˆ—表
        std::vector<ValidationIssue> m_issues;
    };
}