mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralgw.git
synced 2025-10-28 17:32:26 +00:00
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
This commit is contained in:
2
.idea/.gitignore
generated
vendored
2
.idea/.gitignore
generated
vendored
@@ -6,3 +6,5 @@
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# GitHub Copilot persisted chat sessions
|
||||
/copilot/chatSessions
|
||||
|
||||
@@ -551,6 +551,12 @@ components:
|
||||
lastModified:
|
||||
type: integer
|
||||
format: int64
|
||||
platform:
|
||||
type: string
|
||||
enum:
|
||||
- AP
|
||||
- SWITCH
|
||||
default: AP
|
||||
|
||||
DefaultConfigurationList:
|
||||
properties:
|
||||
@@ -1963,15 +1969,6 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
- in: query
|
||||
name: deviceType
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- AP
|
||||
- SWITCH
|
||||
required: false
|
||||
default: AP
|
||||
requestBody:
|
||||
description: Information used to create the new device
|
||||
content:
|
||||
@@ -2018,15 +2015,6 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
- in: query
|
||||
name: deviceType
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- AP
|
||||
- SWITCH
|
||||
required: false
|
||||
default: AP
|
||||
requestBody:
|
||||
description: Configuration details
|
||||
content:
|
||||
|
||||
@@ -76,15 +76,11 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
AP_WS_Connection::~AP_WS_Connection() {
|
||||
// poco_information(Logger_, fmt::format("DESTRUCTOR({}): 0 - Session={} Connection closed.", SerialNumber_,
|
||||
// State_.sessionId));
|
||||
// std::lock_guard G(ConnectionMutex_);
|
||||
// poco_information(Logger_, fmt::format("DESTRUCTOR({}): 1 - Session={} Connection closed.", SerialNumber_,
|
||||
// State_.sessionId));
|
||||
EndConnection(false);
|
||||
poco_debug(Logger_, fmt::format("TERMINATION({}): Session={}, Connection removed.", SerialNumber_,
|
||||
State_.sessionId));
|
||||
std::lock_guard G(ConnectionMutex_);
|
||||
AP_WS_Server()->DecrementConnectionCount();
|
||||
EndConnection();
|
||||
poco_debug(Logger_, fmt::format("TERMINATION({}): Session={}, Connection removed.", SerialNumber_,
|
||||
State_.sessionId));
|
||||
}
|
||||
|
||||
static void NotifyKafkaDisconnect(const std::string &SerialNumber, std::uint64_t uuid) {
|
||||
@@ -100,7 +96,7 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
void AP_WS_Connection::EndConnection(bool Clean) {
|
||||
void AP_WS_Connection::EndConnection() {
|
||||
bool expectedValue=false;
|
||||
if (Dead_.compare_exchange_strong(expectedValue,true,std::memory_order_release,std::memory_order_relaxed)) {
|
||||
|
||||
@@ -126,9 +122,7 @@ namespace OpenWifi {
|
||||
if(!SerialNumber_.empty()) {
|
||||
DeviceDisconnectionCleanup(SerialNumber_, uuid_);
|
||||
}
|
||||
|
||||
if(Clean)
|
||||
AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_);
|
||||
AP_WS_Server()->AddCleanupSession(State_.sessionId, SerialNumberInt_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace OpenWifi {
|
||||
Poco::Logger &L, std::pair<std::shared_ptr<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession>> R);
|
||||
~AP_WS_Connection();
|
||||
|
||||
void EndConnection(bool Clean = true);
|
||||
void EndConnection();
|
||||
void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc);
|
||||
void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
|
||||
void ProcessIncomingFrame();
|
||||
@@ -108,7 +108,7 @@ namespace OpenWifi {
|
||||
void Start();
|
||||
|
||||
private:
|
||||
std::recursive_mutex ConnectionMutex_;
|
||||
mutable std::recursive_mutex ConnectionMutex_;
|
||||
std::mutex TelemetryMutex_;
|
||||
Poco::Logger &Logger_;
|
||||
std::shared_ptr<Poco::Net::SocketReactor> Reactor_;
|
||||
|
||||
@@ -200,9 +200,31 @@ namespace OpenWifi {
|
||||
Running_ = true;
|
||||
GarbageCollector_.setName("ws:garbage");
|
||||
GarbageCollector_.start(*this);
|
||||
|
||||
std::thread CleanupThread([this](){ CleanupSessions(); });
|
||||
CleanupThread.detach();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AP_WS_Server::CleanupSessions() {
|
||||
|
||||
while(Running_) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
|
||||
while(Running_ && !CleanupSessions_.empty()) {
|
||||
std::pair<uint64_t, uint64_t> Session;
|
||||
{
|
||||
std::lock_guard G(CleanupMutex_);
|
||||
Session = CleanupSessions_.front();
|
||||
CleanupSessions_.pop_front();
|
||||
}
|
||||
this->Logger().information(fmt::format("Cleaning up session: {} for device: {}", Session.first, Utils::IntToSerialNumber(Session.second)));
|
||||
EndSession(Session.first, Session.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AP_WS_Server::run() {
|
||||
uint64_t last_log = Utils::Now(),
|
||||
last_zombie_run = 0,
|
||||
@@ -236,29 +258,35 @@ namespace OpenWifi {
|
||||
waits = 0;
|
||||
auto hint = SerialNumbers_[hashIndex].begin();
|
||||
while (hint != end(SerialNumbers_[hashIndex])) {
|
||||
|
||||
if (hint->second == nullptr) {
|
||||
poco_information(
|
||||
LocalLogger,
|
||||
fmt::format("Dead device found in hash index {}", hashIndex));
|
||||
hint = SerialNumbers_[hashIndex].erase(hint);
|
||||
continue;
|
||||
}
|
||||
auto Device = hint->second;
|
||||
auto RightNow = Utils::Now();
|
||||
if (RightNow > Device->LastContact_ &&
|
||||
(RightNow - Device->LastContact_) > SessionTimeOut_) {
|
||||
poco_information(
|
||||
LocalLogger,
|
||||
fmt::format("{}: Session seems idle. Controller disconnecting device.",
|
||||
Device->SerialNumber_));
|
||||
hint = SerialNumbers_[hashIndex].erase(hint);
|
||||
} else if (Device->State_.Connected) {
|
||||
total_connected_time +=
|
||||
(RightNow - Device->State_.started);
|
||||
++hint;
|
||||
} else {
|
||||
++hint;
|
||||
auto Device = hint->second;
|
||||
auto RightNow = Utils::Now();
|
||||
if (Device->Dead_) {
|
||||
AddCleanupSession(Device->State_.sessionId, Device->SerialNumberInt_);
|
||||
++hint;
|
||||
// hint = SerialNumbers_[hashIndex].erase(hint);
|
||||
} else if (RightNow > Device->LastContact_ &&
|
||||
(RightNow - Device->LastContact_) > SessionTimeOut_) {
|
||||
poco_information(
|
||||
LocalLogger,
|
||||
fmt::format(
|
||||
"{}: Session seems idle. Controller disconnecting device.",
|
||||
Device->SerialNumber_));
|
||||
// hint = SerialNumbers_[hashIndex].erase(hint);
|
||||
AddCleanupSession(Device->State_.sessionId, Device->SerialNumberInt_);
|
||||
++hint;
|
||||
} else {
|
||||
if (Device->State_.Connected) {
|
||||
total_connected_time +=
|
||||
(RightNow - Device->State_.started);
|
||||
}
|
||||
++hint;
|
||||
}
|
||||
}
|
||||
}
|
||||
SerialNumbersMutex_[hashIndex].unlock();
|
||||
@@ -272,8 +300,7 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
poco_information(LocalLogger,
|
||||
fmt::format("Garbage collecting zombies... (step 2)"));
|
||||
poco_information(LocalLogger, fmt::format("Garbage collecting zombies... (step 2)"));
|
||||
LeftOverSessions_ = 0;
|
||||
for (int i = 0; i < SessionHash::HashMax(); i++) {
|
||||
waits = 0;
|
||||
@@ -285,6 +312,10 @@ namespace OpenWifi {
|
||||
while (hint != end(Sessions_[i])) {
|
||||
if (hint->second == nullptr) {
|
||||
hint = Sessions_[i].erase(hint);
|
||||
} else if (hint->second->Dead_) {
|
||||
// hint = Sessions_[i].erase(hint);
|
||||
AddCleanupSession(hint->second->State_.sessionId, hint->second->SerialNumberInt_);
|
||||
++hint;
|
||||
} else if (RightNow > hint->second->LastContact_ &&
|
||||
(RightNow - hint->second->LastContact_) >
|
||||
SessionTimeOut_) {
|
||||
@@ -292,7 +323,9 @@ namespace OpenWifi {
|
||||
LocalLogger,
|
||||
fmt::format("{}: Session seems idle. Controller disconnecting device.",
|
||||
hint->second->SerialNumber_));
|
||||
hint = Sessions_[i].erase(hint);
|
||||
AddCleanupSession(hint->second->State_.sessionId, hint->second->SerialNumberInt_);
|
||||
++hint;
|
||||
// hint = Sessions_[i].erase(hint);
|
||||
} else {
|
||||
++LeftOverSessions_;
|
||||
++hint;
|
||||
@@ -309,10 +342,9 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
AverageDeviceConnectionTime_ =
|
||||
NumberOfConnectedDevices_ > 0
|
||||
? total_connected_time / NumberOfConnectedDevices_
|
||||
: 0;
|
||||
AverageDeviceConnectionTime_ = NumberOfConnectedDevices_ > 0
|
||||
? total_connected_time / NumberOfConnectedDevices_
|
||||
: 0;
|
||||
poco_information(LocalLogger, fmt::format("Garbage collecting zombies done..."));
|
||||
} catch (const Poco::Exception &E) {
|
||||
poco_error(LocalLogger, fmt::format("Poco::Exception: Garbage collecting zombies failed: {}", E.displayText()));
|
||||
@@ -323,12 +355,11 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(NumberOfConnectedDevices_) {
|
||||
if (last_garbage_run > 0) {
|
||||
AverageDeviceConnectionTime_ += (now - last_garbage_run);
|
||||
}
|
||||
} else {
|
||||
AverageDeviceConnectionTime_ = 0;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -445,17 +476,21 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void AP_WS_Server::StartSession(uint64_t session_id, uint64_t SerialNumber) {
|
||||
auto deviceHash = MACHash::Hash(SerialNumber);
|
||||
auto sessionHash = SessionHash::Hash(session_id);
|
||||
std::lock_guard SessionLock(SessionMutex_[sessionHash]);
|
||||
auto SessionHint = Sessions_[sessionHash].find(session_id);
|
||||
if (SessionHint != end(Sessions_[sessionHash])) {
|
||||
std::lock_guard Lock(SerialNumbersMutex_[deviceHash]);
|
||||
SerialNumbers_[deviceHash][SerialNumber] = SessionHint->second;
|
||||
std::shared_ptr<AP_WS_Connection> Connection;
|
||||
{
|
||||
std::lock_guard SessionLock(SessionMutex_[sessionHash]);
|
||||
auto SessionHint = Sessions_[sessionHash].find(session_id);
|
||||
if (SessionHint == end(Sessions_[sessionHash])) {
|
||||
return;
|
||||
}
|
||||
Connection = SessionHint->second;
|
||||
Sessions_[sessionHash].erase(SessionHint);
|
||||
} else {
|
||||
poco_error(Logger(), fmt::format("StartSession: Could not find session '{}'", session_id));
|
||||
}
|
||||
|
||||
auto deviceHash = MACHash::Hash(SerialNumber);
|
||||
std::lock_guard Lock(SerialNumbersMutex_[deviceHash]);
|
||||
SerialNumbers_[deviceHash][SerialNumber] = Connection;
|
||||
}
|
||||
|
||||
bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t SerialNumber) {
|
||||
|
||||
@@ -203,6 +203,13 @@ namespace OpenWifi {
|
||||
--NumberOfConnectedDevices_;
|
||||
}
|
||||
|
||||
inline void AddCleanupSession(uint64_t session_id, uint64_t SerialNumber) {
|
||||
std::lock_guard G(CleanupMutex_);
|
||||
CleanupSessions_.emplace_back(session_id, SerialNumber);
|
||||
}
|
||||
|
||||
void CleanupSessions();
|
||||
|
||||
private:
|
||||
std::array<std::mutex,SessionHashMax> SessionMutex_;
|
||||
std::array<std::map<std::uint64_t, std::shared_ptr<AP_WS_Connection>>,SessionHashMax> Sessions_;
|
||||
@@ -222,6 +229,10 @@ namespace OpenWifi {
|
||||
bool SimulatorEnabled_ = false;
|
||||
bool AllowSerialNumberMismatch_ = true;
|
||||
|
||||
Poco::Thread CleanupThread_;
|
||||
std::mutex CleanupMutex_;
|
||||
std::deque<std::pair<uint64_t, uint64_t>> CleanupSessions_;
|
||||
|
||||
std::unique_ptr<AP_WS_ReactorThreadPool> Reactor_pool_;
|
||||
std::atomic_bool Running_ = false;
|
||||
|
||||
|
||||
@@ -60,9 +60,13 @@ namespace OpenWifi {
|
||||
return BadRequest(RESTAPI::Errors::ModelIDListCannotBeEmpty);
|
||||
}
|
||||
|
||||
auto DeviceType = GetParameter("deviceType", "AP");
|
||||
DefConfig.Platform = DefConfig.Platform.empty() ? "AP" : DefConfig.Platform;
|
||||
if(DefConfig.Platform != "AP" && DefConfig.Platform != "SWITCH") {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
std::string Error;
|
||||
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(DeviceType),
|
||||
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(DefConfig.Platform),
|
||||
DefConfig.Configuration, Error,
|
||||
GetBoolParameter("strict", false))) {
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid, Error);
|
||||
@@ -90,10 +94,20 @@ namespace OpenWifi {
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if(Existing.Platform.empty()) {
|
||||
Existing.Platform = "AP";
|
||||
}
|
||||
|
||||
if(ParsedBody_->has("platform")) {
|
||||
if(NewConfig.Platform.empty() || (NewConfig.Platform != "AP" && NewConfig.Platform != "SWITCH")) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
Existing.Platform = NewConfig.Platform;
|
||||
}
|
||||
|
||||
if (!NewConfig.Configuration.empty()) {
|
||||
auto DeviceType = GetParameter("deviceType", "AP");
|
||||
std::string Error;
|
||||
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(DeviceType),
|
||||
if (!ValidateUCentralConfiguration(ConfigurationValidator::GetType(Existing.Platform),
|
||||
NewConfig.Configuration, Error,
|
||||
GetBoolParameter("strict", false))) {
|
||||
return BadRequest(RESTAPI::Errors::ConfigBlockInvalid, Error);
|
||||
|
||||
@@ -184,15 +184,6 @@ namespace OpenWifi::GWObjects {
|
||||
return false;
|
||||
}
|
||||
|
||||
void DefaultConfiguration::to_json(Poco::JSON::Object &Obj) const {
|
||||
EmbedDocument("configuration", Obj, Configuration);
|
||||
field_to_json(Obj, "name", Name);
|
||||
field_to_json(Obj, "modelIds", Models);
|
||||
field_to_json(Obj, "description", Description);
|
||||
field_to_json(Obj, "created", Created);
|
||||
field_to_json(Obj, "lastModified", LastModified);
|
||||
}
|
||||
|
||||
void DefaultFirmware::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "deviceType", deviceType);
|
||||
field_to_json(Obj, "description", Description);
|
||||
@@ -240,12 +231,25 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj, "deferred", deferred);
|
||||
}
|
||||
|
||||
void DefaultConfiguration::to_json(Poco::JSON::Object &Obj) const {
|
||||
EmbedDocument("configuration", Obj, Configuration);
|
||||
field_to_json(Obj, "name", Name);
|
||||
field_to_json(Obj, "modelIds", Models);
|
||||
field_to_json(Obj, "description", Description);
|
||||
field_to_json(Obj, "created", Created);
|
||||
field_to_json(Obj, "lastModified", LastModified);
|
||||
field_to_json(Obj, "Platform", Platform);
|
||||
}
|
||||
|
||||
bool DefaultConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "name", Name);
|
||||
field_from_json(Obj, "configuration", Configuration);
|
||||
field_from_json(Obj, "name", Name);
|
||||
field_from_json(Obj, "modelIds", Models);
|
||||
field_from_json(Obj, "description", Description);
|
||||
field_from_json(Obj, "created", Created);
|
||||
field_from_json(Obj, "lastModified", LastModified);
|
||||
field_from_json(Obj, "Platform", Platform);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
|
||||
@@ -186,6 +186,7 @@ namespace OpenWifi::GWObjects {
|
||||
std::string Description;
|
||||
uint64_t Created;
|
||||
uint64_t LastModified;
|
||||
std::string Platform;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
@@ -200,6 +200,7 @@ namespace OpenWifi {
|
||||
bool GetDefaultConfigurations(uint64_t From, uint64_t HowMany,
|
||||
std::vector<GWObjects::DefaultConfiguration> &Devices);
|
||||
bool FindDefaultConfigurationForModel(const std::string &Model,
|
||||
const std::string &Platform,
|
||||
GWObjects::DefaultConfiguration &DefConfig);
|
||||
uint64_t GetDefaultConfigurationsCount();
|
||||
bool DefaultConfigurationAlreadyExists(std::string &Name);
|
||||
|
||||
@@ -19,18 +19,18 @@ namespace OpenWifi {
|
||||
"Models TEXT, "
|
||||
"Description TEXT, "
|
||||
"Created BIGINT , "
|
||||
"LastModified BIGINT)"};
|
||||
"LastModified BIGINT, Platform TEXT )"};
|
||||
|
||||
const static std::string DB_DefConfig_SelectFields{"Name, "
|
||||
"Configuration, "
|
||||
"Models, "
|
||||
"Description, "
|
||||
"Created, "
|
||||
"LastModified "};
|
||||
"LastModified, Platform "};
|
||||
|
||||
const static std::string DB_DefConfig_InsertValues{"?,?,?,?,?,?"};
|
||||
const static std::string DB_DefConfig_InsertValues{"?,?,?,?,?,?,?"};
|
||||
|
||||
typedef Poco::Tuple<std::string, std::string, std::string, std::string, uint64_t, uint64_t>
|
||||
typedef Poco::Tuple<std::string, std::string, std::string, std::string, uint64_t, uint64_t, std::string>
|
||||
DefConfigRecordTuple;
|
||||
typedef std::vector<DefConfigRecordTuple> DefConfigRecordList;
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace OpenWifi {
|
||||
T.Description = R.get<3>();
|
||||
T.Created = R.get<4>();
|
||||
T.LastModified = R.get<5>();
|
||||
T.Platform = R.get<6>();
|
||||
}
|
||||
|
||||
void Convert(const GWObjects::DefaultConfiguration &R, DefConfigRecordTuple &T) {
|
||||
@@ -50,6 +51,7 @@ namespace OpenWifi {
|
||||
T.set<3>(R.Description);
|
||||
T.set<4>(R.Created);
|
||||
T.set<5>(R.LastModified);
|
||||
T.set<6>(R.Platform);
|
||||
}
|
||||
|
||||
bool Storage::CreateDefaultConfiguration(std::string &Name,
|
||||
@@ -127,7 +129,7 @@ namespace OpenWifi {
|
||||
DefConfig.LastModified = Now;
|
||||
|
||||
std::string St{"UPDATE DefaultConfigs SET Name=?, Configuration=?, Models=?, "
|
||||
"Description=?, Created=? , LastModified=? WHERE Name=?"};
|
||||
"Description=?, Created=? , LastModified=? , Platform=? WHERE Name=?"};
|
||||
|
||||
DefConfigRecordTuple R;
|
||||
Convert(DefConfig, R);
|
||||
@@ -219,7 +221,7 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::FindDefaultConfigurationForModel(const std::string &Model,
|
||||
bool Storage::FindDefaultConfigurationForModel(const std::string &Model, const std::string &Platform,
|
||||
GWObjects::DefaultConfiguration &DefConfig) {
|
||||
try {
|
||||
DefConfigRecordList Records;
|
||||
@@ -235,7 +237,7 @@ namespace OpenWifi {
|
||||
GWObjects::DefaultConfiguration Config;
|
||||
Convert(i, Config);
|
||||
for (const auto &j : Config.Models) {
|
||||
if (j == "*" || j == Model) {
|
||||
if ((j == "*" || j == Model) && (Poco::toUpper(Config.Platform) == Poco::toUpper(Platform))){
|
||||
DefConfig = Config;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -578,11 +578,11 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
if (!Found && AP_WS_Server()->UseDefaults() &&
|
||||
FindDefaultConfigurationForModel(Caps.Compatible(), DefConfig)) {
|
||||
FindDefaultConfigurationForModel(Caps.Compatible(), Caps.Platform(), DefConfig)) {
|
||||
Config::Config NewConfig(DefConfig.Configuration);
|
||||
NewConfig.SetUUID(Now);
|
||||
D.Configuration = NewConfig.get();
|
||||
} else if (!Found) {
|
||||
} else if (!Found && Caps.Platform()=="AP") {
|
||||
Config::Config NewConfig;
|
||||
NewConfig.SetUUID(Now);
|
||||
D.Configuration = NewConfig.get();
|
||||
|
||||
@@ -275,9 +275,21 @@ namespace OpenWifi {
|
||||
"Models TEXT, "
|
||||
"Description TEXT, "
|
||||
"Created BIGINT , "
|
||||
"LastModified BIGINT)",
|
||||
"LastModified BIGINT, Platform TEXT)",
|
||||
Poco::Data::Keywords::now;
|
||||
}
|
||||
|
||||
std::vector<std::string> Script{
|
||||
"alter table DefaultConfigs add column Platform text"
|
||||
};
|
||||
|
||||
for (const auto &i : Script) {
|
||||
try {
|
||||
Sess << i, Poco::Data::Keywords::now;
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger().log(E);
|
||||
|
||||
Reference in New Issue
Block a user