chenluhua1980
2026-01-05 6a0f19f181b6968d86aca3885662aabedefc3a3e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#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; }
        void setId(std::string& id);
        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);
        bool removePjPointer(const std::string& id);
        bool addPjPointer(CProcessJob* pj);
        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<ValidationIssue>& CControlJob::issues();
        void clearIssues();
 
        // ¡ª¡ª 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(std::string reason);          // ·ÇÖÕ̬ -> 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;
    };
}