mirror of
				https://github.com/Telecominfraproject/wlan-cloud-owprov.git
				synced 2025-10-30 18:18:03 +00:00 
			
		
		
		
	Merge pull request #39 from Telecominfraproject/main
Fix: https://telecominfraproject.atlassian.net/browse/WIFI-10070
This commit is contained in:
		| @@ -125,7 +125,6 @@ add_executable(owprov | |||||||
|         src/RESTAPI/RESTAPI_db_helpers.h |         src/RESTAPI/RESTAPI_db_helpers.h | ||||||
|         src/JobController.cpp src/JobController.h |         src/JobController.cpp src/JobController.h | ||||||
|         src/JobRegistrations.cpp |         src/JobRegistrations.cpp | ||||||
|         src/storage/storage_jobs.cpp src/storage/storage_jobs.h |  | ||||||
|         src/storage/storage_maps.cpp src/storage/storage_maps.h |         src/storage/storage_maps.cpp src/storage/storage_maps.h | ||||||
|         src/RESTAPI/RESTAPI_map_handler.cpp src/RESTAPI/RESTAPI_map_handler.h |         src/RESTAPI/RESTAPI_map_handler.cpp src/RESTAPI/RESTAPI_map_handler.h | ||||||
|         src/RESTAPI/RESTAPI_map_list_handler.cpp src/RESTAPI/RESTAPI_map_list_handler.h |         src/RESTAPI/RESTAPI_map_list_handler.cpp src/RESTAPI/RESTAPI_map_list_handler.h | ||||||
|   | |||||||
| @@ -30,8 +30,29 @@ namespace OpenWifi { | |||||||
|         Utils::SetThreadName("job-controller"); |         Utils::SetThreadName("job-controller"); | ||||||
|         while(Running_) { |         while(Running_) { | ||||||
|             Poco::Thread::trySleep(2000); |             Poco::Thread::trySleep(2000); | ||||||
|  |  | ||||||
|  |             std::lock_guard G(Mutex_); | ||||||
|  |  | ||||||
|  |             for(auto &job:jobs_) { | ||||||
|  |                 if(job!=nullptr) { | ||||||
|  |                     if(job->Started()==0 && Pool_.used()<Pool_.available()) { | ||||||
|  |                         job->Logger().information(fmt::format("Starting {}: {}",job->JobId(),job->Name())); | ||||||
|  |                         job->Start(); | ||||||
|  |                         Pool_.start(*job); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             for(auto it = jobs_.begin(); it!=jobs_.end();) { | ||||||
|  |                 if(*it!=nullptr && (*it)->Completed()!=0) { | ||||||
|  |                     auto tmp = it; | ||||||
|  |                     (*it)->Logger().information(fmt::format("Completed {}: {}",(*it)->JobId(),(*it)->Name())); | ||||||
|  |                     it = jobs_.erase(it); | ||||||
|  |                     delete *tmp; | ||||||
|  |                 } else { | ||||||
|  |                     ++it; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -7,99 +7,45 @@ | |||||||
| #include <vector> | #include <vector> | ||||||
| #include <utility> | #include <utility> | ||||||
| #include <functional> | #include <functional> | ||||||
|  | #include <list> | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     class Job { |     class Job : public Poco::Runnable { | ||||||
|         public: |     public: | ||||||
|             struct Parameter { |         Job(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) : | ||||||
|                 std::string name; |             jobId_(JobID), | ||||||
|                 std::string value; |             name_(name), | ||||||
|                 inline void to_json(Poco::JSON::Object &Obj) const { |             parameters_(parameters), | ||||||
|                     RESTAPI_utils::field_to_json(Obj,"name",name); |             when_(when), | ||||||
|                     RESTAPI_utils::field_to_json(Obj,"value",value); |             userinfo_(UI), | ||||||
|                 } |             Logger_(L) | ||||||
|  |         {}; | ||||||
|  |  | ||||||
|                 inline bool from_json(const Poco::JSON::Object::Ptr &Obj) { |         virtual void run() = 0; | ||||||
|                     try { |         [[nodiscard]] std::string Name() const { return name_; } | ||||||
|                         RESTAPI_utils::field_from_json(Obj,"name",name); |         const SecurityObjects::UserInfo & UserInfo() const { return userinfo_; } | ||||||
|                         RESTAPI_utils::field_from_json(Obj,"value",value); |         Poco::Logger & Logger() { return Logger_; } | ||||||
|                         return true; |         const std::string & JobId() const { return jobId_; } | ||||||
|                     } catch (...) { |         const std::string & Parameter(int x) const { return parameters_[x];} | ||||||
|  |         uint64_t When() const { return when_; } | ||||||
|  |         void Start() { started_ = OpenWifi::Now(); } | ||||||
|  |         uint64_t Started() const { return started_; } | ||||||
|  |         uint64_t Completed() const { return completed_;} | ||||||
|  |         void Complete() { completed_ = OpenWifi::Now(); } | ||||||
|  |  | ||||||
|                     } |     private: | ||||||
|                     return false; |         std::string                 jobId_; | ||||||
|                 } |         std::string                 name_; | ||||||
|             }; |         std::vector<std::string>    parameters_; | ||||||
|  |         uint64_t                    when_=0; | ||||||
|             struct Status { |         SecurityObjects::UserInfo   userinfo_; | ||||||
|                 Types::UUID_t   UUID; |         Poco::Logger                & Logger_; | ||||||
|                 uint64_t        Start = 0 ; |         uint64_t                    started_=0; | ||||||
|                 uint64_t        Progress = 0 ; |         uint64_t                    completed_=0; | ||||||
|                 uint64_t        Completed = 0 ; |  | ||||||
|                 std::string     CurrentDisplay; |  | ||||||
|             }; |  | ||||||
|  |  | ||||||
|             struct Result { |  | ||||||
|                 int         Error=0; |  | ||||||
|                 std::string Reason; |  | ||||||
|             }; |  | ||||||
|  |  | ||||||
|             typedef std::vector<Parameter>       Parameters; |  | ||||||
|             typedef std::vector<Parameters>      ParametersVec; |  | ||||||
|             typedef std::function<bool(const Parameters &Parameters, Result &Result, bool &Retry)>  WorkerFunction; |  | ||||||
|             typedef std::vector<Status>          Statuses; |  | ||||||
|  |  | ||||||
|             Job(std::string Title, |  | ||||||
|                          std::string Description, |  | ||||||
|                          std::string RegisteredName, |  | ||||||
|                          ParametersVec Parameters, |  | ||||||
|                          [[maybe_unused]] bool Parallel=true) : |  | ||||||
|                     Title_(std::move(Title)), |  | ||||||
|                     Description_(std::move(Description)), |  | ||||||
|                     RegisteredName_(std::move(RegisteredName)), |  | ||||||
|                     Parameters_(std::move(Parameters)) |  | ||||||
|                 { |  | ||||||
|                     UUID_ = MicroService::instance().CreateUUID(); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             [[nodiscard]] inline const Types::UUID_t & ID() const { return UUID_; } |  | ||||||
|  |  | ||||||
|         private: |  | ||||||
|             Types::UUID_t       UUID_; |  | ||||||
|             std::string         Title_; |  | ||||||
|             std::string         Description_; |  | ||||||
|             std::string         RegisteredName_; |  | ||||||
|             ParametersVec       Parameters_; |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     class JobRegistry { |  | ||||||
|         public: |  | ||||||
|             static auto instance() { |  | ||||||
|                 static auto instance_ = new JobRegistry; |  | ||||||
|                 return instance_; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             inline void RegisterJobType( const std::string & JobType, Job::WorkerFunction Function) { |  | ||||||
|                     JobTypes_[JobType] = std::move(Function); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             inline bool Execute(const std::string &JobType, const Job::Parameters & Params, Job::Result &Result, bool & Retry) { |  | ||||||
|                 auto Hint = JobTypes_.find(JobType); |  | ||||||
|                 if(Hint != end(JobTypes_)) { |  | ||||||
|                     Hint->second(Params, Result, Retry); |  | ||||||
|                     return true; |  | ||||||
|                 } |  | ||||||
|                 return false; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         private: |  | ||||||
|             std::map<std::string,Job::WorkerFunction>  JobTypes_; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     inline auto JobRegistry() { return JobRegistry::instance(); } |  | ||||||
|  |  | ||||||
|     class JobController : public SubSystemServer, Poco::Runnable { |     class JobController : public SubSystemServer, Poco::Runnable { | ||||||
|         public: |         public: | ||||||
|             static auto instance() { |             static auto instance() { | ||||||
| @@ -112,11 +58,16 @@ namespace OpenWifi { | |||||||
|             void run() override; |             void run() override; | ||||||
|             inline void wakeup() { Thr_.wakeUp(); } |             inline void wakeup() { Thr_.wakeUp(); } | ||||||
|  |  | ||||||
|             bool JobList(Job::Statuses & Statuses); |             void AddJob( Job* newJob ) { | ||||||
|  |                 std::lock_guard G(Mutex_); | ||||||
|  |                 jobs_.push_back(newJob); | ||||||
|  |             } | ||||||
|  |  | ||||||
|         private: |         private: | ||||||
|             Poco::Thread            Thr_; |             Poco::Thread                        Thr_; | ||||||
|             std::atomic_bool        Running_=false; |             std::atomic_bool                    Running_=false; | ||||||
|  |             std::list<Job *>                    jobs_; | ||||||
|  |             Poco::ThreadPool                    Pool_; | ||||||
|  |  | ||||||
|         JobController() noexcept: |         JobController() noexcept: | ||||||
|             SubSystemServer("JobController", "JOB-SVR", "job") |             SubSystemServer("JobController", "JOB-SVR", "job") | ||||||
|   | |||||||
| @@ -228,10 +228,10 @@ namespace OpenWifi{ | |||||||
|  |  | ||||||
|             Poco::JSON::Object  Answer; |             Poco::JSON::Object  Answer; | ||||||
|             SNL.serialNumbers = Existing.devices; |             SNL.serialNumbers = Existing.devices; | ||||||
|  |             auto JobId = MicroService::instance().CreateUUID(); | ||||||
|             auto Task = new VenueConfigUpdater(UUID,UserInfo_.userinfo,0,Logger()); |             Types::StringVec Parameters{UUID};; | ||||||
|             auto JobId = Task->Start(); |             auto NewJob = new VenueConfigUpdater(JobId,"VenueConfigurationUpdater", Parameters, 0, UserInfo_.userinfo, Logger()); | ||||||
|  |             JobController()->AddJob(dynamic_cast<Job*>(NewJob)); | ||||||
|             SNL.to_json(Answer); |             SNL.to_json(Answer); | ||||||
|             Answer.set("jobId",JobId); |             Answer.set("jobId",JobId); | ||||||
|             return ReturnObject(Answer); |             return ReturnObject(Answer); | ||||||
| @@ -242,10 +242,10 @@ namespace OpenWifi{ | |||||||
|  |  | ||||||
|             Poco::JSON::Object  Answer; |             Poco::JSON::Object  Answer; | ||||||
|             SNL.serialNumbers = Existing.devices; |             SNL.serialNumbers = Existing.devices; | ||||||
|  |             auto JobId = MicroService::instance().CreateUUID(); | ||||||
|             auto Task = new VenueUpgrade(UUID,UserInfo_.userinfo,0,Logger()); |             Types::StringVec Parameters{UUID};; | ||||||
|             auto JobId = Task->Start(); |             auto NewJob = new VenueUpgrade(JobId,"VenueFirmwareUpgrade", Parameters, 0, UserInfo_.userinfo, Logger()); | ||||||
|  |             JobController()->AddJob(dynamic_cast<Job*>(NewJob)); | ||||||
|             SNL.to_json(Answer); |             SNL.to_json(Answer); | ||||||
|             Answer.set("jobId",JobId); |             Answer.set("jobId",JobId); | ||||||
|             return ReturnObject(Answer); |             return ReturnObject(Answer); | ||||||
| @@ -256,10 +256,10 @@ namespace OpenWifi{ | |||||||
|  |  | ||||||
|             Poco::JSON::Object  Answer; |             Poco::JSON::Object  Answer; | ||||||
|             SNL.serialNumbers = Existing.devices; |             SNL.serialNumbers = Existing.devices; | ||||||
|  |             auto JobId = MicroService::instance().CreateUUID(); | ||||||
|             auto Task = new VenueRebooter(UUID,UserInfo_.userinfo,0,Logger()); |             Types::StringVec Parameters{UUID};; | ||||||
|             auto JobId = Task->Start(); |             auto NewJob = new VenueRebooter(JobId,"VenueRebooter", Parameters, 0, UserInfo_.userinfo, Logger()); | ||||||
|  |             JobController()->AddJob(dynamic_cast<Job*>(NewJob)); | ||||||
|             SNL.to_json(Answer); |             SNL.to_json(Answer); | ||||||
|             Answer.set("jobId",JobId); |             Answer.set("jobId",JobId); | ||||||
|             return ReturnObject(Answer); |             return ReturnObject(Answer); | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ | |||||||
| #include "APConfig.h" | #include "APConfig.h" | ||||||
| #include "sdks/SDK_gw.h" | #include "sdks/SDK_gw.h" | ||||||
| #include "framework/WebSocketClientNotifications.h" | #include "framework/WebSocketClientNotifications.h" | ||||||
|  | #include "JobController.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
| @@ -82,45 +83,21 @@ namespace OpenWifi { | |||||||
|         inline Poco::Logger & Logger() { return Logger_; } |         inline Poco::Logger & Logger() { return Logger_; } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     class VenueConfigUpdater: public Poco::Runnable { |     class VenueConfigUpdater: public Job { | ||||||
|     public: |     public: | ||||||
|         explicit VenueConfigUpdater(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) : |         VenueConfigUpdater(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) : | ||||||
|             VenueUUID_(VenueUUID), |                 Job(JobID, name, parameters, when, UI, L) { | ||||||
|             UI_(UI), |  | ||||||
|             When_(When), |  | ||||||
|             Logger_(L) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline std::string Start() { |         inline virtual void run() { | ||||||
|             JobId_ = MicroService::CreateUUID(); |             std::string                 VenueUUID_; | ||||||
|             Worker_.start(*this); |  | ||||||
|             return JobId_; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     private: |  | ||||||
|         std::string                 VenueUUID_; |  | ||||||
|         SecurityObjects::UserInfo   UI_; |  | ||||||
|         uint64_t                    When_; |  | ||||||
|         Poco::Logger                &Logger_; |  | ||||||
|         Poco::Thread                Worker_; |  | ||||||
|         std::string                 JobId_; |  | ||||||
|         Poco::ThreadPool            Pool_{2,16,300}; |  | ||||||
|  |  | ||||||
|         inline Poco::Logger & Logger() { return Logger_; } |  | ||||||
|  |  | ||||||
|         inline void run() final { |  | ||||||
|  |  | ||||||
|             Utils::SetThreadName("venue-update"); |             Utils::SetThreadName("venue-update"); | ||||||
|  |             VenueUUID_ = Parameter(0); | ||||||
|             if(When_ && When_>OpenWifi::Now()) |  | ||||||
|                 Poco::Thread::trySleep( (long) (When_ - OpenWifi::Now()) * 1000 ); |  | ||||||
|  |  | ||||||
|             WebSocketNotification<WebSocketNotificationJobContent> N; |             WebSocketNotification<WebSocketNotificationJobContent> N; | ||||||
|  |  | ||||||
|             Logger().information(fmt::format("Job {} Starting.", JobId_)); |  | ||||||
|  |  | ||||||
|             ProvObjects::Venue  Venue; |             ProvObjects::Venue  Venue; | ||||||
|             uint64_t Updated = 0, Failed = 0 , BadConfigs = 0 ; |             uint64_t Updated = 0, Failed = 0 , BadConfigs = 0 ; | ||||||
|             if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { |             if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { | ||||||
| @@ -131,7 +108,7 @@ namespace OpenWifi { | |||||||
|                 }; |                 }; | ||||||
|  |  | ||||||
|                 N.content.title = fmt::format("Updating {} configurations", Venue.info.name); |                 N.content.title = fmt::format("Updating {} configurations", Venue.info.name); | ||||||
|                 N.content.jobId = JobId_; |                 N.content.jobId = JobId(); | ||||||
|  |  | ||||||
|                 std::array<tState,MaxThreads> Tasks; |                 std::array<tState,MaxThreads> Tasks; | ||||||
|  |  | ||||||
| @@ -200,19 +177,18 @@ namespace OpenWifi { | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 N.content.details = fmt::format("Job {} Completed: {} updated, {} failed to update, {} bad configurations. ", |                 N.content.details = fmt::format("Job {} Completed: {} updated, {} failed to update, {} bad configurations. ", | ||||||
|                                                 JobId_, Updated ,Failed, BadConfigs); |                                                 JobId(), Updated ,Failed, BadConfigs); | ||||||
|  |  | ||||||
|             } else { |             } else { | ||||||
|                 N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); |                 N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); | ||||||
|                 Logger().warning(N.content.details); |                 Logger().warning(N.content.details); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             WebSocketClientNotificationVenueUpdateJobCompletionToUser(UI_.email, N); |             WebSocketClientNotificationVenueUpdateJobCompletionToUser(UserInfo().email, N); | ||||||
|             Logger().information(fmt::format("Job {} Completed: {} updated, {} failed to update , {} bad configurations.", |             Logger().information(fmt::format("Job {} Completed: {} updated, {} failed to update , {} bad configurations.", | ||||||
|                                              JobId_, Updated ,Failed, BadConfigs)); |                                              JobId(), Updated ,Failed, BadConfigs)); | ||||||
|             Utils::SetThreadName("free"); |             Utils::SetThreadName("free"); | ||||||
|  |             Complete(); | ||||||
|             delete this; |  | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ | |||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
| #include "APConfig.h" | #include "APConfig.h" | ||||||
| #include "sdks/SDK_gw.h" | #include "sdks/SDK_gw.h" | ||||||
|  | #include "JobController.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
| @@ -48,44 +49,19 @@ namespace OpenWifi { | |||||||
|         inline Poco::Logger & Logger() { return Logger_; } |         inline Poco::Logger & Logger() { return Logger_; } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     class VenueRebooter: public Poco::Runnable { |     class VenueRebooter: public Job { | ||||||
|     public: |     public: | ||||||
|         explicit VenueRebooter(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) : |         VenueRebooter(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) : | ||||||
|                 VenueUUID_(VenueUUID), |                 Job(JobID, name, parameters, when, UI, L) { | ||||||
|                 UI_(UI), |  | ||||||
|                 When_(When), |  | ||||||
|                 Logger_(L) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline std::string Start() { |         inline virtual void run() final { | ||||||
|             JobId_ = MicroService::CreateUUID(); |  | ||||||
|             Worker_.start(*this); |  | ||||||
|             return JobId_; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     private: |  | ||||||
|         std::string                 VenueUUID_; |  | ||||||
|         SecurityObjects::UserInfo   UI_; |  | ||||||
|         uint64_t                    When_; |  | ||||||
|         Poco::Logger                &Logger_; |  | ||||||
|         Poco::Thread                Worker_; |  | ||||||
|         std::string                 JobId_; |  | ||||||
|         Poco::ThreadPool            Pool_{2,16,300}; |  | ||||||
|  |  | ||||||
|         inline Poco::Logger & Logger() { return Logger_; } |  | ||||||
|  |  | ||||||
|         inline void run() final { |  | ||||||
|  |  | ||||||
|             Utils::SetThreadName("venue-reboot"); |             Utils::SetThreadName("venue-reboot"); | ||||||
|  |  | ||||||
|             if(When_ && When_>OpenWifi::Now()) |  | ||||||
|                 Poco::Thread::trySleep( (long) (When_ - OpenWifi::Now()) * 1000 ); |  | ||||||
|  |  | ||||||
|             WebSocketClientNotificationVenueRebootList_t        N; |             WebSocketClientNotificationVenueRebootList_t        N; | ||||||
|  |             auto VenueUUID_ = Parameter(0); | ||||||
|             Logger().information(fmt::format("Job {} Starting.", JobId_)); |  | ||||||
|  |  | ||||||
|             ProvObjects::Venue  Venue; |             ProvObjects::Venue  Venue; | ||||||
|             uint64_t rebooted_ = 0, failed_ = 0; |             uint64_t rebooted_ = 0, failed_ = 0; | ||||||
| @@ -97,7 +73,7 @@ namespace OpenWifi { | |||||||
|                 }; |                 }; | ||||||
|  |  | ||||||
|                 N.content.title = fmt::format("Rebooting {} devices.", Venue.info.name); |                 N.content.title = fmt::format("Rebooting {} devices.", Venue.info.name); | ||||||
|                 N.content.jobId = JobId_; |                 N.content.jobId = JobId(); | ||||||
|  |  | ||||||
|                 std::array<tState,MaxThreads> Tasks; |                 std::array<tState,MaxThreads> Tasks; | ||||||
|  |  | ||||||
| @@ -162,20 +138,18 @@ namespace OpenWifi { | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 N.content.details = fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.", |                 N.content.details = fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.", | ||||||
|                                                 JobId_, rebooted_ ,failed_); |                                                 JobId(), rebooted_ ,failed_); | ||||||
|  |  | ||||||
|             } else { |             } else { | ||||||
|                 N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); |                 N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); | ||||||
|                 Logger().warning(N.content.details); |                 Logger().warning(N.content.details); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             WebSocketClientNotificationVenueRebootCompletionToUser(UI_.email,N); |             WebSocketClientNotificationVenueRebootCompletionToUser(UserInfo().email,N); | ||||||
|             Logger().information(fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.", |             Logger().information(fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.", | ||||||
|                                              JobId_, rebooted_ ,failed_)); |                                              JobId(), rebooted_ ,failed_)); | ||||||
|  |  | ||||||
|             Utils::SetThreadName("free"); |             Utils::SetThreadName("free"); | ||||||
|  |             Complete(); | ||||||
|             delete this; |  | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ | |||||||
| #include "APConfig.h" | #include "APConfig.h" | ||||||
| #include "sdks/SDK_gw.h" | #include "sdks/SDK_gw.h" | ||||||
| #include "sdks/SDK_fms.h" | #include "sdks/SDK_fms.h" | ||||||
|  | #include "JobController.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class VenueDeviceUpgrade : public Poco::Runnable { |     class VenueDeviceUpgrade : public Poco::Runnable { | ||||||
| @@ -69,45 +70,20 @@ namespace OpenWifi { | |||||||
|         inline Poco::Logger & Logger() { return Logger_; } |         inline Poco::Logger & Logger() { return Logger_; } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     class VenueUpgrade: public Poco::Runnable { |     class VenueUpgrade: public Job { | ||||||
|     public: |     public: | ||||||
|         explicit VenueUpgrade(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) : |         VenueUpgrade(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) : | ||||||
|                 VenueUUID_(VenueUUID), |                 Job(JobID, name, parameters, when, UI, L) { | ||||||
|                 UI_(UI), |  | ||||||
|                 When_(When), |  | ||||||
|                 Logger_(L) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline std::string Start() { |         inline virtual void run() final { | ||||||
|             JobId_ = MicroService::CreateUUID(); |  | ||||||
|             Worker_.start(*this); |  | ||||||
|             return JobId_; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     private: |  | ||||||
|         std::string                 VenueUUID_; |  | ||||||
|         SecurityObjects::UserInfo   UI_; |  | ||||||
|         uint64_t                    When_; |  | ||||||
|         Poco::Logger                &Logger_; |  | ||||||
|         Poco::Thread                Worker_; |  | ||||||
|         std::string                 JobId_; |  | ||||||
|         Poco::ThreadPool            Pool_{2,16,300}; |  | ||||||
|  |  | ||||||
|         inline Poco::Logger & Logger() { return Logger_; } |  | ||||||
|  |  | ||||||
|         inline void run() final { |  | ||||||
|  |  | ||||||
|             Utils::SetThreadName("venue-upgr"); |             Utils::SetThreadName("venue-upgr"); | ||||||
|  |             auto VenueUUID_ = Parameter(0); | ||||||
|             if(When_ && When_>OpenWifi::Now()) |  | ||||||
|                 Poco::Thread::trySleep( (long) (When_ - OpenWifi::Now()) * 1000 ); |  | ||||||
|  |  | ||||||
|             WebSocketClientNotificationVenueRebootList_t        N; |             WebSocketClientNotificationVenueRebootList_t        N; | ||||||
|  |  | ||||||
|             Logger().information(fmt::format("Job {} Starting.", JobId_)); |  | ||||||
|  |  | ||||||
|             ProvObjects::Venue  Venue; |             ProvObjects::Venue  Venue; | ||||||
|             uint64_t upgraded_ = 0, failed_ = 0; |             uint64_t upgraded_ = 0, failed_ = 0; | ||||||
|             if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { |             if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { | ||||||
| @@ -118,7 +94,7 @@ namespace OpenWifi { | |||||||
|                 }; |                 }; | ||||||
|  |  | ||||||
|                 N.content.title = fmt::format("Upgrading {} devices.", Venue.info.name); |                 N.content.title = fmt::format("Upgrading {} devices.", Venue.info.name); | ||||||
|                 N.content.jobId = JobId_; |                 N.content.jobId = JobId(); | ||||||
|  |  | ||||||
|                 std::array<tState,MaxThreads> Tasks; |                 std::array<tState,MaxThreads> Tasks; | ||||||
|                 ProvObjects::DeviceRules    Rules; |                 ProvObjects::DeviceRules    Rules; | ||||||
| @@ -186,19 +162,19 @@ namespace OpenWifi { | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 N.content.details = fmt::format("Job {} Completed: {} upgraded, {} failed to upgrade.", |                 N.content.details = fmt::format("Job {} Completed: {} upgraded, {} failed to upgrade.", | ||||||
|                                                 JobId_, upgraded_ ,failed_); |                                                 JobId(), upgraded_ ,failed_); | ||||||
|  |  | ||||||
|             } else { |             } else { | ||||||
|                 N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); |                 N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); | ||||||
|                 Logger().warning(N.content.details); |                 Logger().warning(N.content.details); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             WebSocketClientNotificationVenueRebootCompletionToUser(UI_.email,N); |             WebSocketClientNotificationVenueRebootCompletionToUser(UserInfo().email,N); | ||||||
|             Logger().information(fmt::format("Job {} Completed: {} upgraded, {} failed to upgrade.", |             Logger().information(fmt::format("Job {} Completed: {} upgraded, {} failed to upgrade.", | ||||||
|                                              JobId_, upgraded_ ,failed_)); |                                              JobId(), upgraded_ ,failed_)); | ||||||
|             Utils::SetThreadName("free"); |             Utils::SetThreadName("free"); | ||||||
|  |  | ||||||
|             delete this; |             Complete(); | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| @@ -27,11 +27,6 @@ namespace OpenWifi { | |||||||
|     inline uint64_t Now() { return std::time(nullptr); }; |     inline uint64_t Now() { return std::time(nullptr); }; | ||||||
| } | } | ||||||
|  |  | ||||||
| namespace OpenWifi::Utils { |  | ||||||
|     std::vector<unsigned char> base64decode(const std::string& input); |  | ||||||
|     std::string base64encode(const unsigned char *input, uint32_t size); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| using namespace std::chrono_literals; | using namespace std::chrono_literals; | ||||||
|  |  | ||||||
| #include "Poco/Util/Application.h" | #include "Poco/Util/Application.h" | ||||||
| @@ -243,11 +238,6 @@ namespace OpenWifi::RESTAPI_utils { | |||||||
|         Obj.set(Field,Value); |         Obj.set(Field,Value); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Poco::Data::BLOB &Value) { |  | ||||||
|         auto Result = Utils::base64encode((const unsigned char *)Value.rawContent(),Value.size()); |  | ||||||
|         Obj.set(Field,Result); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringPairVec & S) { |     inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringPairVec & S) { | ||||||
|         Poco::JSON::Array   Array; |         Poco::JSON::Array   Array; | ||||||
|         for(const auto &i:S) { |         for(const auto &i:S) { | ||||||
| @@ -344,12 +334,12 @@ namespace OpenWifi::RESTAPI_utils { | |||||||
|  |  | ||||||
|     inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, double & Value) { |     inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, double & Value) { | ||||||
|         if(Obj->has(Field) && !Obj->isNull(Field)) |         if(Obj->has(Field) && !Obj->isNull(Field)) | ||||||
|             Value = (double)Obj->get(Field); |             Value = (double) Obj->get(Field); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, float & Value) { |     inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, float & Value) { | ||||||
|         if(Obj->has(Field) && !Obj->isNull(Field)) |         if(Obj->has(Field) && !Obj->isNull(Field)) | ||||||
|             Value = (float)Obj->get(Field); |             Value = (float) Obj->get(Field); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, bool &Value) { |     inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, bool &Value) { | ||||||
| @@ -384,14 +374,7 @@ namespace OpenWifi::RESTAPI_utils { | |||||||
|  |  | ||||||
|     inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint64_t &Value) { |     inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint64_t &Value) { | ||||||
|         if(Obj->has(Field) && !Obj->isNull(Field)) |         if(Obj->has(Field) && !Obj->isNull(Field)) | ||||||
|             Value = (uint64_t)Obj->get(Field); |             Value = (uint64_t ) Obj->get(Field); | ||||||
|     } |  | ||||||
|  |  | ||||||
|     inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Poco::Data::BLOB &Value) { |  | ||||||
|         if(Obj->has(Field) && !Obj->isNull(Field)) { |  | ||||||
|             auto Result = Utils::base64decode(Obj->get(Field).toString()); |  | ||||||
|             Value.assignRaw((const unsigned char *)&Result[0],Result.size()); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::StringPairVec &Vec) { |     inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::StringPairVec &Vec) { | ||||||
| @@ -2081,17 +2064,6 @@ namespace OpenWifi { | |||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, Poco::Data::BLOB &Value) { |  | ||||||
|             if(O->has(Field)) { |  | ||||||
|                 std::string Content = O->get(Field).toString(); |  | ||||||
|                 auto DecodedBlob = Utils::base64decode(Content); |  | ||||||
|                 Value.assignRaw((const unsigned char *)&DecodedBlob[0],DecodedBlob.size()); |  | ||||||
|                 return true; |  | ||||||
|             } |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         template <typename T> bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, const T &value, T & assignee) { |         template <typename T> bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, const T &value, T & assignee) { | ||||||
|             if(O->has(Field)) { |             if(O->has(Field)) { | ||||||
|                 assignee = value; |                 assignee = value; | ||||||
| @@ -5020,8 +4992,12 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         for(const auto &client:Clients_) { |         for(const auto &client:Clients_) { | ||||||
|             if(client.second.second == UserName) { |             if(client.second.second == UserName) { | ||||||
|                 if(client.second.first->Send(Payload)) | 				try { | ||||||
|                     Sent++; | 					if (client.second.first->Send(Payload)) | ||||||
|  | 						Sent++; | ||||||
|  | 				} catch (...) { | ||||||
|  | 					return false; | ||||||
|  | 				} | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         return Sent>0; |         return Sent>0; | ||||||
| @@ -5043,70 +5019,70 @@ namespace OpenWifi { | |||||||
|         int flags; |         int flags; | ||||||
|         int n; |         int n; | ||||||
|         bool Done=false; |         bool Done=false; | ||||||
|         Poco::Buffer<char>			IncomingFrame(0); | 		try { | ||||||
|         n = WS_->receiveFrame(IncomingFrame, flags); | 			Poco::Buffer<char> IncomingFrame(0); | ||||||
|         auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK; | 			n = WS_->receiveFrame(IncomingFrame, flags); | ||||||
|  | 			auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK; | ||||||
|  |  | ||||||
|         if(n==0) { | 			if (n == 0) { | ||||||
|             return delete this; | 				return delete this; | ||||||
|         } | 			} | ||||||
|  |  | ||||||
|         switch(Op) { | 			switch (Op) { | ||||||
|             case Poco::Net::WebSocket::FRAME_OP_PING: { | 			case Poco::Net::WebSocket::FRAME_OP_PING: { | ||||||
|                 WS_->sendFrame("", 0, | 				WS_->sendFrame("", 0, | ||||||
|                                (int)Poco::Net::WebSocket::FRAME_OP_PONG | | 							   (int)Poco::Net::WebSocket::FRAME_OP_PONG | | ||||||
|                                (int)Poco::Net::WebSocket::FRAME_FLAG_FIN); | 								   (int)Poco::Net::WebSocket::FRAME_FLAG_FIN); | ||||||
|             } | 			} break; | ||||||
|                 break; | 			case Poco::Net::WebSocket::FRAME_OP_PONG: { | ||||||
|             case Poco::Net::WebSocket::FRAME_OP_PONG: { | 			} break; | ||||||
|             } | 			case Poco::Net::WebSocket::FRAME_OP_CLOSE: { | ||||||
|                 break; | 				Logger().warning(Poco::format("CLOSE(%s): Client is closing its connection.", Id_)); | ||||||
|             case Poco::Net::WebSocket::FRAME_OP_CLOSE: { | 				Done = true; | ||||||
|                 Logger().warning(Poco::format("CLOSE(%s): Client is closing its connection.",Id_)); | 			} break; | ||||||
|                 Done=true; | 			case Poco::Net::WebSocket::FRAME_OP_TEXT: { | ||||||
|             } | 				IncomingFrame.append(0); | ||||||
|                 break; | 				if (!Authenticated_) { | ||||||
|             case Poco::Net::WebSocket::FRAME_OP_TEXT: { | 					std::string Frame{IncomingFrame.begin()}; | ||||||
|                 IncomingFrame.append(0); | 					auto Tokens = Utils::Split(Frame, ':'); | ||||||
|                 if(!Authenticated_) { | 					bool Expired = false, Contacted = false; | ||||||
|                     std::string Frame{IncomingFrame.begin()}; | 					if (Tokens.size() == 2 && | ||||||
|                     auto Tokens = Utils::Split(Frame,':'); | 						AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) { | ||||||
|                     bool Expired = false, Contacted = false; | 						Authenticated_ = true; | ||||||
|                     if(Tokens.size()==2 && AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) { | 						std::string S{"Welcome! Bienvenue! Bienvenidos!"}; | ||||||
|                         Authenticated_=true; | 						WS_->sendFrame(S.c_str(), S.size()); | ||||||
|                         std::string S{"Welcome! Bienvenue! Bienvenidos!"}; | 						WebSocketClientServer()->SetUser(Id_, UserInfo_.userinfo.email); | ||||||
|                         WS_->sendFrame(S.c_str(),S.size()); | 					} else { | ||||||
|                         WebSocketClientServer()->SetUser(Id_,UserInfo_.userinfo.email); | 						std::string S{"Invalid token. Closing connection."}; | ||||||
|                     } else { | 						WS_->sendFrame(S.c_str(), S.size()); | ||||||
|                         std::string S{"Invalid token. Closing connection."}; | 						Done = true; | ||||||
|                         WS_->sendFrame(S.c_str(),S.size()); | 					} | ||||||
|                         Done=true; |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 } else { | 				} else { | ||||||
|                     try { | 					try { | ||||||
|                         Poco::JSON::Parser P; | 						Poco::JSON::Parser P; | ||||||
|                         auto Obj = P.parse(IncomingFrame.begin()) | 						auto Obj = | ||||||
|                                 .extract<Poco::JSON::Object::Ptr>(); | 							P.parse(IncomingFrame.begin()).extract<Poco::JSON::Object::Ptr>(); | ||||||
|                         std::string Answer; | 						std::string Answer; | ||||||
|                         if(Processor_!= nullptr) | 						if (Processor_ != nullptr) | ||||||
|                             Processor_->Processor(Obj, Answer, Done); | 							Processor_->Processor(Obj, Answer, Done); | ||||||
|                         if (!Answer.empty()) | 						if (!Answer.empty()) | ||||||
|                             WS_->sendFrame(Answer.c_str(), (int) Answer.size()); | 							WS_->sendFrame(Answer.c_str(), (int)Answer.size()); | ||||||
|                         else { | 						else { | ||||||
|                             WS_->sendFrame("{}", 2); | 							WS_->sendFrame("{}", 2); | ||||||
|                         } | 						} | ||||||
|                     } catch (const Poco::JSON::JSONException & E) { | 					} catch (const Poco::JSON::JSONException &E) { | ||||||
|                         Logger().log(E); | 						Logger().log(E); | ||||||
|                     } | 						Done=true; | ||||||
|                 } | 					} | ||||||
|             } | 				} | ||||||
|                 break; | 			} break; | ||||||
|             default: | 			default: { | ||||||
|             { | 			} | ||||||
|  | 			} | ||||||
|             } | 		} catch (...) { | ||||||
|         } | 			Done=true; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|         if(Done) { |         if(Done) { | ||||||
|             delete this; |             delete this; | ||||||
|   | |||||||
| @@ -1,51 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-10-28. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "storage_jobs.h" |  | ||||||
| #include "framework/OpenWifiTypes.h" |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     static  ORM::FieldVec    JobDB_Fields{ |  | ||||||
|         // object info |  | ||||||
|         ORM::Field{"id",64, true}, |  | ||||||
|         ORM::Field{"name",ORM::FieldType::FT_TEXT}, |  | ||||||
|         ORM::Field{"description",ORM::FieldType::FT_TEXT}, |  | ||||||
|         ORM::Field{"type",ORM::FieldType::FT_TEXT}, |  | ||||||
|         ORM::Field{"progress",ORM::FieldType::FT_BIGINT}, |  | ||||||
|         ORM::Field{"total",ORM::FieldType::FT_BIGINT}, |  | ||||||
|         ORM::Field{"parameters",ORM::FieldType::FT_TEXT} |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     static  ORM::IndexVec    JobDB_Indexes{ |  | ||||||
|         { std::string("job_name_index"), |  | ||||||
|           ORM::IndexEntryVec{ |  | ||||||
|             {std::string("name"), |  | ||||||
|              ORM::Indextype::ASC} } } |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     JobDB::JobDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L) : |  | ||||||
|     DB(T, "jobs", JobDB_Fields, JobDB_Indexes, P, L, "job") {} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<> void ORM::DB<OpenWifi::JobDBRecordType, OpenWifi::JobRecord>::Convert(const OpenWifi::JobDBRecordType &In, OpenWifi::JobRecord &Out) { |  | ||||||
|     Out.id = In.get<0>(); |  | ||||||
|     Out.name = In.get<1>(); |  | ||||||
|     Out.description = In.get<2>(); |  | ||||||
|     Out.type = In.get<3>(); |  | ||||||
|     Out.progress = In.get<4>(); |  | ||||||
|     Out.total = In.get<5>(); |  | ||||||
|     Out.parameters = OpenWifi::RESTAPI_utils::to_array_of_array_of_object<OpenWifi::Job::Parameter>(In.get<3>()); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<> void ORM::DB<OpenWifi::JobDBRecordType, OpenWifi::JobRecord>::Convert(const OpenWifi::JobRecord &In, OpenWifi::JobDBRecordType &Out) { |  | ||||||
|     Out.set<0>(In.id); |  | ||||||
|     Out.set<1>(In.name); |  | ||||||
|     Out.set<2>(In.description); |  | ||||||
|     Out.set<3>(In.type); |  | ||||||
|     Out.set<4>(In.progress); |  | ||||||
|     Out.set<5>(In.total); |  | ||||||
|     Out.set<6>(OpenWifi::RESTAPI_utils::to_string(In.parameters)); |  | ||||||
| } |  | ||||||
| @@ -1,40 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-10-28. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "framework/orm.h" |  | ||||||
| #include "JobController.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|     typedef Poco::Tuple< |  | ||||||
|         std::string, |  | ||||||
|         std::string, |  | ||||||
|         std::string, |  | ||||||
|         std::string, |  | ||||||
|         uint64_t, |  | ||||||
|         uint64_t, |  | ||||||
|         std::string |  | ||||||
|     > JobDBRecordType; |  | ||||||
|  |  | ||||||
|     struct JobRecord { |  | ||||||
|         Types::UUID_t       id; |  | ||||||
|         std::string         name; |  | ||||||
|         std::string         description; |  | ||||||
|         std::string         type; |  | ||||||
|         uint64_t            progress; |  | ||||||
|         uint64_t            total; |  | ||||||
|         Job::ParametersVec  parameters; |  | ||||||
|  |  | ||||||
|         // void from_string(const std::string &S); |  | ||||||
|         // std::string to_string() const; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     class JobDB : public ORM::DB<JobDBRecordType, JobRecord> { |  | ||||||
|     public: |  | ||||||
|         JobDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L); |  | ||||||
|         virtual ~JobDB() {}; |  | ||||||
|     private: |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
		Reference in New Issue
	
	Block a user
	 Stephane Bourque
					Stephane Bourque