#include "stdafx.h" #include "CControlJob.h" #include #include "SerializeUtil.h" static inline std::string trimCopy(std::string s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !std::isspace(static_cast(c)); })); s.erase(std::find_if(s.rbegin(), s.rend(), [](char c) { return !std::isspace(static_cast(c)); }).base(), s.end()); return s; } namespace SERVO { CControlJob::CControlJob() { } CControlJob::CControlJob(std::string cjId) : m_cjId(trimCopy(std::move(cjId))) { clampString(m_cjId, MAX_ID_LEN); } CControlJob::CControlJob(CControlJob& src) { m_cjId = src.m_cjId; clampString(m_cjId, MAX_ID_LEN); m_priority = src.m_priority; m_pjIds = src.m_pjIds; m_state = src.m_state; m_failReason = src.m_failReason; m_tQueued = src.m_tQueued; m_tStart = src.m_tStart; m_tEnd = src.m_tEnd; } void CControlJob::setId(std::string& id) { m_cjId = trimCopy(id); clampString(m_cjId, MAX_ID_LEN); } bool CControlJob::addPJ(const std::string& pjId) { if (pjId.empty()) return false; auto id = pjId; auto it = std::find(m_pjIds.begin(), m_pjIds.end(), id); if (it != m_pjIds.end()) return false; clampString(id, MAX_ID_LEN); m_pjIds.push_back(std::move(id)); return true; } bool CControlJob::addPJs(const std::vector& ids) { bool added = false; for (auto& s : ids) added |= addPJ(s); return added; } bool CControlJob::setPJs(const std::vector& pjs) { m_pjs = pjs; return true; } bool CControlJob::addPjPointer(CProcessJob* pj) { for (auto item : m_pjs) { if (item->id().compare(pj->id()) == 0) return false; } m_pjs.push_back(pj); return true; } bool CControlJob::removePjPointer(const std::string& id) { for(auto iter = m_pjs.begin(); iter != m_pjs.end(); ++iter) { if ((*iter)->id().compare(id) == 0) { m_pjs.erase(iter); return true; } } return false; } bool CControlJob::removePJ(const std::string& pjId) { auto it = std::find(m_pjIds.begin(), m_pjIds.end(), pjId); if (it == m_pjIds.end()) return false; m_pjIds.erase(it); return true; } bool CControlJob::containsPJ(const std::string& pjId) const { return std::find(m_pjIds.begin(), m_pjIds.end(), pjId) != m_pjIds.end(); } const std::vector& CControlJob::issues() { return m_issues; } void CControlJob::clearIssues() { m_issues.clear(); } bool CControlJob::validateForCreate( const std::function& canCreateCjFn, const std::function& getPjExistsFn, const std::function& canJoinFn ) { m_issues.clear(); auto add = [&](uint32_t code, std::string msg) { m_issues.push_back({ code, std::move(msg) }); }; // ÊÇ·ñÄÜ´´½¨CJ, ÓÉÉϲã¸ù¾Ýµ±Ç°ÈÎÎñ£¬»úÆ÷״̬µÈ¼ìÑé uint32_t cc; std::string mm; if (!canCreateCjFn(cc, mm)) { add(cc, mm); } // CJID »ù´¡Ð£Ñé if (m_cjId.empty()) add(1101, "CJID empty"); if (!asciiPrintable(m_cjId)) add(1102, "CJID has non-printable chars"); // PJ ÁбíУÑé if (m_pjIds.empty()) add(1110, "PRJOBLIST empty"); for (const auto& pj : m_pjIds) { if (!getPjExistsFn(pj)) add(1111, "PJ not found: " + pj); else if (!canJoinFn(pj)) add(1112, "PJ not joinable: " + pj); } return m_issues.empty(); } // Ó¦Óô´½¨/¸üУ¨ÓÃÓÚ S14F9 ¡ú S14F10 ·¾¶£© CControlJob::CreateResult CControlJob::applyCreate( const CreateRequest& req, const std::function& getPjExistsFn, const std::function& canJoinFn ) { CreateResult r; // ¸²¸ÇÓÅÏȼ¶£¨ÈçÌṩ£© if (req.priority.has_value()) { m_priority = *req.priority; } // Öð PJ Åж¨ for (const auto& pjIdRaw : req.requestedPjIds) { std::string pjId = trimCopy(pjIdRaw); clampString(pjId, MAX_ID_LEN); if (!getPjExistsFn(pjId)) { r.errors.push_back({ 2001, "PRJOBLIST: " + pjId + " not found" }); continue; } if (!canJoinFn(pjId)) { r.errors.push_back({ 2002, "PRJOBLIST: " + pjId + " not joinable (state)" }); continue; } if (containsPJ(pjId)) { // ÒÑÔÚÁÐ±í£¬ÊÓ×÷³É¹¦£¨Ãݵȣ© r.acceptedPjIds.push_back(pjId); continue; } // ¼ÓÈë CJ m_pjIds.push_back(pjId); r.acceptedPjIds.push_back(std::move(pjId)); } // ¹é²¢ ACK if (r.errors.empty()) r.objack = 0; // È«³É¹¦ else if (!r.acceptedPjIds.empty()) r.objack = 1; // ²¿·Ö³É¹¦ else r.objack = 2; // ȫʧ°Ü return r; } // ¡ª¡ª ״̬»ú ¡ª¡ª // bool CControlJob::queue() { if (m_state != CJState::NoState) return false; markQueued(); return true; } bool CControlJob::start() { if (m_state != CJState::Queued) return false; m_state = CJState::Executing; if (!m_tStart.has_value()) markStart(); return true; } bool CControlJob::pause() { if (m_state != CJState::Executing) return false; m_state = CJState::Paused; return true; } bool CControlJob::resume() { if (m_state != CJState::Paused) return false; m_state = CJState::Executing; return true; } bool CControlJob::complete() { if (m_state != CJState::Executing && m_state != CJState::Paused) return false; m_state = CJState::Completed; markEnd(); return true; } bool CControlJob::abort(std::string reason) { if (m_state == CJState::Completed || m_state == CJState::Aborted || m_state == CJState::Failed) return false; m_failReason = trimCopy(reason); clampString(m_failReason, 128); m_state = CJState::Aborted; markEnd(); return true; } bool CControlJob::fail(std::string reason) { m_failReason = trimCopy(reason); clampString(m_failReason, 128); m_state = CJState::Failed; markEnd(); return true; } // ¡ª¡ª ¾ÛºÏÍê³ÉÅÐ¶Ï ¡ª¡ª // bool CControlJob::tryAggregateComplete( const std::function& isPjCompletedFn ) { if (m_pjIds.empty()) return false; for (const auto& pj : m_pjIds) { if (!isPjCompletedFn(pj)) return false; } // ËùÓÐ PJ ÒÑÍê³É ¡ú CJ Íê³É return complete(); } // ¡ª¡ª ʱ¼ä´Á ¡ª¡ª // void CControlJob::markQueued() { m_state = CJState::Queued; m_tQueued = std::chrono::system_clock::now(); } void CControlJob::markStart() { m_tStart = std::chrono::system_clock::now(); } void CControlJob::markEnd() { m_tEnd = std::chrono::system_clock::now(); } // ¡ª¡ª ¹¤¾ß ¡ª¡ª // void CControlJob::clampString(std::string& s, size_t maxLen) { if (s.size() > maxLen) s.resize(maxLen); } bool CControlJob::asciiPrintable(const std::string& s) { return std::all_of(s.begin(), s.end(), [](unsigned char c) { return c >= 0x20 && c <= 0x7E; }); } void CControlJob::serialize(std::ostream& os) const { write_pod(os, CJ_MAGIC); write_pod(os, CJ_VERSION); // ±êʶ/ÓÅÏȼ¶/״̬/ʧ°ÜÔ­Òò write_string(os, id()); // »ò m_cjId write_pod(os, priority()); // »ò m_priority write_pod(os, static_cast(state())); // »ò m_state write_string(os, failReason()); // »ò m_failReason // ʱ¼ä´Á write_opt_time(os, tQueued()); write_opt_time(os, tStart()); write_opt_time(os, tEnd()); // ¹ØÁª PJ Áбí write_vec_str(os, pjIds()); // »ò m_pjIds } bool CControlJob::deserialize(std::istream& is, CControlJob& out, std::string* err) { auto fail = [&](const char* msg) { if (err) *err = msg; return false; }; uint32_t magic = 0; if (!read_pod(is, magic)) return fail("read CJ magic"); if (magic != CJ_MAGIC) return fail("bad CJ magic"); uint16_t ver = 0; if (!read_pod(is, ver)) return fail("read CJ version"); if (ver != CJ_VERSION) return fail("unsupported CJ version"); std::string cjId; if (!read_string(is, cjId)) return fail("read CJID"); uint8_t prio = 0; if (!read_pod(is, prio)) return fail("read Priority"); uint8_t st = 0; if (!read_pod(is, st)) return fail("read State"); std::string failText; if (!read_string(is, failText)) return fail("read failReason"); std::optional tQ, tS, tE; if (!read_opt_time(is, tQ)) return fail("read tQueued"); if (!read_opt_time(is, tS)) return fail("read tStart"); if (!read_opt_time(is, tE)) return fail("read tEnd"); std::vector pjIds; if (!read_vec_str(is, pjIds)) return fail("read PJIDs"); // ¡ª¡ª д»Ø¶ÔÏó£¨Ö±½Ó¸Ä³ÉÔ±£¬»òͨ¹ý setter£©¡ª¡ª // ÈôÄãÓÐ setter£ºout.setId(...)/setPriority(...)/setState(...)/setFailReason(...) out = CControlJob(cjId); out.setPriority(prio); out.m_state = static_cast(st); out.m_failReason = std::move(failText); out.m_tQueued = std::move(tQ); out.m_tStart = std::move(tS); out.m_tEnd = std::move(tE); out.m_pjIds = std::move(pjIds); return true; } std::string CControlJob::getStateText() { switch (m_state) { case SERVO::CJState::NoState: return "NoState"; break; case SERVO::CJState::Queued: return "Queued"; break; case SERVO::CJState::Executing: return "Executing"; break; case SERVO::CJState::Paused: return "Paused"; break; case SERVO::CJState::Completed: return "Completed"; break; case SERVO::CJState::Aborted: return "Aborted"; break; case SERVO::CJState::Failed: return "Failed"; break; default: break; } return ""; } }