mirror of
				https://github.com/Telecominfraproject/wlan-cloud-owprov.git
				synced 2025-10-31 02:27:52 +00:00 
			
		
		
		
	Compare commits
	
		
			52 Commits
		
	
	
		
			v2.6.0-RC2
			...
			v2.6.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 7fcf2ca41b | ||
|   | 3c2017859b | ||
|   | eecf9a49c2 | ||
|   | 5945d02b3d | ||
|   | 0ac192cdc0 | ||
|   | 1b5eb87eef | ||
|   | 46db18d7cd | ||
|   | 30b8665d7d | ||
|   | c8b3a3b060 | ||
|   | 944500dea9 | ||
|   | a5e0dcb210 | ||
|   | 096da35ff4 | ||
|   | bd7f3af11c | ||
|   | 2a06021c4a | ||
|   | bf18bb25ba | ||
|   | 656562c691 | ||
|   | e93f899b76 | ||
|   | eda73038f6 | ||
|   | 953ca155a4 | ||
|   | 898806f232 | ||
|   | 7d97b19b85 | ||
|   | d6c587fde6 | ||
|   | 58c9a7805b | ||
|   | 94dd4c84e9 | ||
|   | 2636715f6f | ||
|   | f9f4624add | ||
|   | cf441de197 | ||
|   | 2ea7e3dcc5 | ||
|   | 158455a528 | ||
|   | 4d2ccec1a8 | ||
|   | 7dad5a9bdb | ||
|   | cd2ac84c5b | ||
|   | 205343619b | ||
|   | 9735f709e9 | ||
|   | ae5fd31818 | ||
|   | aa1136e55b | ||
|   | 2b46ad4a66 | ||
|   | 439aa1d07a | ||
|   | a9293a7717 | ||
|   | 43d7078cb7 | ||
|   | 18f5d42f00 | ||
|   | 70622b2bb8 | ||
|   | 5b24aea47c | ||
|   | e97617a0db | ||
|   | ba63a7033f | ||
|   | e9db2e1a0d | ||
|   | d85fef7725 | ||
|   | 543c46bf68 | ||
|   | 73eec53fe4 | ||
|   | 8ad2d67c2c | ||
|   | 442f810688 | ||
|   | 2dca5204ea | 
							
								
								
									
										9
									
								
								.github/workflows/cleanup.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.github/workflows/cleanup.yml
									
									
									
									
										vendored
									
									
								
							| @@ -4,6 +4,7 @@ on: | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - main | ||||
|       - 'release/*' | ||||
|     types: [ closed ] | ||||
|  | ||||
| defaults: | ||||
| @@ -16,4 +17,10 @@ jobs: | ||||
|     steps: | ||||
|       - run: | | ||||
|           export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-') | ||||
|           curl -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owprov/$PR_BRANCH_TAG" | ||||
|  | ||||
|           if [[ ! $PR_BRANCH_TAG =~ (main|master|release-*) ]]; then | ||||
|             echo "PR branch is $PR_BRANCH_TAG, deleting Docker image" | ||||
|             curl -s -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owprov/$PR_BRANCH_TAG" | ||||
|           else | ||||
|             echo "PR branch is $PR_BRANCH_TAG, not deleting Docker image" | ||||
|           fi | ||||
|   | ||||
| @@ -125,7 +125,6 @@ add_executable(owprov | ||||
|         src/RESTAPI/RESTAPI_db_helpers.h | ||||
|         src/JobController.cpp src/JobController.h | ||||
|         src/JobRegistrations.cpp | ||||
|         src/storage/storage_jobs.cpp src/storage/storage_jobs.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_list_handler.cpp src/RESTAPI/RESTAPI_map_list_handler.h | ||||
|   | ||||
| @@ -5,7 +5,7 @@ if [ "$SELFSIGNED_CERTS" = 'true' ]; then | ||||
|     update-ca-certificates | ||||
| fi | ||||
|  | ||||
| if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWPROV_CONFIG"/owprov.properties ]]; then | ||||
| if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then | ||||
|   RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWPROV_ROOT/certs/restapi-ca.pem"} \ | ||||
|   RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16005"} \ | ||||
|   RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWPROV_ROOT/certs/restapi-cert.pem"} \ | ||||
|   | ||||
| @@ -9,7 +9,7 @@ fullnameOverride: "" | ||||
| images: | ||||
|   owprov: | ||||
|     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owprov | ||||
|     tag: v2.6.0-RC2 | ||||
|     tag: v2.6.0 | ||||
|     pullPolicy: Always | ||||
| #    regcred: | ||||
| #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | ||||
|   | ||||
| @@ -27,71 +27,13 @@ components: | ||||
|  | ||||
|   responses: | ||||
|     NotFound: | ||||
|       description: The specified resource was not found. | ||||
|       content: | ||||
|         application/json: | ||||
|           schema: | ||||
|             properties: | ||||
|               ErrorCode: | ||||
|                 type: integer | ||||
|               ErrorDetails: | ||||
|                 type: string | ||||
|               ErrorDescription: | ||||
|                 type: string | ||||
|  | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound' | ||||
|     Unauthorized: | ||||
|       description: The requested does not have sufficient rights to perform the operation. | ||||
|       content: | ||||
|         application/json: | ||||
|           schema: | ||||
|             properties: | ||||
|               ErrorCode: | ||||
|                 type: integer | ||||
|                 enum: | ||||
|                   - 0     # Success | ||||
|                   - 1     # PASSWORD_CHANGE_REQUIRED, | ||||
|                   - 2     # INVALID_CREDENTIALS, | ||||
|                   - 3     # PASSWORD_ALREADY_USED, | ||||
|                   - 4     # USERNAME_PENDING_VERIFICATION, | ||||
|                   - 5     # PASSWORD_INVALID, | ||||
|                   - 6     # INTERNAL_ERROR, | ||||
|                   - 7     # ACCESS_DENIED, | ||||
|                   - 8     # INVALID_TOKEN | ||||
|                   - 9     # EXPIRED_TOKEN | ||||
|                   - 10    # RATE_LIMIT_EXCEEDED | ||||
|                   - 11    # BAD_MFA_TRANSACTION | ||||
|                   - 12    # MFA_FAILURE | ||||
|                   - 13    # SECURITY_SERVICE_UNREACHABLE | ||||
|               ErrorDetails: | ||||
|                 type: string | ||||
|               ErrorDescription: | ||||
|                 type: string | ||||
|  | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized' | ||||
|     Success: | ||||
|       description: The requested operation was performed. | ||||
|       content: | ||||
|         application/json: | ||||
|           schema: | ||||
|             properties: | ||||
|               Operation: | ||||
|                 type: string | ||||
|               Details: | ||||
|                 type: string | ||||
|               Code: | ||||
|                 type: integer | ||||
|  | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success' | ||||
|     BadRequest: | ||||
|       description: The requested operation failed. | ||||
|       content: | ||||
|         application/json: | ||||
|           schema: | ||||
|             properties: | ||||
|               ErrorCode: | ||||
|                 type: integer | ||||
|               ErrorDetails: | ||||
|                 type: string | ||||
|               ErrorDescription: | ||||
|                 type: integer | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest' | ||||
|  | ||||
|   schemas: | ||||
|  | ||||
|   | ||||
| @@ -153,6 +153,7 @@ namespace OpenWifi { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         try { | ||||
|             std::set<std::string> Sections; | ||||
|             for (const auto &i: Config_) { | ||||
|                 Poco::JSON::Parser P; | ||||
| @@ -188,7 +189,8 @@ namespace OpenWifi { | ||||
|                             ReplaceVariablesInObject(OriginalSection, ExpandedSection); | ||||
|                             Configuration->set(SectionName, ExpandedSection); | ||||
|                         } else { | ||||
|                         std::cout << " --- unknown element type --- " << O->get(SectionName).toString() << std::endl; | ||||
|                             std::cout << " --- unknown element type --- " << O->get(SectionName).toString() | ||||
|                                       << std::endl; | ||||
|                         } | ||||
|                     } else { | ||||
|                         if (Explain_) { | ||||
| @@ -203,10 +205,10 @@ namespace OpenWifi { | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         if(Config_.empty()) | ||||
|             return false; | ||||
|         } catch (...) { | ||||
|  | ||||
|         return true; | ||||
|         } | ||||
|         return !Config_.empty(); | ||||
|     } | ||||
|  | ||||
|     static bool DeviceTypeMatch(const std::string &DeviceType, const Types::StringVec & Types) { | ||||
|   | ||||
| @@ -26,6 +26,7 @@ namespace OpenWifi { | ||||
|  | ||||
|     void AutoDiscovery::run() { | ||||
|         Poco::AutoPtr<Poco::Notification>	Note(Queue_.waitDequeueNotification()); | ||||
|         Utils::SetThreadName("auto-discovery"); | ||||
|         while(Note && Running_) { | ||||
|             auto Msg = dynamic_cast<DiscoveryMessage *>(Note.get()); | ||||
|             if(Msg!= nullptr) { | ||||
|   | ||||
| @@ -33,7 +33,7 @@ namespace OpenWifi { | ||||
|             void Stop() override; | ||||
|             void ConnectionReceived( const std::string & Key, const std::string & Payload) { | ||||
|                 std::lock_guard G(Mutex_); | ||||
|                 Logger().information(Poco::format("Device(%s): Connection/Ping message.", Key)); | ||||
|                 poco_debug(Logger(),Poco::format("Device(%s): Connection/Ping message.", Key)); | ||||
|                 Queue_.enqueueNotification( new DiscoveryMessage(Key,Payload)); | ||||
|             } | ||||
|             void run() override; | ||||
|   | ||||
| @@ -26,6 +26,8 @@ namespace OpenWifi { | ||||
|                 {"https://ucentral.io/ucentral.schema.pretty.json", "ucentral.schema.pretty.json" } | ||||
|             }; | ||||
|  | ||||
|         Utils::SetThreadName("file-dmnldr"); | ||||
|  | ||||
|         for(const auto &[url,filename]:Files) { | ||||
|             try { | ||||
|                 std::string FileContent; | ||||
|   | ||||
| @@ -27,11 +27,32 @@ namespace OpenWifi { | ||||
|  | ||||
|     void JobController::run() { | ||||
|         Running_ = true ; | ||||
|  | ||||
|         Utils::SetThreadName("job-controller"); | ||||
|         while(Running_) { | ||||
|             Poco::Thread::trySleep(2000); | ||||
|  | ||||
|             std::lock_guard G(Mutex_); | ||||
|  | ||||
|             for(auto ¤t_job:jobs_) { | ||||
|                 if(current_job!=nullptr) { | ||||
|                     if(current_job->Started()==0 && Pool_.used()<Pool_.available()) { | ||||
|                         current_job->Logger().information(fmt::format("Starting {}: {}",current_job->JobId(),current_job->Name())); | ||||
|                         current_job->Start(); | ||||
|                         Pool_.start(*current_job); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             for(auto it = jobs_.begin(); it!=jobs_.end();) {\ | ||||
|                 auto current_job = *it; | ||||
|                 if(current_job!=nullptr && current_job->Completed()!=0) { | ||||
|                     current_job->Logger().information(fmt::format("Completed {}: {}",current_job->JobId(),current_job->Name())); | ||||
|                     it = jobs_.erase(it); | ||||
|                     delete current_job; | ||||
|                 } else { | ||||
|                     ++it; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -7,99 +7,45 @@ | ||||
| #include <vector> | ||||
| #include <utility> | ||||
| #include <functional> | ||||
| #include <list> | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     class Job { | ||||
|     class Job : public Poco::Runnable { | ||||
|     public: | ||||
|             struct Parameter { | ||||
|                 std::string name; | ||||
|                 std::string value; | ||||
|                 inline void to_json(Poco::JSON::Object &Obj) const { | ||||
|                     RESTAPI_utils::field_to_json(Obj,"name",name); | ||||
|                     RESTAPI_utils::field_to_json(Obj,"value",value); | ||||
|                 } | ||||
|         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) : | ||||
|             jobId_(JobID), | ||||
|             name_(name), | ||||
|             parameters_(parameters), | ||||
|             when_(when), | ||||
|             userinfo_(UI), | ||||
|             Logger_(L) | ||||
|         {}; | ||||
|  | ||||
|                 inline bool from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||
|                     try { | ||||
|                         RESTAPI_utils::field_from_json(Obj,"name",name); | ||||
|                         RESTAPI_utils::field_from_json(Obj,"value",value); | ||||
|                         return true; | ||||
|                     } catch (...) { | ||||
|  | ||||
|                     } | ||||
|                     return false; | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             struct Status { | ||||
|                 Types::UUID_t   UUID; | ||||
|                 uint64_t        Start = 0 ; | ||||
|                 uint64_t        Progress = 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_; } | ||||
|         virtual void run() = 0; | ||||
|         [[nodiscard]] std::string Name() const { return name_; } | ||||
|         const SecurityObjects::UserInfo & UserInfo() const { return userinfo_; } | ||||
|         Poco::Logger & Logger() { return Logger_; } | ||||
|         const std::string & JobId() const { return jobId_; } | ||||
|         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: | ||||
|             Types::UUID_t       UUID_; | ||||
|             std::string         Title_; | ||||
|             std::string         Description_; | ||||
|             std::string         RegisteredName_; | ||||
|             ParametersVec       Parameters_; | ||||
|         std::string                 jobId_; | ||||
|         std::string                 name_; | ||||
|         std::vector<std::string>    parameters_; | ||||
|         uint64_t                    when_=0; | ||||
|         SecurityObjects::UserInfo   userinfo_; | ||||
|         Poco::Logger                & Logger_; | ||||
|         uint64_t                    started_=0; | ||||
|         uint64_t                    completed_=0; | ||||
|     }; | ||||
|  | ||||
|     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 { | ||||
|         public: | ||||
|             static auto instance() { | ||||
| @@ -112,11 +58,16 @@ namespace OpenWifi { | ||||
|             void run() override; | ||||
|             inline void wakeup() { Thr_.wakeUp(); } | ||||
|  | ||||
|             bool JobList(Job::Statuses & Statuses); | ||||
|             void AddJob( Job* newJob ) { | ||||
|                 std::lock_guard G(Mutex_); | ||||
|                 jobs_.push_back(newJob); | ||||
|             } | ||||
|  | ||||
|         private: | ||||
|             Poco::Thread                        Thr_; | ||||
|             std::atomic_bool                    Running_=false; | ||||
|             std::list<Job *>                    jobs_; | ||||
|             Poco::ThreadPool                    Pool_; | ||||
|  | ||||
|         JobController() noexcept: | ||||
|             SubSystemServer("JobController", "JOB-SVR", "job") | ||||
|   | ||||
| @@ -27,6 +27,7 @@ namespace OpenWifi{ | ||||
|             for (const auto &i: V.children) { | ||||
|                 ProvObjects::Venue V2; | ||||
|                 if (StorageService()->VenueDB().GetRecord("id", i, V2)) { | ||||
|                     std::copy(V2.devices.begin(),V2.devices.end(),std::back_inserter(R)); | ||||
|                     auto LowerDevs = GetDevices(V2, GetChildren); | ||||
|                     std::copy(LowerDevs.begin(), LowerDevs.end(), std::back_inserter(R)); | ||||
|                 } | ||||
| @@ -227,10 +228,10 @@ namespace OpenWifi{ | ||||
|  | ||||
|             Poco::JSON::Object  Answer; | ||||
|             SNL.serialNumbers = Existing.devices; | ||||
|  | ||||
|             auto Task = new VenueConfigUpdater(UUID,UserInfo_.userinfo,0,Logger()); | ||||
|             auto JobId = Task->Start(); | ||||
|  | ||||
|             auto JobId = MicroService::instance().CreateUUID(); | ||||
|             Types::StringVec Parameters{UUID};; | ||||
|             auto NewJob = new VenueConfigUpdater(JobId,"VenueConfigurationUpdater", Parameters, 0, UserInfo_.userinfo, Logger()); | ||||
|             JobController()->AddJob(dynamic_cast<Job*>(NewJob)); | ||||
|             SNL.to_json(Answer); | ||||
|             Answer.set("jobId",JobId); | ||||
|             return ReturnObject(Answer); | ||||
| @@ -241,10 +242,10 @@ namespace OpenWifi{ | ||||
|  | ||||
|             Poco::JSON::Object  Answer; | ||||
|             SNL.serialNumbers = Existing.devices; | ||||
|  | ||||
|             auto Task = new VenueUpgrade(UUID,UserInfo_.userinfo,0,Logger()); | ||||
|             auto JobId = Task->Start(); | ||||
|  | ||||
|             auto JobId = MicroService::instance().CreateUUID(); | ||||
|             Types::StringVec Parameters{UUID};; | ||||
|             auto NewJob = new VenueUpgrade(JobId,"VenueFirmwareUpgrade", Parameters, 0, UserInfo_.userinfo, Logger()); | ||||
|             JobController()->AddJob(dynamic_cast<Job*>(NewJob)); | ||||
|             SNL.to_json(Answer); | ||||
|             Answer.set("jobId",JobId); | ||||
|             return ReturnObject(Answer); | ||||
| @@ -255,10 +256,10 @@ namespace OpenWifi{ | ||||
|  | ||||
|             Poco::JSON::Object  Answer; | ||||
|             SNL.serialNumbers = Existing.devices; | ||||
|  | ||||
|             auto Task = new VenueRebooter(UUID,UserInfo_.userinfo,0,Logger()); | ||||
|             auto JobId = Task->Start(); | ||||
|  | ||||
|             auto JobId = MicroService::instance().CreateUUID(); | ||||
|             Types::StringVec Parameters{UUID};; | ||||
|             auto NewJob = new VenueRebooter(JobId,"VenueRebooter", Parameters, 0, UserInfo_.userinfo, Logger()); | ||||
|             JobController()->AddJob(dynamic_cast<Job*>(NewJob)); | ||||
|             SNL.to_json(Answer); | ||||
|             Answer.set("jobId",JobId); | ||||
|             return ReturnObject(Answer); | ||||
|   | ||||
| @@ -42,6 +42,7 @@ namespace OpenWifi { | ||||
|  | ||||
|     void Signup::run() { | ||||
|         Running_ = true; | ||||
|         Utils::SetThreadName("signup-mgr"); | ||||
|         while(Running_) { | ||||
|             Poco::Thread::trySleep(5000); | ||||
|  | ||||
|   | ||||
| @@ -105,6 +105,7 @@ namespace OpenWifi { | ||||
|     } | ||||
|  | ||||
|     void Storage::onTimer([[maybe_unused]] Poco::Timer &timer) { | ||||
|         Utils::SetThreadName("strg-janitor"); | ||||
|     } | ||||
|  | ||||
|     void Storage::Stop() { | ||||
| @@ -213,31 +214,109 @@ namespace OpenWifi { | ||||
|             return true; | ||||
|         }; | ||||
|  | ||||
|         auto FixEntityDevices = [&](const ProvObjects::Entity &E) -> bool { | ||||
|         auto FixEntity = [&](const ProvObjects::Entity &E) -> bool { | ||||
|             Types::UUIDvec_t NewDevices; | ||||
|             bool Modified=false; | ||||
|             for(const auto &device:E.devices) { | ||||
|                 ProvObjects::InventoryTag T; | ||||
|                 if(InventoryDB().GetRecord("id", device, T)) { | ||||
|                     NewDevices.emplace_back(device); | ||||
|                 } else { | ||||
|  | ||||
|                     Modified=true; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if(NewDevices!=E.devices) { | ||||
|             Types::UUIDvec_t NewContacts; | ||||
|             for(const auto &contact:E.contacts) { | ||||
|                 ProvObjects::Contact C; | ||||
|                 if(ContactDB().GetRecord("id", contact, C)) { | ||||
|                     NewContacts.emplace_back(contact); | ||||
|                 } else { | ||||
|                     Modified=true; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             Types::UUIDvec_t NewLocations; | ||||
|             for(const auto &location:E.locations) { | ||||
|                 ProvObjects::Location L; | ||||
|                 if(LocationDB().GetRecord("id", location, L)) { | ||||
|                     NewLocations.emplace_back(location); | ||||
|                 } else { | ||||
|                     Modified=true; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             Types::UUIDvec_t NewVenues; | ||||
|             for(const auto &venue:E.venues) { | ||||
|                 ProvObjects::Venue V; | ||||
|                 if(VenueDB().GetRecord("id", venue, V)) { | ||||
|                     NewVenues.emplace_back(venue); | ||||
|                 } else { | ||||
|                     Modified=true; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             Types::UUIDvec_t NewVariables; | ||||
|             for(const auto &variable:E.variables) { | ||||
|                 ProvObjects::VariableBlock V; | ||||
|                 if(VariablesDB().GetRecord("id", variable, V)) { | ||||
|                     NewVariables.emplace_back(variable); | ||||
|                 } else { | ||||
|                     Modified=true; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if(Modified) | ||||
|             { | ||||
|                 Logger().warning(fmt::format("  fixing entity: {}",E.info.name)); | ||||
|                 ProvObjects::Entity NewEntity = E; | ||||
|                 NewEntity.devices = NewDevices; | ||||
|                 NewEntity.contacts = NewContacts; | ||||
|                 NewEntity.locations = NewLocations; | ||||
|                 NewEntity.venues = NewVenues; | ||||
|                 NewEntity.variables = NewVariables; | ||||
|                 EntityDB().UpdateRecord("id", E.info.id, NewEntity); | ||||
|             } | ||||
|             return true; | ||||
|         }; | ||||
|  | ||||
|         auto FixInventory = [&](const ProvObjects::InventoryTag &T) -> bool { | ||||
|             // check the venue/entity for this device. | ||||
|             ProvObjects::InventoryTag   NewTag{T}; | ||||
|             bool modified=false; | ||||
|             if(!T.venue.empty() && !VenueDB().Exists("id",T.venue)) { | ||||
|                 NewTag.venue.clear(); | ||||
|                 modified=true; | ||||
|             } | ||||
|  | ||||
|             if(!T.entity.empty() && !EntityDB().Exists("id",T.entity)) { | ||||
|                 NewTag.entity.clear(); | ||||
|                 modified=true; | ||||
|             } | ||||
|  | ||||
|             if(!T.location.empty() && !LocationDB().Exists("id",T.location)) { | ||||
|                 NewTag.location.clear(); | ||||
|                 modified=true; | ||||
|             } | ||||
|  | ||||
|             if(!T.contact.empty() && !ContactDB().Exists("id",T.contact)) { | ||||
|                 NewTag.contact.clear(); | ||||
|                 modified=true; | ||||
|             } | ||||
|  | ||||
|             if(modified) { | ||||
|                 Logger().warning(fmt::format("  fixing entity: {}",T.info.name)); | ||||
|                 InventoryDB().UpdateRecord("id", T.info.id, NewTag); | ||||
|             } | ||||
|             return true; | ||||
|         }; | ||||
|  | ||||
|         Logger().information("Checking DB consistency: venues"); | ||||
|         VenueDB().Iterate(FixVenueDevices); | ||||
|         Logger().information("Checking DB consistency: entities"); | ||||
|         EntityDB().Iterate(FixEntityDevices); | ||||
|  | ||||
|         EntityDB().Iterate(FixEntity); | ||||
|         Logger().information("Checking DB consistency: inventory"); | ||||
|         InventoryDB().Iterate(FixInventory); | ||||
|     } | ||||
|  | ||||
|     void Storage::InitializeSystemDBs() { | ||||
|   | ||||
| @@ -21,7 +21,7 @@ namespace OpenWifi { | ||||
|     } | ||||
|  | ||||
|     void TagServer::run() { | ||||
|  | ||||
|         Utils::SetThreadName("tag-server"); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -9,6 +9,7 @@ | ||||
| #include "APConfig.h" | ||||
| #include "sdks/SDK_gw.h" | ||||
| #include "framework/WebSocketClientNotifications.h" | ||||
| #include "JobController.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
| @@ -19,8 +20,6 @@ namespace OpenWifi { | ||||
|                 auto Status = Results->get("status").extract<Poco::JSON::Object::Ptr>(); | ||||
|                 auto Rejected = Status->getArray("rejected"); | ||||
|                 std::transform(Rejected->begin(),Rejected->end(),std::back_inserter(Warnings), [](auto i) -> auto { return i.toString(); }); | ||||
| //                for(const auto &i:*Rejected) | ||||
|                 //                  Warnings.push_back(i.toString()); | ||||
|             } | ||||
|         } catch (...) { | ||||
|         } | ||||
| @@ -37,12 +36,14 @@ namespace OpenWifi { | ||||
|         void run() final { | ||||
|             ProvObjects::InventoryTag   Device; | ||||
|             started_=true; | ||||
|             Utils::SetThreadName("venue-cfg"); | ||||
|             if(StorageService()->InventoryDB().GetRecord("id",uuid_,Device)) { | ||||
|                 SerialNumber = Device.serialNumber; | ||||
|                 // std::cout << "Starting push for " << Device.serialNumber << std::endl; | ||||
|                 Logger().debug(fmt::format("{}: Computing configuration.",Device.serialNumber)); | ||||
|                 auto DeviceConfig = std::make_shared<APConfig>(Device.serialNumber, Device.deviceType, Logger(), false); | ||||
|                 auto Configuration = Poco::makeShared<Poco::JSON::Object>(); | ||||
|                 try { | ||||
|                     if (DeviceConfig->Get(Configuration)) { | ||||
|                         std::ostringstream OS; | ||||
|                         Configuration->stringify(OS); | ||||
| @@ -63,9 +64,14 @@ namespace OpenWifi { | ||||
|                         bad_config_++; | ||||
|                         // std::cout << Device.serialNumber << ": Bad config" << std::endl; | ||||
|                     } | ||||
|                 } catch (...) { | ||||
|                     Logger().debug(fmt::format("{}: Configuration is bad (caused an exception).", Device.serialNumber)); | ||||
|                     bad_config_++; | ||||
|                 } | ||||
|             } | ||||
|             done_ = true; | ||||
|             // std::cout << "Done push for " << Device.serialNumber << std::endl; | ||||
|             Utils::SetThreadName("free"); | ||||
|         } | ||||
|  | ||||
|         uint64_t        updated_=0, failed_=0, bad_config_=0; | ||||
| @@ -80,133 +86,101 @@ namespace OpenWifi { | ||||
|         inline Poco::Logger & Logger() { return Logger_; } | ||||
|     }; | ||||
|  | ||||
|     class VenueConfigUpdater: public Poco::Runnable { | ||||
|     class VenueConfigUpdater: public Job { | ||||
|     public: | ||||
|         explicit VenueConfigUpdater(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) : | ||||
|             VenueUUID_(VenueUUID), | ||||
|             UI_(UI), | ||||
|             When_(When), | ||||
|             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) : | ||||
|                 Job(JobID, name, parameters, when, UI, L) { | ||||
|  | ||||
|         } | ||||
|  | ||||
|         inline std::string Start() { | ||||
|             JobId_ = MicroService::CreateUUID(); | ||||
|             Worker_.start(*this); | ||||
|             return JobId_; | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|         inline virtual void run() { | ||||
|             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 { | ||||
|  | ||||
|             if(When_ && When_>OpenWifi::Now()) | ||||
|                 Poco::Thread::trySleep( (long) (When_ - OpenWifi::Now()) * 1000 ); | ||||
|             Utils::SetThreadName("venue-update"); | ||||
|             VenueUUID_ = Parameter(0); | ||||
|  | ||||
|             WebSocketNotification<WebSocketNotificationJobContent> N; | ||||
|  | ||||
|             Logger().information(fmt::format("Job {} Starting.", JobId_)); | ||||
|  | ||||
|             ProvObjects::Venue  Venue; | ||||
|             uint64_t Updated = 0, Failed = 0 , BadConfigs = 0 ; | ||||
|             if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { | ||||
|                 const std::size_t MaxThreads=16; | ||||
|                 struct tState { | ||||
|                     Poco::Thread                thr_; | ||||
|                     VenueDeviceConfigUpdater    *task= nullptr; | ||||
|                 }; | ||||
|  | ||||
|                 N.content.title = fmt::format("Updating {} configurations", Venue.info.name); | ||||
|                 N.content.jobId = JobId_; | ||||
|                 N.content.jobId = JobId(); | ||||
|  | ||||
|                 Poco::ThreadPool    Pool_; | ||||
|                 std::list<VenueDeviceConfigUpdater*> JobList; | ||||
|  | ||||
|                 std::array<tState,MaxThreads> Tasks; | ||||
|  | ||||
|                 for(const auto &uuid:Venue.devices) { | ||||
|                     auto NewTask = new VenueDeviceConfigUpdater(uuid, Venue.info.name, Logger()); | ||||
|                     // std::cout << "Scheduling config push for " << uuid << std::endl; | ||||
|                     bool found_slot = false; | ||||
|                     while (!found_slot) { | ||||
|                         for (auto &cur_task: Tasks) { | ||||
|                             if (cur_task.task == nullptr) { | ||||
|                                 cur_task.task = NewTask; | ||||
|                                 cur_task.thr_.start(*NewTask); | ||||
|                                 found_slot = true; | ||||
|                                 break; | ||||
|                     bool TaskAdded=false; | ||||
|                     while(!TaskAdded) { | ||||
|                         if (Pool_.available()) { | ||||
|                             JobList.push_back(NewTask); | ||||
|                             Pool_.start(*NewTask); | ||||
|                             TaskAdded = true; | ||||
|                             continue; | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                         //  Let's look for a slot... | ||||
|                         if (!found_slot) { | ||||
|                             for (auto &cur_task: Tasks) { | ||||
|                                 if (cur_task.task != nullptr && cur_task.task->started_) { | ||||
|                                     if (cur_task.thr_.isRunning()) | ||||
|                                         continue; | ||||
|                                     if (!cur_task.thr_.isRunning() && cur_task.task->done_) { | ||||
|                                         cur_task.thr_.join(); | ||||
|                                         Updated += cur_task.task->updated_; | ||||
|                                         Failed += cur_task.task->failed_; | ||||
|                                         BadConfigs += cur_task.task->bad_config_; | ||||
|                                         cur_task.task->started_ = cur_task.task->done_ = false; | ||||
|                                         delete cur_task.task; | ||||
|                                         cur_task.task = nullptr; | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 Logger().debug("Waiting for outstanding update threads to finish."); | ||||
|                 bool stillTasksRunning=true; | ||||
|                 while(stillTasksRunning) { | ||||
|                     stillTasksRunning = false; | ||||
|                     for(auto &cur_task:Tasks) { | ||||
|                         if(cur_task.task!= nullptr && cur_task.task->started_) { | ||||
|                             if(cur_task.thr_.isRunning()) { | ||||
|                                 stillTasksRunning = true; | ||||
|                                 continue; | ||||
|                             } | ||||
|                             if(!cur_task.thr_.isRunning() && cur_task.task->done_) { | ||||
|                                 cur_task.thr_.join(); | ||||
|                                 if(cur_task.task->updated_) { | ||||
|                                     Updated++; | ||||
|                                     N.content.success.push_back(cur_task.task->SerialNumber); | ||||
|                                 } else if(cur_task.task->failed_) { | ||||
|                                     Failed++; | ||||
|                                     N.content.warning.push_back(cur_task.task->SerialNumber); | ||||
|                     for(auto job_it = JobList.begin(); job_it !=JobList.end();) { | ||||
|                         VenueDeviceConfigUpdater * current_job = *job_it; | ||||
|                         if(current_job!= nullptr && current_job->done_) { | ||||
|                             Updated += current_job->updated_; | ||||
|                             Failed += current_job->failed_; | ||||
|                             BadConfigs += current_job->bad_config_; | ||||
|                             if(current_job->updated_) { | ||||
|                                 N.content.success.push_back(current_job->SerialNumber); | ||||
|                             } else if(current_job->failed_) { | ||||
|                                 N.content.warning.push_back(current_job->SerialNumber); | ||||
|                             } else { | ||||
|                                     BadConfigs++; | ||||
|                                     N.content.error.push_back(cur_task.task->SerialNumber); | ||||
|                                 N.content.error.push_back(current_job->SerialNumber); | ||||
|                             } | ||||
|                                 cur_task.task->started_ = cur_task.task->done_ = false; | ||||
|                                 delete cur_task.task; | ||||
|                                 cur_task.task = nullptr; | ||||
|                             job_it = JobList.erase(job_it); | ||||
|                             delete current_job; | ||||
|                         } else { | ||||
|                             ++job_it; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 Logger().debug("Waiting for outstanding update threads to finish."); | ||||
|                 Pool_.joinAll(); | ||||
|                 for(auto job_it = JobList.begin(); job_it !=JobList.end();) { | ||||
|                     VenueDeviceConfigUpdater * current_job = *job_it; | ||||
|                     if(current_job!= nullptr && current_job->done_) { | ||||
|                         Updated += current_job->updated_; | ||||
|                         Failed += current_job->failed_; | ||||
|                         BadConfigs += current_job->bad_config_; | ||||
|                         if(current_job->updated_) { | ||||
|                             N.content.success.push_back(current_job->SerialNumber); | ||||
|                         } else if(current_job->failed_) { | ||||
|                             N.content.warning.push_back(current_job->SerialNumber); | ||||
|                         } else { | ||||
|                             N.content.error.push_back(current_job->SerialNumber); | ||||
|                         } | ||||
|                         job_it = JobList.erase(job_it); | ||||
|                         delete current_job; | ||||
|                     } else { | ||||
|                         ++job_it; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 N.content.details = fmt::format("Job {} Completed: {} updated, {} failed to update, {} bad configurations. ", | ||||
|                                                 JobId_, Updated ,Failed, BadConfigs); | ||||
|                                                 JobId(), Updated ,Failed, BadConfigs); | ||||
|  | ||||
|             } else { | ||||
|                 N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); | ||||
|                 Logger().warning(N.content.details); | ||||
|             } | ||||
|  | ||||
|             WebSocketClientNotificationVenueUpdateJobCompletionToUser(UI_.email, N); | ||||
|             // std::cout << N.content.details << std::endl; | ||||
|             WebSocketClientNotificationVenueUpdateJobCompletionToUser(UserInfo().email, N); | ||||
|             Logger().information(fmt::format("Job {} Completed: {} updated, {} failed to update , {} bad configurations.", | ||||
|                                              JobId_, Updated ,Failed, BadConfigs)); | ||||
|             delete this; | ||||
|                                              JobId(), Updated ,Failed, BadConfigs)); | ||||
|             Utils::SetThreadName("free"); | ||||
|             Complete(); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
| #include "StorageService.h" | ||||
| #include "APConfig.h" | ||||
| #include "sdks/SDK_gw.h" | ||||
| #include "JobController.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
| @@ -48,129 +49,90 @@ namespace OpenWifi { | ||||
|         inline Poco::Logger & Logger() { return Logger_; } | ||||
|     }; | ||||
|  | ||||
|     class VenueRebooter: public Poco::Runnable { | ||||
|     class VenueRebooter: public Job { | ||||
|     public: | ||||
|         explicit VenueRebooter(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) : | ||||
|                 VenueUUID_(VenueUUID), | ||||
|                 UI_(UI), | ||||
|                 When_(When), | ||||
|                 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) : | ||||
|                 Job(JobID, name, parameters, when, UI, L) { | ||||
|  | ||||
|         } | ||||
|  | ||||
|         inline std::string Start() { | ||||
|             JobId_ = MicroService::CreateUUID(); | ||||
|             Worker_.start(*this); | ||||
|             return JobId_; | ||||
|         } | ||||
|         inline virtual void run() final { | ||||
|  | ||||
|     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 { | ||||
|  | ||||
|             if(When_ && When_>OpenWifi::Now()) | ||||
|                 Poco::Thread::trySleep( (long) (When_ - OpenWifi::Now()) * 1000 ); | ||||
|             Utils::SetThreadName("venue-reboot"); | ||||
|  | ||||
|             WebSocketClientNotificationVenueRebootList_t        N; | ||||
|  | ||||
|             Logger().information(fmt::format("Job {} Starting.", JobId_)); | ||||
|             auto VenueUUID_ = Parameter(0); | ||||
|  | ||||
|             ProvObjects::Venue  Venue; | ||||
|             uint64_t rebooted_ = 0, failed_ = 0; | ||||
|             if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { | ||||
|                 const std::size_t MaxThreads=16; | ||||
|                 struct tState { | ||||
|                     Poco::Thread                thr_; | ||||
|                     VenueDeviceRebooter    *task= nullptr; | ||||
|                 }; | ||||
|  | ||||
|                 N.content.title = fmt::format("Rebooting {} devices.", Venue.info.name); | ||||
|                 N.content.jobId = JobId_; | ||||
|                 N.content.jobId = JobId(); | ||||
|  | ||||
|                 std::array<tState,MaxThreads> Tasks; | ||||
|                 Poco::ThreadPool    Pool_; | ||||
|                 std::list<VenueDeviceRebooter*> JobList; | ||||
|  | ||||
|                 for(const auto &uuid:Venue.devices) { | ||||
|                     auto NewTask = new VenueDeviceRebooter(uuid, Venue.info.name, Logger()); | ||||
|                     // std::cout << "Scheduling config push for " << uuid << std::endl; | ||||
|                     bool found_slot = false; | ||||
|                     while (!found_slot) { | ||||
|                         for (auto &cur_task: Tasks) { | ||||
|                             if (cur_task.task == nullptr) { | ||||
|                                 cur_task.task = NewTask; | ||||
|                                 cur_task.thr_.start(*NewTask); | ||||
|                                 found_slot = true; | ||||
|                                 break; | ||||
|                     bool TaskAdded=false; | ||||
|                     while(!TaskAdded) { | ||||
|                         if (Pool_.available()) { | ||||
|                             JobList.push_back(NewTask); | ||||
|                             Pool_.start(*NewTask); | ||||
|                             TaskAdded = true; | ||||
|                             continue; | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                         //  Let's look for a slot... | ||||
|                         if (!found_slot) { | ||||
|                             for (auto &cur_task: Tasks) { | ||||
|                                 if (cur_task.task != nullptr && cur_task.task->started_) { | ||||
|                                     if (cur_task.thr_.isRunning()) | ||||
|                                         continue; | ||||
|                                     if (!cur_task.thr_.isRunning() && cur_task.task->done_) { | ||||
|                                         cur_task.thr_.join(); | ||||
|                                         rebooted_ += cur_task.task->rebooted_; | ||||
|                                         failed_ += cur_task.task->failed_; | ||||
|                                         cur_task.task->started_ = cur_task.task->done_ = false; | ||||
|                                         delete cur_task.task; | ||||
|                                         cur_task.task = nullptr; | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                     for(auto job_it = JobList.begin(); job_it !=JobList.end();) { | ||||
|                         VenueDeviceRebooter * current_job = *job_it; | ||||
|                         if(current_job!= nullptr && current_job->done_) { | ||||
|                             if(current_job->rebooted_) | ||||
|                                 N.content.success.push_back(current_job->SerialNumber); | ||||
|                             else | ||||
|                                 N.content.warning.push_back(current_job->SerialNumber); | ||||
|                             rebooted_ += current_job->rebooted_; | ||||
|                             failed_ += current_job->failed_; | ||||
|                             job_it = JobList.erase(job_it); | ||||
|                             delete current_job; | ||||
|                         } else { | ||||
|                             ++job_it; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 Logger().debug("Waiting for outstanding update threads to finish."); | ||||
|                 bool stillTasksRunning=true; | ||||
|                 while(stillTasksRunning) { | ||||
|                     stillTasksRunning = false; | ||||
|                     for(auto &cur_task:Tasks) { | ||||
|                         if(cur_task.task!= nullptr && cur_task.task->started_) { | ||||
|                             if(cur_task.thr_.isRunning()) { | ||||
|                                 stillTasksRunning = true; | ||||
|                                 continue; | ||||
|                             } | ||||
|                             if(!cur_task.thr_.isRunning() && cur_task.task->done_) { | ||||
|                                 cur_task.thr_.join(); | ||||
|                                 if(cur_task.task->rebooted_) { | ||||
|                                     rebooted_++; | ||||
|                                     N.content.success.push_back(cur_task.task->SerialNumber); | ||||
|                                 } else if(cur_task.task->failed_) { | ||||
|                                     failed_++; | ||||
|                                     N.content.warning.push_back(cur_task.task->SerialNumber); | ||||
|                                 } | ||||
|                                 cur_task.task->started_ = cur_task.task->done_ = false; | ||||
|                                 delete cur_task.task; | ||||
|                                 cur_task.task = nullptr; | ||||
|                 Pool_.joinAll(); | ||||
|                 for(auto job_it = JobList.begin(); job_it !=JobList.end();) { | ||||
|                     VenueDeviceRebooter * current_job = *job_it; | ||||
|                     if(current_job!= nullptr && current_job->done_) { | ||||
|                         if(current_job->rebooted_) | ||||
|                             N.content.success.push_back(current_job->SerialNumber); | ||||
|                         else | ||||
|                             N.content.warning.push_back(current_job->SerialNumber); | ||||
|                         rebooted_ += current_job->rebooted_; | ||||
|                         failed_ += current_job->failed_; | ||||
|                         job_it = JobList.erase(job_it); | ||||
|                         delete current_job; | ||||
|                     } else { | ||||
|                         ++job_it; | ||||
|                     } | ||||
|                 } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 N.content.details = fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.", | ||||
|                                                 JobId_, rebooted_ ,failed_); | ||||
|                                                 JobId(), rebooted_ ,failed_); | ||||
|  | ||||
|             } else { | ||||
|                 N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); | ||||
|                 Logger().warning(N.content.details); | ||||
|             } | ||||
|  | ||||
|             WebSocketClientNotificationVenueRebootCompletionToUser(UI_.email,N); | ||||
|             // std::cout << N.content.details << std::endl; | ||||
|             WebSocketClientNotificationVenueRebootCompletionToUser(UserInfo().email,N); | ||||
|             Logger().information(fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.", | ||||
|                                              JobId_, rebooted_ ,failed_)); | ||||
|             delete this; | ||||
|                                              JobId(), rebooted_ ,failed_)); | ||||
|             Utils::SetThreadName("free"); | ||||
|             Complete(); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|   | ||||
| @@ -11,6 +11,7 @@ | ||||
| #include "APConfig.h" | ||||
| #include "sdks/SDK_gw.h" | ||||
| #include "sdks/SDK_fms.h" | ||||
| #include "JobController.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     class VenueDeviceUpgrade : public Poco::Runnable { | ||||
| @@ -30,7 +31,7 @@ namespace OpenWifi { | ||||
|  | ||||
|                 Storage::ApplyRules(rules_,Device.deviceRules); | ||||
|                 if(Device.deviceRules.firmwareUpgrade=="no") { | ||||
|                     std::cout << "Skipped Upgrade:" << Device.serialNumber << std::endl; | ||||
|                     poco_debug(Logger(),fmt::format("Skipped Upgrade: {}", Device.serialNumber)); | ||||
|                     skipped_++; | ||||
|                     done_=true; | ||||
|                     return; | ||||
| @@ -39,16 +40,14 @@ namespace OpenWifi { | ||||
|                 FMSObjects::Firmware    F; | ||||
|                 if(SDK::FMS::Firmware::GetLatest(Device.deviceType,Device.deviceRules.rcOnly=="yes",F)) { | ||||
|                     if (SDK::GW::Device::Upgrade(nullptr, Device.serialNumber, 0, F.uri)) { | ||||
|                         std::cout << "Upgraded:" << Device.serialNumber << " to " << F.uri << std::endl; | ||||
|                         Logger().debug(fmt::format("{}: Upgraded.",Device.serialNumber)); | ||||
|                         upgraded_++; | ||||
|                     } else { | ||||
|                         std::cout << "Did not Upgrade:" << Device.serialNumber << " to " << F.uri << std::endl; | ||||
|                         Logger().information(fmt::format("{}: Not Upgraded.", Device.serialNumber)); | ||||
|                         failed_++; | ||||
|                     } | ||||
|                 } else { | ||||
|                     std::cout << "Did not Upgrade:" << Device.serialNumber << " to <unknown>" << std::endl; | ||||
|                     Logger().information(fmt::format("{}: Not Upgraded. No firmware available.", Device.serialNumber)); | ||||
|                     failed_++; | ||||
|                 } | ||||
|             } | ||||
| @@ -69,132 +68,94 @@ namespace OpenWifi { | ||||
|         inline Poco::Logger & Logger() { return Logger_; } | ||||
|     }; | ||||
|  | ||||
|     class VenueUpgrade: public Poco::Runnable { | ||||
|     class VenueUpgrade: public Job { | ||||
|     public: | ||||
|         explicit VenueUpgrade(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) : | ||||
|                 VenueUUID_(VenueUUID), | ||||
|                 UI_(UI), | ||||
|                 When_(When), | ||||
|                 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) : | ||||
|                 Job(JobID, name, parameters, when, UI, L) { | ||||
|  | ||||
|         } | ||||
|  | ||||
|         inline std::string Start() { | ||||
|             JobId_ = MicroService::CreateUUID(); | ||||
|             Worker_.start(*this); | ||||
|             return JobId_; | ||||
|         } | ||||
|         inline virtual void run() final { | ||||
|  | ||||
|     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 { | ||||
|  | ||||
|             if(When_ && When_>OpenWifi::Now()) | ||||
|                 Poco::Thread::trySleep( (long) (When_ - OpenWifi::Now()) * 1000 ); | ||||
|             Utils::SetThreadName("venue-upgr"); | ||||
|             auto VenueUUID_ = Parameter(0); | ||||
|  | ||||
|             WebSocketClientNotificationVenueRebootList_t        N; | ||||
|  | ||||
|             Logger().information(fmt::format("Job {} Starting.", JobId_)); | ||||
|  | ||||
|             ProvObjects::Venue  Venue; | ||||
|             uint64_t upgraded_ = 0, failed_ = 0; | ||||
|             if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { | ||||
|                 const std::size_t MaxThreads=16; | ||||
|                 struct tState { | ||||
|                     Poco::Thread                thr_; | ||||
|                     VenueDeviceUpgrade    *task= nullptr; | ||||
|                 }; | ||||
|  | ||||
|                 N.content.title = fmt::format("Upgrading {} devices.", Venue.info.name); | ||||
|                 N.content.jobId = JobId_; | ||||
|                 N.content.jobId = JobId(); | ||||
|  | ||||
|                 std::array<tState,MaxThreads> Tasks; | ||||
|                 Poco::ThreadPool                Pool_; | ||||
|                 std::list<VenueDeviceUpgrade*>  JobList; | ||||
|                 ProvObjects::DeviceRules        Rules; | ||||
|  | ||||
|                 StorageService()->VenueDB().EvaluateDeviceRules(Venue.info.id, Rules); | ||||
|  | ||||
|                 for(const auto &uuid:Venue.devices) { | ||||
|                     auto NewTask = new VenueDeviceUpgrade(uuid, Venue.info.name, Rules, Logger()); | ||||
|                     // std::cout << "Scheduling config push for " << uuid << std::endl; | ||||
|                     bool found_slot = false; | ||||
|                     while (!found_slot) { | ||||
|                         for (auto &cur_task: Tasks) { | ||||
|                             if (cur_task.task == nullptr) { | ||||
|                                 cur_task.task = NewTask; | ||||
|                                 cur_task.thr_.start(*NewTask); | ||||
|                                 found_slot = true; | ||||
|                                 break; | ||||
|                     bool TaskAdded = false; | ||||
|                     while (!TaskAdded) { | ||||
|                         if (Pool_.available()) { | ||||
|                             JobList.push_back(NewTask); | ||||
|                             Pool_.start(*NewTask); | ||||
|                             TaskAdded = true; | ||||
|                             continue; | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                         //  Let's look for a slot... | ||||
|                         if (!found_slot) { | ||||
|                             for (auto &cur_task: Tasks) { | ||||
|                                 if (cur_task.task != nullptr && cur_task.task->started_) { | ||||
|                                     if (cur_task.thr_.isRunning()) | ||||
|                                         continue; | ||||
|                                     if (!cur_task.thr_.isRunning() && cur_task.task->done_) { | ||||
|                                         cur_task.thr_.join(); | ||||
|                                         upgraded_ += cur_task.task->upgraded_; | ||||
|                                         failed_ += cur_task.task->failed_; | ||||
|                                         cur_task.task->started_ = cur_task.task->done_ = false; | ||||
|                                         delete cur_task.task; | ||||
|                                         cur_task.task = nullptr; | ||||
|                     for (auto job_it = JobList.begin(); job_it != JobList.end();) { | ||||
|                         VenueDeviceUpgrade *current_job = *job_it; | ||||
|                         if (current_job != nullptr && current_job->done_) { | ||||
|                             if (current_job->upgraded_) | ||||
|                                 N.content.success.push_back(current_job->SerialNumber); | ||||
|                             else | ||||
|                                 N.content.warning.push_back(current_job->SerialNumber); | ||||
|                             upgraded_ += current_job->upgraded_; | ||||
|                             failed_ += current_job->failed_; | ||||
|                             job_it = JobList.erase(job_it); | ||||
|                             delete current_job; | ||||
|                         } else { | ||||
|                             ++job_it; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 Logger().debug("Waiting for outstanding update threads to finish."); | ||||
|                 bool stillTasksRunning=true; | ||||
|                 while(stillTasksRunning) { | ||||
|                     stillTasksRunning = false; | ||||
|                     for(auto &cur_task:Tasks) { | ||||
|                         if(cur_task.task!= nullptr && cur_task.task->started_) { | ||||
|                             if(cur_task.thr_.isRunning()) { | ||||
|                                 stillTasksRunning = true; | ||||
|                                 continue; | ||||
|                             } | ||||
|                             if(!cur_task.thr_.isRunning() && cur_task.task->done_) { | ||||
|                                 cur_task.thr_.join(); | ||||
|                                 if(cur_task.task->upgraded_) { | ||||
|                                     upgraded_++; | ||||
|                                     N.content.success.push_back(cur_task.task->SerialNumber); | ||||
|                                 } else if(cur_task.task->failed_) { | ||||
|                                     failed_++; | ||||
|                                     N.content.warning.push_back(cur_task.task->SerialNumber); | ||||
|                                 } | ||||
|                                 cur_task.task->started_ = cur_task.task->done_ = false; | ||||
|                                 delete cur_task.task; | ||||
|                                 cur_task.task = nullptr; | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
|                 Logger().debug("Waiting for outstanding upgrade threads to finish."); | ||||
|                 Pool_.joinAll(); | ||||
|                 for(auto job_it = JobList.begin(); job_it !=JobList.end();) { | ||||
|                     VenueDeviceUpgrade * current_job = *job_it; | ||||
|                     if(current_job!= nullptr && current_job->done_) { | ||||
|                         if(current_job->upgraded_) | ||||
|                             N.content.success.push_back(current_job->SerialNumber); | ||||
|                         else | ||||
|                             N.content.warning.push_back(current_job->SerialNumber); | ||||
|                         upgraded_ += current_job->upgraded_; | ||||
|                         failed_ += current_job->failed_; | ||||
|                         job_it = JobList.erase(job_it); | ||||
|                         delete current_job; | ||||
|                     } else { | ||||
|                         ++job_it; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 N.content.details = fmt::format("Job {} Completed: {} upgraded, {} failed to upgrade.", | ||||
|                                                 JobId_, upgraded_ ,failed_); | ||||
|  | ||||
|                                                 JobId(), upgraded_ ,failed_); | ||||
|             } else { | ||||
|                 N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); | ||||
|                 Logger().warning(N.content.details); | ||||
|             } | ||||
|  | ||||
|             WebSocketClientNotificationVenueRebootCompletionToUser(UI_.email,N); | ||||
|             // std::cout << N.content.details << std::endl; | ||||
|             WebSocketClientNotificationVenueRebootCompletionToUser(UserInfo().email,N); | ||||
|             Logger().information(fmt::format("Job {} Completed: {} upgraded, {} failed to upgrade.", | ||||
|                                              JobId_, upgraded_ ,failed_)); | ||||
|             delete this; | ||||
|                                              JobId(), upgraded_ ,failed_)); | ||||
|             Utils::SetThreadName("free"); | ||||
|  | ||||
|             Complete(); | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| @@ -643,6 +643,27 @@ namespace OpenWifi::RESTAPI_utils { | ||||
|  | ||||
| namespace OpenWifi::Utils { | ||||
|  | ||||
| 	inline void SetThreadName(const char *name) { | ||||
| #ifdef __linux__ | ||||
| 		Poco::Thread::current()->setName(name); | ||||
| 		pthread_setname_np(pthread_self(), name); | ||||
| #endif | ||||
| #ifdef __APPLE__ | ||||
| 	Poco::Thread::current()->setName(name); | ||||
| 	pthread_setname_np(name); | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| 	inline void SetThreadName(Poco::Thread &thr, const char *name) { | ||||
| #ifdef __linux__ | ||||
| 		thr.setName(name); | ||||
| 		pthread_setname_np(thr.tid(), name); | ||||
| #endif | ||||
| #ifdef __APPLE__ | ||||
| 		thr.setName(name); | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
|     enum MediaTypeEncodings { | ||||
|         PLAIN, | ||||
|         BINARY, | ||||
| @@ -1167,6 +1188,7 @@ namespace OpenWifi { | ||||
|     static const std::string uSERVICE_SUBCRIBER{ "owsub"}; | ||||
|     static const std::string uSERVICE_INSTALLER{ "owinst"}; | ||||
|     static const std::string uSERVICE_ANALYTICS{ "owanalytics"}; | ||||
| 	static const std::string uSERVICE_OWRRM{ "owrrm"}; | ||||
|  | ||||
| 	class ConfigurationEntry { | ||||
| 	  public: | ||||
| @@ -1315,7 +1337,7 @@ namespace OpenWifi { | ||||
| 		inline void Start(); | ||||
| 		inline void Stop(); | ||||
| 	  private: | ||||
| 		std::atomic_bool 	Running_ = false; | ||||
| 		mutable std::atomic_bool 	Running_ = false; | ||||
| 		Poco::Thread		Thread_; | ||||
| 	}; | ||||
|  | ||||
| @@ -1846,7 +1868,8 @@ namespace OpenWifi { | ||||
| 	            Request = &RequestIn; | ||||
| 	            Response = &ResponseIn; | ||||
|  | ||||
| 				Poco::Thread::current()->setName("WebServerThread_" + std::to_string(TransactionId_)); | ||||
| 				std::string th_name = "restsvr_" + std::to_string(TransactionId_); | ||||
| 				Utils::SetThreadName(th_name.c_str()); | ||||
|  | ||||
|                 if(Request->getContentLength()>0) { | ||||
|                     if(Request->getContentType().find("application/json")!=std::string::npos) { | ||||
| @@ -1895,28 +1918,24 @@ namespace OpenWifi { | ||||
| 	    [[nodiscard]] inline bool NeedAdditionalInfo() const { return QB_.AdditionalInfo; } | ||||
| 	    [[nodiscard]] inline const std::vector<std::string> & SelectedRecords() const { return QB_.Select; } | ||||
|  | ||||
| /*	    [[nodiscard]] inline const Poco::JSON::Object::Ptr ParseStream() { | ||||
| 	        return IncomingParser_.parse(Request->stream()).extract<Poco::JSON::Object::Ptr>(); | ||||
| 	    } | ||||
| */ | ||||
|  | ||||
| 		inline static bool ParseBindings(const std::string & Request, const std::list<std::string> & EndPoints, BindingMap &bindings) { | ||||
| 			bindings.clear(); | ||||
| 	        std::vector<std::string> PathItems = Utils::Split(Request, '/'); | ||||
| 			auto PathItems = Poco::StringTokenizer(Request, "/"); | ||||
|  | ||||
| 			for(const auto &EndPoint:EndPoints) { | ||||
| 	            std::vector<std::string> ParamItems = Utils::Split(EndPoint, '/'); | ||||
| 	            if (PathItems.size() != ParamItems.size()) | ||||
| 				auto ParamItems = Poco::StringTokenizer(EndPoint, "/"); | ||||
| 				if (PathItems.count() != ParamItems.count()) | ||||
| 					continue; | ||||
|  | ||||
| 				bool Matched = true; | ||||
| 	            for (size_t i = 0; i != PathItems.size() && Matched; i++) { | ||||
| 				for (size_t i = 0; i < PathItems.count(); i++) { | ||||
| 					if (PathItems[i] != ParamItems[i]) { | ||||
| 						if (ParamItems[i][0] == '{') { | ||||
| 							auto ParamName = ParamItems[i].substr(1, ParamItems[i].size() - 2); | ||||
| 							bindings[Poco::toLower(ParamName)] = PathItems[i]; | ||||
| 						} else { | ||||
| 							Matched = false; | ||||
| 							break; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| @@ -2582,7 +2601,7 @@ namespace OpenWifi { | ||||
|     private: | ||||
|         std::recursive_mutex  	Mutex_; | ||||
|         Poco::Thread        	Worker_; | ||||
|         std::atomic_bool    	Running_=false; | ||||
|         mutable std::atomic_bool    	Running_=false; | ||||
| 		Poco::NotificationQueue	Queue_; | ||||
|     }; | ||||
|  | ||||
| @@ -2608,7 +2627,7 @@ namespace OpenWifi { | ||||
| 	  private: | ||||
| 		std::recursive_mutex  	Mutex_; | ||||
|         Poco::Thread        	Worker_; | ||||
|         std::atomic_bool    	Running_=false; | ||||
|         mutable std::atomic_bool    	Running_=false; | ||||
|     }; | ||||
|  | ||||
| 	class KafkaDispatcher : public Poco::Runnable { | ||||
| @@ -2665,6 +2684,7 @@ namespace OpenWifi { | ||||
|  | ||||
| 		inline void run() override { | ||||
| 			Poco::AutoPtr<Poco::Notification>	Note(Queue_.waitDequeueNotification()); | ||||
| 			Utils::SetThreadName("kafka-dispatch"); | ||||
| 			while(Note && Running_) { | ||||
| 				auto Msg = dynamic_cast<KafkaMessage*>(Note.get()); | ||||
| 				if(Msg!= nullptr) { | ||||
| @@ -2690,7 +2710,7 @@ namespace OpenWifi { | ||||
| 		std::recursive_mutex  	Mutex_; | ||||
| 		Types::NotifyTable      Notifiers_; | ||||
| 		Poco::Thread        	Worker_; | ||||
| 		std::atomic_bool    	Running_=false; | ||||
| 		mutable std::atomic_bool    	Running_=false; | ||||
| 		uint64_t          		FunctionId_=1; | ||||
| 		Poco::NotificationQueue	Queue_; | ||||
| 	}; | ||||
| @@ -2885,6 +2905,7 @@ namespace OpenWifi { | ||||
|  | ||||
| 	            void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) override | ||||
| 	            { | ||||
| 					Utils::SetThreadName("alb-request"); | ||||
| 					try { | ||||
| 						if((id_ % 100) == 0) { | ||||
| 							Logger_.debug(fmt::format("ALB-REQUEST({}): ALB Request {}.", | ||||
| @@ -2953,7 +2974,7 @@ namespace OpenWifi { | ||||
| 	    std::unique_ptr<Poco::Net::HTTPServer>   	Server_; | ||||
| 	    std::unique_ptr<Poco::Net::ServerSocket> 	Socket_; | ||||
| 	    int                                     	Port_ = 0; | ||||
| 	    std::atomic_bool                            Running_=false; | ||||
| 	    mutable std::atomic_bool                            Running_=false; | ||||
| 	}; | ||||
|  | ||||
| 	inline auto ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); } | ||||
| @@ -2985,7 +3006,7 @@ namespace OpenWifi { | ||||
|  | ||||
| 	    inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) { | ||||
| 	        RESTAPIHandler::BindingMap Bindings; | ||||
| 			Poco::Thread::current()->setName(fmt::format("RESTAPI_ExtServer_{}",Id)); | ||||
| 			Utils::SetThreadName(fmt::format("rest_ext_{}",Id).c_str()); | ||||
| 	        return RESTAPI_ExtRouter(Path, Bindings, Logger(), Server_, Id); | ||||
| 	    } | ||||
|  | ||||
| @@ -3009,7 +3030,7 @@ namespace OpenWifi { | ||||
| 	    inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override { | ||||
| 			try { | ||||
| 				Poco::URI uri(Request.getURI()); | ||||
| 				Poco::Thread::current()->setName(fmt::format("ExtWebServer_{}",TransactionId_)); | ||||
| 				Utils::SetThreadName(fmt::format("rest_ext_{}",TransactionId_).c_str()); | ||||
| 				return RESTAPI_ExtServer()->CallServer(uri.getPath(), TransactionId_++); | ||||
| 			} catch (...) { | ||||
|  | ||||
| @@ -3118,7 +3139,7 @@ namespace OpenWifi { | ||||
|  | ||||
| 	    inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) { | ||||
| 	        RESTAPIHandler::BindingMap Bindings; | ||||
| 			Poco::Thread::current()->setName(fmt::format("RESTAPI_IntServer_{}",Id)); | ||||
| 			Utils::SetThreadName(fmt::format("rest_int_{}",Id).c_str()); | ||||
| 	        return RESTAPI_IntRouter(Path, Bindings, Logger(), Server_, Id); | ||||
| 	    } | ||||
| 	private: | ||||
| @@ -3527,6 +3548,8 @@ namespace OpenWifi { | ||||
|     void DaemonPostInitialization(Poco::Util::Application &self); | ||||
|  | ||||
| 	inline void MicroService::initialize(Poco::Util::Application &self) { | ||||
| 		// Utils::SetThreadName("microservice"); | ||||
|  | ||||
| 		// add the default services | ||||
|         LoadConfigurationFile(); | ||||
|         InitializeLoggingSystem(); | ||||
| @@ -3922,6 +3945,7 @@ namespace OpenWifi { | ||||
|  | ||||
|     inline int MicroService::main([[maybe_unused]] const ArgVec &args) { | ||||
|  | ||||
| 		// Utils::SetThreadName("main"); | ||||
| 	    MyErrorHandler	ErrorHandler(*this); | ||||
| 	    Poco::ErrorHandler::set(&ErrorHandler); | ||||
|  | ||||
| @@ -4037,6 +4061,7 @@ namespace OpenWifi { | ||||
|  | ||||
|     inline void BusEventManager::run() { | ||||
|         Running_ = true; | ||||
| 		Utils::SetThreadName("BusEventManager"); | ||||
|         auto Msg = MicroService::instance().MakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN); | ||||
|         KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroService::instance().PrivateEndPoint(),Msg, false); | ||||
|         while(Running_) { | ||||
| @@ -4122,6 +4147,8 @@ namespace OpenWifi { | ||||
| 	} | ||||
|  | ||||
| 	inline void KafkaProducer::run() { | ||||
|  | ||||
| 		Utils::SetThreadName("KafkaProducer"); | ||||
| 	    cppkafka::Configuration Config({ | ||||
|             { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, | ||||
|             { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") } | ||||
| @@ -4160,6 +4187,8 @@ namespace OpenWifi { | ||||
| 	} | ||||
|  | ||||
| 	inline void KafkaConsumer::run() { | ||||
| 		Utils::SetThreadName("KafkaConsumer"); | ||||
|  | ||||
| 	    cppkafka::Configuration Config({ | ||||
| 	        { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, | ||||
| 	        { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") }, | ||||
| @@ -4818,7 +4847,7 @@ namespace OpenWifi { | ||||
| 		[[nodiscard]] bool SendToUser(const std::string &userName, const std::string &Payload); | ||||
| 		void SendToAll(const std::string &Payload); | ||||
|     private: | ||||
|         std::atomic_bool Running_ = false; | ||||
|         mutable std::atomic_bool Running_ = false; | ||||
|         Poco::Thread Thr_; | ||||
|         // std::unique_ptr<MyParallelSocketReactor> ReactorPool_; | ||||
| 		Poco::Net::SocketReactor					Reactor_; | ||||
| @@ -4915,6 +4944,7 @@ namespace OpenWifi { | ||||
|  | ||||
|     inline void WebSocketClientServer::run() { | ||||
|         Running_ = true ; | ||||
| 		Utils::SetThreadName("ws:clnt-svr"); | ||||
|         while(Running_) { | ||||
|             Poco::Thread::trySleep(2000); | ||||
|  | ||||
| @@ -4962,8 +4992,12 @@ namespace OpenWifi { | ||||
|  | ||||
|         for(const auto &client:Clients_) { | ||||
|             if(client.second.second == UserName) { | ||||
| 				try { | ||||
| 					if (client.second.first->Send(Payload)) | ||||
| 						Sent++; | ||||
| 				} catch (...) { | ||||
| 					return false; | ||||
| 				} | ||||
|             } | ||||
|         } | ||||
|         return Sent>0; | ||||
| @@ -4985,6 +5019,7 @@ namespace OpenWifi { | ||||
|         int flags; | ||||
|         int n; | ||||
|         bool Done=false; | ||||
| 		try { | ||||
| 			Poco::Buffer<char> IncomingFrame(0); | ||||
| 			n = WS_->receiveFrame(IncomingFrame, flags); | ||||
| 			auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK; | ||||
| @@ -4998,23 +5033,21 @@ namespace OpenWifi { | ||||
| 				WS_->sendFrame("", 0, | ||||
| 							   (int)Poco::Net::WebSocket::FRAME_OP_PONG | | ||||
| 								   (int)Poco::Net::WebSocket::FRAME_FLAG_FIN); | ||||
|             } | ||||
|                 break; | ||||
| 			} break; | ||||
| 			case Poco::Net::WebSocket::FRAME_OP_PONG: { | ||||
|             } | ||||
|                 break; | ||||
| 			} break; | ||||
| 			case Poco::Net::WebSocket::FRAME_OP_CLOSE: { | ||||
| 				Logger().warning(Poco::format("CLOSE(%s): Client is closing its connection.", Id_)); | ||||
| 				Done = true; | ||||
|             } | ||||
|                 break; | ||||
| 			} break; | ||||
| 			case Poco::Net::WebSocket::FRAME_OP_TEXT: { | ||||
| 				IncomingFrame.append(0); | ||||
| 				if (!Authenticated_) { | ||||
| 					std::string Frame{IncomingFrame.begin()}; | ||||
| 					auto Tokens = Utils::Split(Frame, ':'); | ||||
| 					bool Expired = false, Contacted = false; | ||||
|                     if(Tokens.size()==2 && AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) { | ||||
| 					if (Tokens.size() == 2 && | ||||
| 						AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) { | ||||
| 						Authenticated_ = true; | ||||
| 						std::string S{"Welcome! Bienvenue! Bienvenidos!"}; | ||||
| 						WS_->sendFrame(S.c_str(), S.size()); | ||||
| @@ -5028,8 +5061,8 @@ namespace OpenWifi { | ||||
| 				} else { | ||||
| 					try { | ||||
| 						Poco::JSON::Parser P; | ||||
|                         auto Obj = P.parse(IncomingFrame.begin()) | ||||
|                                 .extract<Poco::JSON::Object::Ptr>(); | ||||
| 						auto Obj = | ||||
| 							P.parse(IncomingFrame.begin()).extract<Poco::JSON::Object::Ptr>(); | ||||
| 						std::string Answer; | ||||
| 						if (Processor_ != nullptr) | ||||
| 							Processor_->Processor(Obj, Answer, Done); | ||||
| @@ -5040,14 +5073,15 @@ namespace OpenWifi { | ||||
| 						} | ||||
| 					} catch (const Poco::JSON::JSONException &E) { | ||||
| 						Logger().log(E); | ||||
| 						Done=true; | ||||
| 					} | ||||
| 				} | ||||
| 			} break; | ||||
| 			default: { | ||||
| 			} | ||||
|                 break; | ||||
|             default: | ||||
|             { | ||||
|  | ||||
| 			} | ||||
| 		} catch (...) { | ||||
| 			Done=true; | ||||
| 		} | ||||
|  | ||||
|         if(Done) { | ||||
|   | ||||
| @@ -133,6 +133,37 @@ namespace ORM { | ||||
|         return R; | ||||
|     } | ||||
|  | ||||
|     inline std::string WHERE_AND_(std::string Result) { | ||||
|         return Result; | ||||
|     } | ||||
|  | ||||
|     template <typename T, typename... Args> std::string WHERE_AND_(std::string Result, const char *fieldName, const T &Value, Args... args) { | ||||
|         if constexpr(std::is_same_v<T,std::string>) | ||||
|         { | ||||
|             if(!Value.empty()) { | ||||
|                 if(!Result.empty()) | ||||
|                     Result += " and "; | ||||
|                 Result += fieldName; | ||||
|                 Result += '='; | ||||
|                 Result += "'"; | ||||
|                 Result += Escape(Value); | ||||
|                 Result += "'"; | ||||
|             } | ||||
|         } else { | ||||
|             if(!Result.empty()) | ||||
|                 Result += " and "; | ||||
|             Result += fieldName ; | ||||
|             Result += '='; | ||||
|             Result += std::to_string(Value); | ||||
|         } | ||||
|         return WHERE_AND_(Result,args...); | ||||
|     } | ||||
|  | ||||
|     template <typename... Args> std::string WHERE_AND(Args... args) { | ||||
|         std::string Result; | ||||
|         return WHERE_AND_(Result, args...); | ||||
|     } | ||||
|  | ||||
|     enum SqlComparison { EQ = 0, NEQ, LT, LTE, GT, GTE }; | ||||
|     enum SqlBinaryOp { AND = 0 , OR }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										13
									
								
								src/ow_version.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/ow_version.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| // | ||||
| // Created by stephane bourque on 2021-12-06. | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <string> | ||||
|  | ||||
| namespace OW_VERSION { | ||||
|     inline static const std::string VERSION{"2.6.0"}; | ||||
|     inline static const std::string BUILD{"128"}; | ||||
|     inline static const std::string HASH{"3b0f2a0"}; | ||||
| } | ||||
| @@ -96,7 +96,7 @@ namespace OpenWifi { | ||||
|     void EntityDB::AddVenues(Poco::JSON::Object &Tree, const std::string & Node) { | ||||
|         ProvObjects::Venue E; | ||||
|         // std::cout << "Adding venue:" << Node << std::endl; | ||||
|         StorageService()->VenueDB().GetRecord("id",Node,E); | ||||
|         if(StorageService()->VenueDB().GetRecord("id",Node,E)) { | ||||
|             Poco::JSON::Array Venues; | ||||
|             for (const auto &i: E.children) { | ||||
|                 Poco::JSON::Object Venue; | ||||
| @@ -108,11 +108,12 @@ namespace OpenWifi { | ||||
|             Tree.set("uuid", E.info.id); | ||||
|             Tree.set("children", Venues); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void EntityDB::BuildTree(Poco::JSON::Object &Tree, const std::string & Node) { | ||||
|         ProvObjects::Entity E; | ||||
|         // std::cout << "Adding node:" << Node << std::endl; | ||||
|         StorageService()->EntityDB().GetRecord("id",Node,E); | ||||
|         if(StorageService()->EntityDB().GetRecord("id",Node,E)) { | ||||
|             Poco::JSON::Array Children; | ||||
|             for (const auto &i: E.children) { | ||||
|                 Poco::JSON::Object Child; | ||||
| @@ -131,6 +132,7 @@ namespace OpenWifi { | ||||
|             Tree.set("children", Children); | ||||
|             Tree.set("venues", Venues); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void EntityDB::ImportVenues(const Poco::JSON::Object::Ptr &O, const std::string &Parent) { | ||||
|         std::string             Type, Name, UUID; | ||||
|   | ||||
| @@ -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: | ||||
|     }; | ||||
| } | ||||
| @@ -499,6 +499,14 @@ listvenues() { | ||||
|     jq < ${result_file} | ||||
| } | ||||
|  | ||||
| getvenuedevices() { | ||||
|     curl    ${FLAGS} -X GET "https://${OWPROV}/api/v1/venue/$1?getDevices=true&getChildren=true" \ | ||||
|         -H "Content-Type: application/json" \ | ||||
|         -H "Authorization: Bearer ${token}" \ | ||||
|         -H "Accept: application/json" > ${result_file} | ||||
|     jq < ${result_file} | ||||
| } | ||||
|  | ||||
| shopt -s nocasematch | ||||
| case "$1" in | ||||
|     "login") login; echo "You are logged in..."  ; logout ;; | ||||
| @@ -546,6 +554,7 @@ case "$1" in | ||||
|     "getsignup") login; getsignup $2; logout;; | ||||
|     "getsubdevs") login; getsubdevs $2; logout;; | ||||
|     "listvenues") login; listvenues $2; logout;; | ||||
|     "getvenuedevices") login; getvenuedevices $2; logout;; | ||||
|     *) help ;; | ||||
| esac | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user