<commit_before>// Copyright 2016 Chirstopher Torres (Raven), L3nn0x
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http ://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "ccharserver.h"
#include "ccharclient.h"
#include "ccharisc.h"
#include "epackettype.h"
#include "platform_defines.h"
#include "connection.h"
#include <unordered_set>
#include "isc_client_status.h"
#include "logconsole.h"

#include <algorithm>

using namespace RoseCommon;

void update_status(const Packet::IscClientStatus& packet, CCharServer& server, User& user) {
    auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
    logger->debug("Char {} now has status {}", user.get_name(), packet.get_status());
    const bool isSwitching = user.get_status() == User::Status::SWITCHING ? true : false;
    user.set_status(packet.get_status());
    // we update the id every client on the map refers to when talking about this character. (this is different from the charId)
    user.set_entityId(packet.get_entityMapId());
    if (user.get_status() == User::Status::CONNECTED && isSwitching) {
        // reload the map
        Core::CharacterTable characterTable{};
        auto conn = Core::connectionPool.getConnection<Core::Osirose>();
        auto charRes = conn(sqlpp::select(characterTable.map)
                            .from(characterTable).where(characterTable.id == user.get_charId()));
        if (charRes.empty()) {
            logger->error("Error while trying to access the updated map of {}", user.get_name());
            return;
        }
        user.set_mapId(charRes.front().map);
    }
}

CCharServer::CCharServer(bool _isc, CCharServer *server) : CRoseServer(_isc), client_count_(0), server_count_(0), iscServer_(server) {
    register_dispatcher(std::function{update_status});
    register_dispatcher(std::function{party_request});

    reactor_thread = std::thread([this]() {
        for (auto [res, task] = work_queue.pop_front(); res;) {
            {
                std::lock_guard<std::recursive_mutex> lock(access);
                std::invoke(std::move(task), *this);
            }
            auto [tmp_res, tmp_task] = work_queue.pop_front();
            res = tmp_res;
            task = std::move(tmp_task);
        }
    });
}

CCharServer::~CCharServer() {
    socket_[SocketType::Client]->shutdown();
    work_queue.kill();
    reactor_thread.join();
}

void CCharServer::OnAccepted(std::unique_ptr<Core::INetwork> _sock) {
  //if (_sock->is_active()) {
    // Do Something?
    std::string _address = _sock->get_address();
    if (IsISCServer() == false) {
      std::lock_guard<std::mutex> lock(client_list_mutex_);
      std::shared_ptr<CCharClient> nClient = std::make_shared<CCharClient>(this, std::move(_sock));
      nClient->set_id(client_count_++);
      nClient->set_update_time( Core::Time::GetTickCount() );
      nClient->set_active(true);
      nClient->start_recv();
      logger_->info( "[{}] Client connected from: {}", nClient->get_id(),
                       _address.c_str());
      client_list_.push_front(std::move(nClient));
    } else {
      std::lock_guard<std::mutex> lock(isc_list_mutex_);
      std::shared_ptr<CCharISC> nClient = std::make_shared<CCharISC>(this, std::move(_sock));
      nClient->set_id(server_count_++);
      nClient->set_update_time( Core::Time::GetTickCount() );
      nClient->set_active(true);
      nClient->start_recv();
      logger_->info( "Server connected from: {}", _address.c_str() );
      isc_list_.push_front(std::move(nClient));
    }
  //}
}

void CCharServer::register_maps(CCharISC* isc, const std::vector<uint16_t>& maps) {
    std::shared_ptr<RoseCommon::CRoseClient> ptr;
    for (const auto& p : isc_list_) {
        if (p.get() == isc) {
            ptr = p;
            break;
        }
    }
    if (!ptr) {
        logger_->error("ISC server not found when registering maps!");
        return;
    }
    for (const auto& m : maps) {
        this->maps[m] = ptr;
    }
}

void CCharServer::transfer(RoseCommon::Packet::IscTransfer&& P) {
    const auto& m = P.get_maps();
    std::unordered_set<std::shared_ptr<CRoseClient>> set;
    if (m.empty()) {
        for (const auto& [m, p] : maps) {
            if (auto ptr = p.lock()) {
                set.insert(ptr);
            }
        }
    } else if (m.size() == 1 && m[0] == 0) {
        dispatch_packet(P.get_originatorId(),
                        RoseCommon::fetchPacket<true>(static_cast<const uint8_t*>(P.get_blob().data())));
        return;
    } else {
        for (const auto& mm : m) {
            if (auto ptr = maps[mm].lock()) {
                set.insert(ptr);
            }
        }
    }
    for (auto ptr : set) {
        ptr->send(P);
    }
}

void CCharServer::transfer_char(RoseCommon::Packet::IscTransferChar&& P) {
    std::vector<uint16_t> maps;
    for (auto name : P.get_names()) {
        if (const auto user = get_user(name); user) {
            maps.push_back(user.value()->get_mapId());
        }
    }
    std::unordered_set<std::shared_ptr<CRoseClient>> set;
    for (auto map : maps) {
        if (auto ptr = this->maps[map].lock()) {
            set.insert(ptr);
        }
    }
    for (auto ptr : set) {
        ptr->send(P);
    }
}

void CCharServer::send_map(uint16_t map, const RoseCommon::CRosePacket& p) {
    auto packet = RoseCommon::Packet::IscTransfer::create(0, {map});
    std::vector<uint8_t> blob;
    p.write_to_vector(blob);
    packet.set_blob(blob);
    if (auto ptr = maps[map].lock()) {
        ptr->send(packet);
    }
}

void CCharServer::send_char(uint32_t character, const RoseCommon::CRosePacket& p) {
    const auto user = get_user(character);
    if (!user) {
        return;
    }
    auto packet = RoseCommon::Packet::IscTransferChar::create({user.value()->get_name()});
    std::vector<uint8_t> blob;
    p.write_to_vector(blob);
    packet.set_blob(blob);

    if (auto ptr = maps[user.value()->get_mapId()].lock()) {
        ptr->send(packet);
    }
}

void CCharServer::send_char(const std::string& character, const RoseCommon::CRosePacket& p) {
    const auto user = get_user(character);
    if (!user) {
        return;
    }
    auto packet = RoseCommon::Packet::IscTransferChar::create({character});
    std::vector<uint8_t> blob;
    p.write_to_vector(blob);
    packet.set_blob(blob);

    if (auto ptr = maps[user.value()->get_mapId()].lock()) {
        ptr->send(packet);
    }
}

bool CCharServer::dispatch_packet(uint32_t charId, std::unique_ptr<RoseCommon::CRosePacket>&& packet) {
    if (!packet) {
        logger_->error("Empty packet");
        return false;
    }
    if (!dispatcher.is_supported(*packet.get())) {
        logger_->error("Packet not supported!");
        return false;
    }
    auto user = get_user(charId);
    if (!user) {
        logger_->error("User {} not loaded!", charId);
        return false;
    }
    work_queue.push_back([&user = *user.value(), packet = std::move(packet)](CCharServer& server) mutable {
        server.dispatcher.dispatch(std::move(packet), server, std::forward<User&>(user));
    });
    return true;
}

std::optional<const User*const> CCharServer::get_user(const std::string& name) const {
    if (const auto result = std::find_if(users.begin(), users.end(),
                                         [&name](const auto& user) { return user.second.get_name() == name; });
        result != users.end()) {
        return {&result->second};
    }
    return {};
}

std::optional<const User*const> CCharServer::get_user(uint32_t id) const {
    if (auto it = users.find(id); it != users.end()) {
        return {&it->second};
    }
    return {};
}

std::optional<const User*const> CCharServer::get_user(uint16_t id, uint16_t mapId) const {
    if (const auto result = std::find_if(users.begin(), users.end(), [id, mapId](const auto& user) {
            return user.second.get_mapId() == mapId && user.second.get_entityId() == id;
        }); result != users.end()) {
        return {&result->second};
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(const std::string& name) {
    if (auto result = std::find_if(users.begin(), users.end(),
                                   [&name](const auto& user) { return user.second.get_name() == name; });
        result != users.end()) {
        return {&result->second};
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(uint32_t id) {
    if (auto it = users.find(id); it != users.end()) {
        return {&it->second};
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(uint16_t id, uint16_t mapId) {
    if (auto result = std::find_if(users.begin(), users.end(), [id, mapId](const auto& user) {
            return user.second.get_mapId() == mapId && user.second.get_entityId() == id;
        }); result != users.end()) {
        return {&result->second};
    }
    return {};
}

void CCharServer::load_user(std::weak_ptr<CCharClient> client, uint32_t id) {
    Core::CharacterTable characterTable{};

    auto conn = Core::connectionPool.getConnection<Core::Osirose>();

    auto charRes = conn(sqlpp::select(characterTable.name, characterTable.map)
                          .from(characterTable).where(characterTable.id == id));

    if (charRes.empty()) {
        return;
    }
    User user(client, charRes.front().name, id, charRes.front().map);
    user.set_party(partys.get_party(id)); // we load the party if there is one for that character
}

void CCharServer::unload_user(uint32_t id) {
    users.erase(id);
}
<commit_msg>Update ccharserver.cpp<commit_after>// Copyright 2016 Chirstopher Torres (Raven), L3nn0x
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http ://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "ccharserver.h"
#include "ccharclient.h"
#include "ccharisc.h"
#include "epackettype.h"
#include "platform_defines.h"
#include "connection.h"
#include <unordered_set>
#include "isc_client_status.h"
#include "logconsole.h"

#include <algorithm>

using namespace RoseCommon;

void update_status(const Packet::IscClientStatus& packet, CCharServer& server, User& user) {
    auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
    logger->debug("Char {} now has status {}", user.get_name(), packet.get_status());
    const bool isSwitching = user.get_status() == User::Status::SWITCHING ? true : false;
    user.set_status(packet.get_status());
    // we update the id every client on the map refers to when talking about this character. (this is different from the charId)
    user.set_entityId(packet.get_entityMapId());
    if (user.get_status() == User::Status::CONNECTED && isSwitching) {
        // reload the map
        Core::CharacterTable characterTable{};
        auto conn = Core::connectionPool.getConnection<Core::Osirose>();
        auto charRes = conn(sqlpp::select(characterTable.map)
                            .from(characterTable).where(characterTable.id == user.get_charId()));
        if (charRes.empty()) {
            logger->error("Error while trying to access the updated map of {}", user.get_name());
            return;
        }
        user.set_mapId(charRes.front().map);
    }
}

CCharServer::CCharServer(bool _isc, CCharServer *server) : CRoseServer(_isc), client_count_(0), server_count_(0), iscServer_(server) {
    register_dispatcher(std::function{update_status});
    register_dispatcher(std::function{party_request});

    reactor_thread = std::thread([this]() {
        for (auto [res, task] = work_queue.pop_front(); res;) {
            {
                std::lock_guard<std::recursive_mutex> lock(access);
                std::invoke(std::move(task), *this);
            }
            auto [tmp_res, tmp_task] = work_queue.pop_front();
            res = tmp_res;
            task = std::move(tmp_task);
        }
    });
}

CCharServer::~CCharServer() {
    socket_[SocketType::Client]->shutdown();
    work_queue.kill();
    reactor_thread.join();
}

void CCharServer::OnAccepted(std::unique_ptr<Core::INetwork> _sock) {
  //if (_sock->is_active()) {
    // Do Something?
    std::string _address = _sock->get_address();
    if (IsISCServer() == false) {
      std::lock_guard<std::mutex> lock(client_list_mutex_);
      std::shared_ptr<CCharClient> nClient = std::make_shared<CCharClient>(this, std::move(_sock));
      nClient->set_id(client_count_++);
      nClient->set_update_time( Core::Time::GetTickCount() );
      nClient->set_active(true);
      nClient->start_recv();
      logger_->info( "[{}] Client connected from: {}", nClient->get_id(),
                       _address.c_str());
      client_list_.push_front(std::move(nClient));
    } else {
      std::lock_guard<std::mutex> lock(isc_list_mutex_);
      std::shared_ptr<CCharISC> nClient = std::make_shared<CCharISC>(this, std::move(_sock));
      nClient->set_id(server_count_++);
      nClient->set_update_time( Core::Time::GetTickCount() );
      nClient->set_active(true);
      nClient->start_recv();
      logger_->info( "Server connected from: {}", _address.c_str() );
      isc_list_.push_front(std::move(nClient));
    }
  //}
}

void CCharServer::register_maps(CCharISC* isc, const std::vector<uint16_t>& maps) {
    std::shared_ptr<RoseCommon::CRoseClient> ptr;
    for (const auto& p : isc_list_) {
        if (p.get() == isc) {
            ptr = p;
            break;
        }
    }
    if (!ptr) {
        logger_->error("ISC server not found when registering maps!");
        return;
    }
    for (const auto& m : maps) {
        this->maps[m] = ptr;
    }
}

void CCharServer::transfer(RoseCommon::Packet::IscTransfer&& P) {
    const auto& m = P.get_maps();
    std::unordered_set<std::shared_ptr<CRoseClient>> set;
    if (m.empty()) {
        for (const auto& [m, p] : maps) {
            if (auto ptr = p.lock()) {
                set.insert(ptr);
            }
        }
    } else if (m.size() == 1 && m[0] == 0) {
        dispatch_packet(P.get_originatorId(),
                        RoseCommon::fetchPacket<true>(static_cast<const uint8_t*>(P.get_blob().data())));
        return;
    } else {
        for (const auto& mm : m) {
            if (auto ptr = maps[mm].lock()) {
                set.insert(ptr);
            }
        }
    }
    for (auto ptr : set) {
        ptr->send(P);
    }
}

void CCharServer::transfer_char(RoseCommon::Packet::IscTransferChar&& P) {
    std::vector<uint16_t> maps;
    for (auto name : P.get_names()) {
        if (const auto user = get_user(name); user) {
            maps.push_back(user.value()->get_mapId());
        }
    }
    std::unordered_set<std::shared_ptr<CRoseClient>> set;
    for (auto map : maps) {
        if (auto ptr = this->maps[map].lock()) {
            set.insert(ptr);
        }
    }
    for (auto ptr : set) {
        ptr->send(P);
    }
}

void CCharServer::send_map(uint16_t map, const RoseCommon::CRosePacket& p) {
    auto packet = RoseCommon::Packet::IscTransfer::create(0, {map});
    std::vector<uint8_t> blob;
    p.write_to_vector(blob);
    packet.set_blob(blob);
    if (auto ptr = maps[map].lock()) {
        ptr->send(packet);
    }
}

void CCharServer::send_char(uint32_t character, const RoseCommon::CRosePacket& packet) {
    const auto user = get_user(character);
    if (!user) {
        return;
    }
    if (auto client = user.value()->get_client().lock(); client) {
        client->send_packet(packet);
    }
}

void CCharServer::send_char(const std::string& character, const RoseCommon::CRosePacket& p) {
    const auto user = get_user(character);
    if (!user) {
        return;
    }
    if (auto client = user.value()->get_client().lock(); client) {
        client->send_packet(packet);
    }
}

bool CCharServer::dispatch_packet(uint32_t charId, std::unique_ptr<RoseCommon::CRosePacket>&& packet) {
    if (!packet) {
        logger_->error("Empty packet");
        return false;
    }
    if (!dispatcher.is_supported(*packet.get())) {
        logger_->error("Packet not supported!");
        return false;
    }
    auto user = get_user(charId);
    if (!user) {
        logger_->error("User {} not loaded!", charId);
        return false;
    }
    work_queue.push_back([&user = *user.value(), packet = std::move(packet)](CCharServer& server) mutable {
        server.dispatcher.dispatch(std::move(packet), server, std::forward<User&>(user));
    });
    return true;
}

std::optional<const User*const> CCharServer::get_user(const std::string& name) const {
    if (const auto result = std::find_if(users.begin(), users.end(),
                                         [&name](const auto& user) { return user.second.get_name() == name; });
        result != users.end()) {
        return {&result->second};
    }
    return {};
}

std::optional<const User*const> CCharServer::get_user(uint32_t id) const {
    if (auto it = users.find(id); it != users.end()) {
        return {&it->second};
    }
    return {};
}

std::optional<const User*const> CCharServer::get_user(uint16_t id, uint16_t mapId) const {
    if (const auto result = std::find_if(users.begin(), users.end(), [id, mapId](const auto& user) {
            return user.second.get_mapId() == mapId && user.second.get_entityId() == id;
        }); result != users.end()) {
        return {&result->second};
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(const std::string& name) {
    if (auto result = std::find_if(users.begin(), users.end(),
                                   [&name](const auto& user) { return user.second.get_name() == name; });
        result != users.end()) {
        return {&result->second};
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(uint32_t id) {
    if (auto it = users.find(id); it != users.end()) {
        return {&it->second};
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(uint16_t id, uint16_t mapId) {
    if (auto result = std::find_if(users.begin(), users.end(), [id, mapId](const auto& user) {
            return user.second.get_mapId() == mapId && user.second.get_entityId() == id;
        }); result != users.end()) {
        return {&result->second};
    }
    return {};
}

void CCharServer::load_user(std::weak_ptr<CCharClient> client, uint32_t id) {
    Core::CharacterTable characterTable{};

    auto conn = Core::connectionPool.getConnection<Core::Osirose>();

    auto charRes = conn(sqlpp::select(characterTable.name, characterTable.map)
                          .from(characterTable).where(characterTable.id == id));

    if (charRes.empty()) {
        return;
    }
    User user(client, charRes.front().name, id, charRes.front().map);
    user.set_party(partys.get_party(id)); // we load the party if there is one for that character
}

void CCharServer::unload_user(uint32_t id) {
    users.erase(id);
}
<|endoftext|>


<commit_before>// Copyright 2016 Chirstopher Torres (Raven), L3nn0x
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http ://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "ccharserver.h"
#include "ccharclient.h"
#include "ccharisc.h"
#include "epackettype.h"
#include "platform_defines.h"
#include "connection.h"
#include <unordered_set>
#include "isc_client_status.h"
#include "logconsole.h"

#include <algorithm>

using namespace RoseCommon;

void update_status(const Packet::IscClientStatus& packet, CCharServer& server, User& user) {
    auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
    logger->debug("Char {} now has status {}", user.get_name(), packet.get_status());
    const bool isSwitching = user.get_status() == User::Status::SWITCHING ? true : false;
    user.set_status(packet.get_status());
    // we update the id every client on the map refers to when talking about this character. (this is different from the charId)
    user.set_entityId(packet.get_entityMapId());
    if (user.get_status() == User::Status::CONNECTED && isSwitching) {
        // reload the map
        Core::CharacterTable characterTable{};
        auto conn = Core::connectionPool.getConnection<Core::Osirose>();
        auto charRes = conn(sqlpp::select(characterTable.map)
                            .from(characterTable).where(characterTable.id == user.get_charId()));
        if (charRes.empty()) {
            logger->error("Error while trying to access the updated map of {}", user.get_name());
            return;
        }
        user.set_mapId(charRes.front().map);
    }
}

CCharServer::CCharServer(bool _isc, CCharServer *server) : CRoseServer(_isc), client_count_(0), server_count_(0), iscServer_(server) {
    register_dispatcher(std::function{update_status});
    register_dispatcher(std::function{party_request});

    reactor_thread = std::thread([this]() {
        for (auto [res, task] = work_queue.pop_front(); res;) {
            {
                std::lock_guard<std::recursive_mutex> lock(access);
                std::invoke(std::move(task), *this);
            }
            auto [tmp_res, tmp_task] = work_queue.pop_front();
            res = tmp_res;
            task = std::move(tmp_task);
        }
    });
}

CCharServer::~CCharServer() {
    socket_[SocketType::Client]->shutdown();
    work_queue.kill();
    reactor_thread.join();
}

void CCharServer::OnAccepted(std::unique_ptr<Core::INetwork> _sock) {
  //if (_sock->is_active()) {
    // Do Something?
    std::string _address = _sock->get_address();
    if (IsISCServer() == false) {
      std::lock_guard<std::mutex> lock(client_list_mutex_);
      std::shared_ptr<CCharClient> nClient = std::make_shared<CCharClient>(this, std::move(_sock));
      nClient->set_id(client_count_++);
      nClient->set_update_time( Core::Time::GetTickCount() );
      nClient->set_active(true);
      nClient->start_recv();
      logger_->info( "[{}] Client connected from: {}", nClient->get_id(),
                       _address.c_str());
      client_list_.push_front(std::move(nClient));
    } else {
      std::lock_guard<std::mutex> lock(isc_list_mutex_);
      std::shared_ptr<CCharISC> nClient = std::make_shared<CCharISC>(this, std::move(_sock));
      nClient->set_id(server_count_++);
      nClient->set_update_time( Core::Time::GetTickCount() );
      nClient->set_active(true);
      nClient->start_recv();
      logger_->info( "Server connected from: {}", _address.c_str() );
      isc_list_.push_front(std::move(nClient));
    }
  //}
}

void CCharServer::register_maps(CCharISC* isc, const std::vector<uint16_t>& maps) {
    std::shared_ptr<RoseCommon::CRoseClient> ptr;
    for (const auto& p : isc_list_) {
        if (p.get() == isc) {
            ptr = p;
            break;
        }
    }
    if (!ptr) {
        logger_->error("ISC server not found when registering maps!");
        return;
    }
    for (const auto& m : maps) {
        this->maps[m] = ptr;
    }
}

void CCharServer::transfer(RoseCommon::Packet::IscTransfer&& P) {
    const auto& m = P.get_maps();
    std::unordered_set<std::shared_ptr<CRoseClient>> set;
    if (m.empty()) {
        for (const auto& [m, p] : maps) {
            if (auto ptr = p.lock()) {
                set.insert(ptr);
            }
        }
    } else if (m.size() == 1 && m[0] == 0) {
        dispatch_packet(P.get_originatorId(),
                        RoseCommon::fetchPacket<true>(static_cast<const uint8_t*>(P.get_blob().data())));
        return;
    } else {
        for (const auto& mm : m) {
            if (auto ptr = maps[mm].lock()) {
                set.insert(ptr);
            }
        }
    }
    for (auto ptr : set) {
        ptr->send(P);
    }
}

void CCharServer::transfer_char(RoseCommon::Packet::IscTransferChar&& P) {
    std::vector<uint16_t> maps;
    for (auto name : P.get_names()) {
        if (const auto user = get_user(name); user) {
            maps.push_back(user.value()->get_mapId());
        }
    }
    std::unordered_set<std::shared_ptr<CRoseClient>> set;
    for (auto map : maps) {
        if (auto ptr = this->maps[map].lock()) {
            set.insert(ptr);
        }
    }
    for (auto ptr : set) {
        ptr->send(P);
    }
}

void CCharServer::send_map(uint16_t map, const RoseCommon::CRosePacket& p) {
    auto packet = RoseCommon::Packet::IscTransfer::create(0, {map});
    std::vector<uint8_t> blob;
    p.write_to_vector(blob);
    packet.set_blob(blob);
    if (auto ptr = maps[map].lock()) {
        ptr->send(packet);
    }
}

void CCharServer::send_char(uint32_t character, const RoseCommon::CRosePacket& packet) {
    const auto user = get_user(character);
    if (!user) {
        return;
    }
    if (auto client = user.value()->get_client().lock(); client) {
        client->send_packet(packet);
    }
}

void CCharServer::send_char(const std::string& character, const RoseCommon::CRosePacket& p) {
    const auto user = get_user(character);
    if (!user) {
        return;
    }
    if (auto client = user.value()->get_client().lock(); client) {
        client->send_packet(packet);
    }
}

bool CCharServer::dispatch_packet(uint32_t charId, std::unique_ptr<RoseCommon::CRosePacket>&& packet) {
    if (!packet) {
        logger_->error("Empty packet");
        return false;
    }
    if (!dispatcher.is_supported(*packet.get())) {
        logger_->error("Packet not supported!");
        return false;
    }
    auto user = get_user(charId);
    if (!user) {
        logger_->error("User {} not loaded!", charId);
        return false;
    }
    work_queue.push_back([&user = *user.value(), packet = std::move(packet)](CCharServer& server) mutable {
        server.dispatcher.dispatch(std::move(packet), server, std::forward<User&>(user));
    });
    return true;
}

std::optional<const User*const> CCharServer::get_user(const std::string& name) const {
    if (const auto result = std::find_if(users.begin(), users.end(),
                                         [&name](const auto& user) { return user.second.get_name() == name; });
        result != users.end()) {
        return {&result->second};
    }
    return {};
}

std::optional<const User*const> CCharServer::get_user(uint32_t id) const {
    if (auto it = users.find(id); it != users.end()) {
        return {&it->second};
    }
    return {};
}

std::optional<const User*const> CCharServer::get_user(uint16_t id, uint16_t mapId) const {
    if (const auto result = std::find_if(users.begin(), users.end(), [id, mapId](const auto& user) {
            return user.second.get_mapId() == mapId && user.second.get_entityId() == id;
        }); result != users.end()) {
        return {&result->second};
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(const std::string& name) {
    if (auto result = std::find_if(users.begin(), users.end(),
                                   [&name](const auto& user) { return user.second.get_name() == name; });
        result != users.end()) {
        return {&result->second};
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(uint32_t id) {
    if (auto it = users.find(id); it != users.end()) {
        return {&it->second};
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(uint16_t id, uint16_t mapId) {
    if (auto result = std::find_if(users.begin(), users.end(), [id, mapId](const auto& user) {
            return user.second.get_mapId() == mapId && user.second.get_entityId() == id;
        }); result != users.end()) {
        return {&result->second};
    }
    return {};
}

void CCharServer::load_user(std::weak_ptr<CCharClient> client, uint32_t id) {
    Core::CharacterTable characterTable{};

    auto conn = Core::connectionPool.getConnection<Core::Osirose>();

    auto charRes = conn(sqlpp::select(characterTable.name, characterTable.map)
                          .from(characterTable).where(characterTable.id == id));

    if (charRes.empty()) {
        return;
    }
    User user(client, charRes.front().name, id, charRes.front().map);
    user.set_party(partys.get_party(id)); // we load the party if there is one for that character
}

void CCharServer::unload_user(uint32_t id) {
    users.erase(id);
}
<commit_msg>Update ccharserver.cpp<commit_after>// Copyright 2016 Chirstopher Torres (Raven), L3nn0x
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http ://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "ccharserver.h"
#include "ccharclient.h"
#include "ccharisc.h"
#include "epackettype.h"
#include "platform_defines.h"
#include "connection.h"
#include <unordered_set>
#include "isc_client_status.h"
#include "logconsole.h"

#include <algorithm>

using namespace RoseCommon;

void update_status(const Packet::IscClientStatus& packet, CCharServer& server, User& user) {
    auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
    logger->debug("Char {} now has status {}", user.get_name(), packet.get_status());
    const bool isSwitching = user.get_status() == User::Status::SWITCHING ? true : false;
    user.set_status(packet.get_status());
    // we update the id every client on the map refers to when talking about this character. (this is different from the charId)
    user.set_entityId(packet.get_entityMapId());
    if (user.get_status() == User::Status::CONNECTED && isSwitching) {
        // reload the map
        Core::CharacterTable characterTable{};
        auto conn = Core::connectionPool.getConnection<Core::Osirose>();
        auto charRes = conn(sqlpp::select(characterTable.map)
                            .from(characterTable).where(characterTable.id == user.get_charId()));
        if (charRes.empty()) {
            logger->error("Error while trying to access the updated map of {}", user.get_name());
            return;
        }
        user.set_mapId(charRes.front().map);
    }
}

CCharServer::CCharServer(bool _isc, CCharServer *server) : CRoseServer(_isc), client_count_(0), server_count_(0), iscServer_(server) {
    register_dispatcher(std::function{update_status});
    register_dispatcher(std::function{party_request});

    reactor_thread = std::thread([this]() {
        for (auto [res, task] = work_queue.pop_front(); res;) {
            {
                std::lock_guard<std::recursive_mutex> lock(access);
                std::invoke(std::move(task), *this);
            }
            auto [tmp_res, tmp_task] = work_queue.pop_front();
            res = tmp_res;
            task = std::move(tmp_task);
        }
    });
}

CCharServer::~CCharServer() {
    socket_[SocketType::Client]->shutdown();
    work_queue.kill();
    reactor_thread.join();
}

void CCharServer::OnAccepted(std::unique_ptr<Core::INetwork> _sock) {
  //if (_sock->is_active()) {
    // Do Something?
    std::string _address = _sock->get_address();
    if (IsISCServer() == false) {
      std::lock_guard<std::mutex> lock(client_list_mutex_);
      std::shared_ptr<CCharClient> nClient = std::make_shared<CCharClient>(this, std::move(_sock));
      nClient->set_id(client_count_++);
      nClient->set_update_time( Core::Time::GetTickCount() );
      nClient->set_active(true);
      nClient->start_recv();
      logger_->info( "[{}] Client connected from: {}", nClient->get_id(),
                       _address.c_str());
      client_list_.push_front(std::move(nClient));
    } else {
      std::lock_guard<std::mutex> lock(isc_list_mutex_);
      std::shared_ptr<CCharISC> nClient = std::make_shared<CCharISC>(this, std::move(_sock));
      nClient->set_id(server_count_++);
      nClient->set_update_time( Core::Time::GetTickCount() );
      nClient->set_active(true);
      nClient->start_recv();
      logger_->info( "Server connected from: {}", _address.c_str() );
      isc_list_.push_front(std::move(nClient));
    }
  //}
}

void CCharServer::register_maps(CCharISC* isc, const std::vector<uint16_t>& maps) {
    std::shared_ptr<RoseCommon::CRoseClient> ptr;
    for (const auto& p : isc_list_) {
        if (p.get() == isc) {
            ptr = p;
            break;
        }
    }
    if (!ptr) {
        logger_->error("ISC server not found when registering maps!");
        return;
    }
    for (const auto& m : maps) {
        this->maps[m] = ptr;
    }
}

void CCharServer::transfer(RoseCommon::Packet::IscTransfer&& P) {
    const auto& m = P.get_maps();
    std::unordered_set<std::shared_ptr<CRoseClient>> set;
    if (m.empty()) {
        for (const auto& [m, p] : maps) {
            if (auto ptr = p.lock()) {
                set.insert(ptr);
            }
        }
    } else if (m.size() == 1 && m[0] == 0) {
        dispatch_packet(P.get_originatorId(),
                        RoseCommon::fetchPacket<true>(static_cast<const uint8_t*>(P.get_blob().data())));
        return;
    } else {
        for (const auto& mm : m) {
            if (auto ptr = maps[mm].lock()) {
                set.insert(ptr);
            }
        }
    }
    for (auto ptr : set) {
        ptr->send(P);
    }
}

void CCharServer::transfer_char(RoseCommon::Packet::IscTransferChar&& P) {
    std::vector<uint16_t> maps;
    for (auto name : P.get_names()) {
        if (const auto user = get_user(name); user) {
            maps.push_back(user.value()->get_mapId());
        }
    }
    std::unordered_set<std::shared_ptr<CRoseClient>> set;
    for (auto map : maps) {
        if (auto ptr = this->maps[map].lock()) {
            set.insert(ptr);
        }
    }
    for (auto ptr : set) {
        ptr->send(P);
    }
}

void CCharServer::send_map(uint16_t map, const RoseCommon::CRosePacket& p) {
    auto packet = RoseCommon::Packet::IscTransfer::create(0, {map});
    std::vector<uint8_t> blob;
    p.write_to_vector(blob);
    packet.set_blob(blob);
    if (auto ptr = maps[map].lock()) {
        ptr->send(packet);
    }
}

void CCharServer::send_char(uint32_t character, const RoseCommon::CRosePacket& packet) {
    const auto user = get_user(character);
    if (!user) {
        return;
    }
    if (auto client = user.value()->get_client().lock(); client) {
        client->send_packet(packet);
    }
}

void CCharServer::send_char(const User& user, const RoseCommon::CRosePacket& packet) {
    if (auto client = user.value()->get_client().lock(); client) {
        client->send_packet(packet);
    }
}

void CCharServer::send_char(const std::string& character, const RoseCommon::CRosePacket& p) {
    const auto user = get_user(character);
    if (!user) {
        return;
    }
    if (auto client = user.value()->get_client().lock(); client) {
        client->send_packet(packet);
    }
}

bool CCharServer::dispatch_packet(uint32_t charId, std::unique_ptr<RoseCommon::CRosePacket>&& packet) {
    if (!packet) {
        logger_->error("Empty packet");
        return false;
    }
    if (!dispatcher.is_supported(*packet.get())) {
        logger_->error("Packet not supported!");
        return false;
    }
    auto user = get_user(charId);
    if (!user) {
        logger_->error("User {} not loaded!", charId);
        return false;
    }
    work_queue.push_back([&user = *user.value(), packet = std::move(packet)](CCharServer& server) mutable {
        server.dispatcher.dispatch(std::move(packet), server, std::forward<User&>(user));
    });
    return true;
}

std::optional<const User*const> CCharServer::get_user(const std::string& name) const {
    if (const auto result = std::find_if(users.begin(), users.end(),
                                         [&name](const auto& user) { return user.second.get_name() == name; });
        result != users.end()) {
        return {&result->second};
    }
    return {};
}

std::optional<const User*const> CCharServer::get_user(uint32_t id) const {
    if (auto it = users.find(id); it != users.end()) {
        return {&it->second};
    }
    return {};
}

std::optional<const User*const> CCharServer::get_user(uint16_t id, uint16_t mapId) const {
    if (const auto result = std::find_if(users.begin(), users.end(), [id, mapId](const auto& user) {
            return user.second.get_mapId() == mapId && user.second.get_entityId() == id;
        }); result != users.end()) {
        return {&result->second};
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(const std::string& name) {
    if (auto result = std::find_if(users.begin(), users.end(),
                                   [&name](const auto& user) { return user.second.get_name() == name; });
        result != users.end()) {
        return {&result->second};
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(uint32_t id) {
    if (auto it = users.find(id); it != users.end()) {
        return {&it->second};
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(uint16_t id, uint16_t mapId) {
    if (auto result = std::find_if(users.begin(), users.end(), [id, mapId](const auto& user) {
            return user.second.get_mapId() == mapId && user.second.get_entityId() == id;
        }); result != users.end()) {
        return {&result->second};
    }
    return {};
}

void CCharServer::load_user(std::weak_ptr<CCharClient> client, uint32_t id) {
    Core::CharacterTable characterTable{};

    auto conn = Core::connectionPool.getConnection<Core::Osirose>();

    auto charRes = conn(sqlpp::select(characterTable.name, characterTable.map)
                          .from(characterTable).where(characterTable.id == id));

    if (charRes.empty()) {
        return;
    }
    User user(client, charRes.front().name, id, charRes.front().map);
    user.set_party(partys.get_party(id)); // we load the party if there is one for that character
}

void CCharServer::unload_user(uint32_t id) {
    users.erase(id);
}

std::shared_ptr<Party> CCharServer::create_party(User& user) {
    auto party = partys.create_party(user.get_id());
    user.set_party(party);
    return party;
}

void CCharServer::add_user_to_party(User& user, std::shared_ptr<Party> party) {
    partys.add_member_to_party(party, user.get_id());
    user.set_party(party);
    // TODO: send packet
}
<|endoftext|>


<commit_before>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2017 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

#include <cstdint>
#include <cassert>

#include <gtest/gtest.h>

#include "joynr/DelayedScheduler.h"
#include "joynr/Logger.h"
#include "joynr/Semaphore.h"
#include "joynr/SingleThreadedIOService.h"

#include "tests/JoynrTest.h"
#include "tests/utils/TimeUtils.h"
#include "tests/mock/MockRunnable.h"

using namespace joynr;

using namespace ::testing;
using ::testing::StrictMock;

// Expected accuracy of the timer in milliseconds
static const std::uint64_t timerAccuracy_ms = 15U;

class SimpleDelayedScheduler :
    public DelayedScheduler
{

public:

    SimpleDelayedScheduler(std::shared_ptr<SingleThreadedIOService> singleThreadedIOService)
        : DelayedScheduler(std::bind(&SimpleDelayedScheduler::workAvailable, this, std::placeholders::_1), singleThreadedIOService->getIOService()),
          est_ms(0)
    {
    }

    ~SimpleDelayedScheduler() = default;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
    MOCK_CONST_METHOD1(workAvailableCalled, void (std::shared_ptr<Runnable>));
    MOCK_CONST_METHOD0(workAvailableInTime, void ());
#pragma GCC diagnostic pop

    DelayedScheduler::RunnableHandle schedule(std::shared_ptr<Runnable> runnable,
                  std::chrono::milliseconds delay)
    {
        RunnableHandle currentHandle = DelayedScheduler::schedule(runnable, delay);
        est_ms = TimeUtils::getCurrentMillisSinceEpoch() + delay.count();
        return currentHandle;
    }

    void workAvailable(std::shared_ptr<Runnable> runnable)
    {
        const std::uint64_t now_ms = TimeUtils::getCurrentMillisSinceEpoch();
        workAvailableCalled(runnable);

        if(est_ms > 0)
        {
            const std::uint64_t diff_ms = (now_ms > est_ms) ? now_ms - est_ms : est_ms - now_ms;

            JOYNR_LOG_TRACE(logger(), "Runnable is available");
            JOYNR_LOG_TRACE(logger(), " ETA        : {}",est_ms);
            JOYNR_LOG_TRACE(logger(), " current    : {}",now_ms);
            JOYNR_LOG_TRACE(logger(), " difference : {}",diff_ms);

            if (diff_ms <= timerAccuracy_ms)
            {
                workAvailableInTime();
            }
        }
        else
        {
            JOYNR_LOG_TRACE(logger(), "No delay given but work available called.");
        }
        //if (runnable->isDeleteOnExit()) {
        //    delete runnable;
        //}
    }

private:
    std::uint64_t est_ms;
};

TEST(DelayedSchedulerTest, startAndShutdownWithoutWork)
{
    auto singleThreadedIOService = std::make_shared<SingleThreadedIOService>();
    singleThreadedIOService->start();
    auto scheduler = std::make_shared<SimpleDelayedScheduler>(singleThreadedIOService);

    scheduler->shutdown();
}

TEST(DelayedSchedulerTest, startAndShutdownWithPendingWork_callDtorOfRunnablesCorrect)
{
    auto singleThreadedIOService = std::make_shared<SingleThreadedIOService>();
    singleThreadedIOService->start();
    auto scheduler = std::make_shared<SimpleDelayedScheduler>(singleThreadedIOService);

    // Dtor should be called
    auto runnable1 = std::make_shared<StrictMock<MockRunnable>>();
    scheduler->schedule(runnable1, std::chrono::milliseconds(100));

    // Dtor called after scheduler was cleaned
    auto runnable2 = std::make_shared<StrictMock<MockRunnable>>();
    scheduler->schedule(runnable2, std::chrono::milliseconds(100));

    EXPECT_CALL(*runnable1, dtorCalled()).Times(1);

    std::this_thread::sleep_for(std::chrono::milliseconds(10));

    scheduler->shutdown();

    std::this_thread::sleep_for(std::chrono::milliseconds(10));

    EXPECT_CALL(*runnable2, dtorCalled()).Times(1);
}

TEST(DelayedSchedulerTest, testAccuracyOfDelayedScheduler)
{
    joynr::Semaphore semaphore;
    auto singleThreadedIOService = std::make_shared<SingleThreadedIOService>();
    singleThreadedIOService->start();
    auto scheduler = std::make_shared<SimpleDelayedScheduler>(singleThreadedIOService);
    auto runnable1 = std::make_shared<StrictMock<MockRunnable>>();
    scheduler->schedule(runnable1, std::chrono::milliseconds(5));

    EXPECT_CALL(*scheduler, workAvailableCalled(std::dynamic_pointer_cast<Runnable>(runnable1))).Times(1);
    EXPECT_CALL(*scheduler, workAvailableInTime()).Times(1).WillOnce(ReleaseSemaphore(&semaphore));

    EXPECT_TRUE(semaphore.waitFor(std::chrono::milliseconds(1000)));

    scheduler->shutdown();

    EXPECT_CALL(*runnable1, dtorCalled()).Times(1);
}

TEST(DelayedSchedulerTest, avoidCallingDtorOfRunnablesAfterSchedulerHasExpired)
{
    joynr::Semaphore semaphore;
    auto singleThreadedIOService = std::make_shared<SingleThreadedIOService>();
    singleThreadedIOService->start();
    auto scheduler = std::make_shared<SimpleDelayedScheduler>(singleThreadedIOService);
    auto runnable1 = std::make_shared<StrictMock<MockRunnable>>();
    scheduler->schedule(runnable1, std::chrono::milliseconds(5));

    EXPECT_CALL(*scheduler, workAvailableCalled(std::dynamic_pointer_cast<Runnable>(runnable1))).Times(1).WillOnce(ReleaseSemaphore(&semaphore));

    EXPECT_CALL(*runnable1, dtorCalled()).Times(1);

    EXPECT_TRUE(semaphore.waitFor(std::chrono::milliseconds(100)));

    scheduler->shutdown();
}

TEST(DelayedSchedulerTest, scheduleAndUnscheduleRunnable_NoCallToRunnable)
{
    auto singleThreadedIOService = std::make_shared<SingleThreadedIOService>();
    singleThreadedIOService->start();
    auto scheduler = std::make_shared<SimpleDelayedScheduler>(singleThreadedIOService);
    auto runnable1 = std::make_shared<StrictMock<MockRunnable>>();
    DelayedScheduler::RunnableHandle handle = scheduler->schedule(runnable1, std::chrono::milliseconds(50));

    EXPECT_CALL(*runnable1, dtorCalled()).Times(1);
    EXPECT_CALL(*scheduler, workAvailableCalled(std::dynamic_pointer_cast<Runnable>(runnable1))).Times(0);
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
    scheduler->unschedule(handle);

    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    scheduler->shutdown();
}

TEST(DelayedSchedulerTest, scheduleAndUnscheduleRunnable_CallDtorOnUnschedule)
{
    joynr::Semaphore semaphore;
    auto singleThreadedIOService = std::make_shared<SingleThreadedIOService>();
    singleThreadedIOService->start();
    auto scheduler = std::make_shared<SimpleDelayedScheduler>(singleThreadedIOService);
    auto runnable1 = std::make_shared<StrictMock<MockRunnable>>();
    DelayedScheduler::RunnableHandle handle = scheduler->schedule(runnable1, std::chrono::milliseconds(50));

    std::this_thread::sleep_for(std::chrono::milliseconds(1));

    EXPECT_CALL(*runnable1, dtorCalled()).Times(1).WillOnce(ReleaseSemaphore(&semaphore));

    scheduler->unschedule(handle);
    runnable1.reset();

    EXPECT_TRUE(semaphore.waitFor(std::chrono::milliseconds(100)));

    scheduler->shutdown();
}
<commit_msg>[C++] Stop SingleThreadedIOService in DelayedSchedulerTest<commit_after>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2017 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

#include <cstdint>
#include <cassert>

#include <gtest/gtest.h>

#include "joynr/DelayedScheduler.h"
#include "joynr/Logger.h"
#include "joynr/Semaphore.h"
#include "joynr/SingleThreadedIOService.h"

#include "tests/JoynrTest.h"
#include "tests/utils/TimeUtils.h"
#include "tests/mock/MockRunnable.h"

using namespace joynr;

using namespace ::testing;
using ::testing::StrictMock;

// Expected accuracy of the timer in milliseconds
static const std::uint64_t timerAccuracy_ms = 15U;

class SimpleDelayedScheduler :
    public DelayedScheduler
{

public:

    SimpleDelayedScheduler(std::shared_ptr<SingleThreadedIOService> singleThreadedIOService)
        : DelayedScheduler(std::bind(&SimpleDelayedScheduler::workAvailable, this, std::placeholders::_1), singleThreadedIOService->getIOService()),
          est_ms(0)
    {
    }

    ~SimpleDelayedScheduler() = default;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
    MOCK_CONST_METHOD1(workAvailableCalled, void (std::shared_ptr<Runnable>));
    MOCK_CONST_METHOD0(workAvailableInTime, void ());
#pragma GCC diagnostic pop

    DelayedScheduler::RunnableHandle schedule(std::shared_ptr<Runnable> runnable,
                  std::chrono::milliseconds delay)
    {
        RunnableHandle currentHandle = DelayedScheduler::schedule(runnable, delay);
        est_ms = TimeUtils::getCurrentMillisSinceEpoch() + delay.count();
        return currentHandle;
    }

    void workAvailable(std::shared_ptr<Runnable> runnable)
    {
        const std::uint64_t now_ms = TimeUtils::getCurrentMillisSinceEpoch();
        workAvailableCalled(runnable);

        if(est_ms > 0)
        {
            const std::uint64_t diff_ms = (now_ms > est_ms) ? now_ms - est_ms : est_ms - now_ms;

            JOYNR_LOG_TRACE(logger(), "Runnable is available");
            JOYNR_LOG_TRACE(logger(), " ETA        : {}",est_ms);
            JOYNR_LOG_TRACE(logger(), " current    : {}",now_ms);
            JOYNR_LOG_TRACE(logger(), " difference : {}",diff_ms);

            if (diff_ms <= timerAccuracy_ms)
            {
                workAvailableInTime();
            }
        }
        else
        {
            JOYNR_LOG_TRACE(logger(), "No delay given but work available called.");
        }
        //if (runnable->isDeleteOnExit()) {
        //    delete runnable;
        //}
    }

private:
    std::uint64_t est_ms;
};

TEST(DelayedSchedulerTest, startAndShutdownWithoutWork)
{
    auto singleThreadedIOService = std::make_shared<SingleThreadedIOService>();
    singleThreadedIOService->start();
    auto scheduler = std::make_shared<SimpleDelayedScheduler>(singleThreadedIOService);

    scheduler->shutdown();
    singleThreadedIOService->stop();
}

TEST(DelayedSchedulerTest, startAndShutdownWithPendingWork_callDtorOfRunnablesCorrect)
{
    auto singleThreadedIOService = std::make_shared<SingleThreadedIOService>();
    singleThreadedIOService->start();
    auto scheduler = std::make_shared<SimpleDelayedScheduler>(singleThreadedIOService);

    // Dtor should be called
    auto runnable1 = std::make_shared<StrictMock<MockRunnable>>();
    scheduler->schedule(runnable1, std::chrono::milliseconds(100));

    // Dtor called after scheduler was cleaned
    auto runnable2 = std::make_shared<StrictMock<MockRunnable>>();
    scheduler->schedule(runnable2, std::chrono::milliseconds(100));

    EXPECT_CALL(*runnable1, dtorCalled()).Times(1);

    std::this_thread::sleep_for(std::chrono::milliseconds(10));

    scheduler->shutdown();

    std::this_thread::sleep_for(std::chrono::milliseconds(10));

    EXPECT_CALL(*runnable2, dtorCalled()).Times(1);
    singleThreadedIOService->stop();
}

TEST(DelayedSchedulerTest, testAccuracyOfDelayedScheduler)
{
    joynr::Semaphore semaphore;
    auto singleThreadedIOService = std::make_shared<SingleThreadedIOService>();
    singleThreadedIOService->start();
    auto scheduler = std::make_shared<SimpleDelayedScheduler>(singleThreadedIOService);
    auto runnable1 = std::make_shared<StrictMock<MockRunnable>>();
    scheduler->schedule(runnable1, std::chrono::milliseconds(5));

    EXPECT_CALL(*scheduler, workAvailableCalled(std::dynamic_pointer_cast<Runnable>(runnable1))).Times(1);
    EXPECT_CALL(*scheduler, workAvailableInTime()).Times(1).WillOnce(ReleaseSemaphore(&semaphore));

    EXPECT_TRUE(semaphore.waitFor(std::chrono::milliseconds(1000)));

    scheduler->shutdown();

    EXPECT_CALL(*runnable1, dtorCalled()).Times(1);
    singleThreadedIOService->stop();
}

TEST(DelayedSchedulerTest, avoidCallingDtorOfRunnablesAfterSchedulerHasExpired)
{
    joynr::Semaphore semaphore;
    auto singleThreadedIOService = std::make_shared<SingleThreadedIOService>();
    singleThreadedIOService->start();
    auto scheduler = std::make_shared<SimpleDelayedScheduler>(singleThreadedIOService);
    auto runnable1 = std::make_shared<StrictMock<MockRunnable>>();
    scheduler->schedule(runnable1, std::chrono::milliseconds(5));

    EXPECT_CALL(*scheduler, workAvailableCalled(std::dynamic_pointer_cast<Runnable>(runnable1))).Times(1).WillOnce(ReleaseSemaphore(&semaphore));

    EXPECT_CALL(*runnable1, dtorCalled()).Times(1);

    EXPECT_TRUE(semaphore.waitFor(std::chrono::milliseconds(100)));

    scheduler->shutdown();
    singleThreadedIOService->stop();
}

TEST(DelayedSchedulerTest, scheduleAndUnscheduleRunnable_NoCallToRunnable)
{
    auto singleThreadedIOService = std::make_shared<SingleThreadedIOService>();
    singleThreadedIOService->start();
    auto scheduler = std::make_shared<SimpleDelayedScheduler>(singleThreadedIOService);
    auto runnable1 = std::make_shared<StrictMock<MockRunnable>>();
    DelayedScheduler::RunnableHandle handle = scheduler->schedule(runnable1, std::chrono::milliseconds(50));

    EXPECT_CALL(*runnable1, dtorCalled()).Times(1);
    EXPECT_CALL(*scheduler, workAvailableCalled(std::dynamic_pointer_cast<Runnable>(runnable1))).Times(0);
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
    scheduler->unschedule(handle);

    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    scheduler->shutdown();
    singleThreadedIOService->stop();
}

TEST(DelayedSchedulerTest, scheduleAndUnscheduleRunnable_CallDtorOnUnschedule)
{
    joynr::Semaphore semaphore;
    auto singleThreadedIOService = std::make_shared<SingleThreadedIOService>();
    singleThreadedIOService->start();
    auto scheduler = std::make_shared<SimpleDelayedScheduler>(singleThreadedIOService);
    auto runnable1 = std::make_shared<StrictMock<MockRunnable>>();
    DelayedScheduler::RunnableHandle handle = scheduler->schedule(runnable1, std::chrono::milliseconds(50));

    std::this_thread::sleep_for(std::chrono::milliseconds(1));

    EXPECT_CALL(*runnable1, dtorCalled()).Times(1).WillOnce(ReleaseSemaphore(&semaphore));

    scheduler->unschedule(handle);
    runnable1.reset();

    EXPECT_TRUE(semaphore.waitFor(std::chrono::milliseconds(100)));

    scheduler->shutdown();
    singleThreadedIOService->stop();
}
<|endoftext|>


<commit_before>#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <sensor_msgs/PointCloud2.h>
#include <sensor_msgs/PointCloud.h>
#include <sensor_msgs/point_cloud_conversion.h>
#include <tf/transform_listener.h>
#include <octomap/octomap.h>
#include <octomap/OcTree.h>
#include <octomap_msgs/Octomap.h>
#include <octomap_msgs/conversions.h>
#include <geometry_msgs/PointStamped.h>

#include <string>
#include <math.h>
#include <vector>

#include "dmath/geometry.h"

class ArtificialPotentialField{
public:
    ArtificialPotentialField(ros::NodeHandle &node) :
        base_link_("base_link"),
        cmd_pub_(node.advertise<geometry_msgs::Twist>("cmd_vel", 10)),
        obs_sub_(node.subscribe("octomap_full", 10, &ArtificialPotentialField::obstacleCallback, this)),
        goal_sub_(node.subscribe("clicked_point", 10, &ArtificialPotentialField::goalCallback, this))

    {
        collision_map_.header.stamp = ros::Time(0);
    }

    void spin(){
        ros::Rate r(10);

        ros::Duration(1).sleep();
        geometry_msgs::Twist cmd;
        cmd.linear.z = 0.15;
        cmd_pub_.publish(cmd);
        ros::Duration(3).sleep();

        cmd.linear.z = 0;
        cmd_pub_.publish(cmd);
        ros::Duration(3).sleep();

        const double force = 0.025;

        while(ros::ok()){
            if(collision_map_.header.stamp != ros::Time(0)){
                std::vector<dmath::Vector3D> obstacles_lc;
                std::string map_frame = collision_map_.header.frame_id;
                octomap::OcTree *tree = dynamic_cast<octomap::OcTree*>(octomap_msgs::msgToMap(collision_map_));
                octomap::OcTree::leaf_iterator const end_it = tree->end_leafs();
                for(octomap::OcTree::leaf_iterator it = tree->begin_leafs(0); it != end_it; it++){
                    geometry_msgs::PointStamped p_in, p_out;
                    p_in.header.frame_id = map_frame;
                    p_in.point.x = it.getX();
                    p_in.point.y = it.getY();
                    p_in.point.z = it.getZ();

                    try{
                        tf_listener_.transformPoint(base_link_, p_in, p_out);
                        dmath::Vector3D obs(p_out.point.x, p_out.point.y, p_out.point.z);
                        if(magnitude(obs) < 500){
                            obstacles_lc.push_back(obs);
                        }
                    }catch(tf::TransformException &ex){
                        ROS_ERROR_STREAM("Exception trying to transform octomap: " << ex.what());
                    }
                }

                dmath::Vector3D Fs;
                //for(int i=0; i < obstacles_lc.size(); i++){
                //    Fs += get_potential_force(obstacles_lc[i], 0, 1.0, 1.0, 1.5);
                //}

                dmath::Vector3D g = goal_lc_;
                Fs += get_potential_force(g, 2, 0, 1.5, 1);

                dmath::Vector3D vel = Fs * force;
                cmd.linear.x = vel.y;
                cmd.linear.y = vel.x;
                cmd.linear.z = vel.z;

                cmd_pub_.publish(cmd);
            }
            r.sleep();
            ros::spinOnce();
        }
    }

private:
    dmath::Vector3D get_potential_force(const dmath::Vector3D &dest_lc, double A = 1, double B = 1, double n = 1, double m = 1){
        dmath::Vector3D u = dest_lc;
        u = normalize(u);

        const double d = magnitude(dest_lc);
        double U = 0;
        if(fabs(d) > dmath::tol){
            U = -A/pow(d, n) + B/pow(d, m);
        }

        return U * u;
    }

    void obstacleCallback(const octomap_msgs::OctomapPtr &obs_msg){
        collision_map_ = *obs_msg;
    }

    void goalCallback(const geometry_msgs::PointStamped &goal_msg){
        geometry_msgs::PointStamped g_lc;
        try{
            tf_listener_.transformPoint(base_link_, goal_msg, g_lc);
            goal_lc_ = dmath::Vector3D(g_lc.point.x, g_lc.point.y, g_lc.point.z);
        }catch(tf::TransformException &ex){
            ROS_ERROR_STREAM("Exception trying to transform octomap: " << ex.what());
            goal_lc_ = dmath::Vector3D();
        }
    }

    octomap_msgs::Octomap collision_map_;
    ros::Publisher cmd_pub_;
    ros::Subscriber obs_sub_, goal_sub_;
    tf::TransformListener tf_listener_;
    std::string base_link_;
    dmath::Vector3D goal_lc_;
};

int main(int argc, char *argv[]){
    ros::init(argc, argv, "apf_planner");

    ros::NodeHandle node;
    ArtificialPotentialField apf(node);
    apf.spin();

    return 0;
}

<commit_msg>Fix a parameter of attraction force from goal<commit_after>#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <sensor_msgs/PointCloud2.h>
#include <sensor_msgs/PointCloud.h>
#include <sensor_msgs/point_cloud_conversion.h>
#include <tf/transform_listener.h>
#include <octomap/octomap.h>
#include <octomap/OcTree.h>
#include <octomap_msgs/Octomap.h>
#include <octomap_msgs/conversions.h>
#include <geometry_msgs/PointStamped.h>

#include <string>
#include <math.h>
#include <vector>

#include "dmath/geometry.h"

class ArtificialPotentialField{
public:
    ArtificialPotentialField(ros::NodeHandle &node) :
        base_link_("base_link"),
        cmd_pub_(node.advertise<geometry_msgs::Twist>("cmd_vel", 10)),
        obs_sub_(node.subscribe("octomap_full", 10, &ArtificialPotentialField::obstacleCallback, this)),
        goal_sub_(node.subscribe("clicked_point", 10, &ArtificialPotentialField::goalCallback, this))

    {
        collision_map_.header.stamp = ros::Time(0);
    }

    void spin(){
        ros::Rate r(10);

        ros::Duration(1).sleep();
        geometry_msgs::Twist cmd;
        cmd.linear.z = 0.15;
        cmd_pub_.publish(cmd);
        ros::Duration(3).sleep();

        cmd.linear.z = 0;
        cmd_pub_.publish(cmd);
        ros::Duration(3).sleep();

        const double force = 0.025;

        while(ros::ok()){
            if(collision_map_.header.stamp != ros::Time(0)){
                std::vector<dmath::Vector3D> obstacles_lc;
                std::string map_frame = collision_map_.header.frame_id;
                octomap::OcTree *tree = dynamic_cast<octomap::OcTree*>(octomap_msgs::msgToMap(collision_map_));
                octomap::OcTree::leaf_iterator const end_it = tree->end_leafs();
                for(octomap::OcTree::leaf_iterator it = tree->begin_leafs(0); it != end_it; it++){
                    geometry_msgs::PointStamped p_in, p_out;
                    p_in.header.frame_id = map_frame;
                    p_in.point.x = it.getX();
                    p_in.point.y = it.getY();
                    p_in.point.z = it.getZ();

                    try{
                        tf_listener_.transformPoint(base_link_, p_in, p_out);
                        dmath::Vector3D obs(p_out.point.x, p_out.point.y, p_out.point.z);
                        if(magnitude(obs) < 500){
                            obstacles_lc.push_back(obs);
                        }
                    }catch(tf::TransformException &ex){
                        ROS_ERROR_STREAM("Exception trying to transform octomap: " << ex.what());
                    }
                }

                dmath::Vector3D Fs;
                //for(int i=0; i < obstacles_lc.size(); i++){
                //    Fs += get_potential_force(obstacles_lc[i], 0, 1.0, 1.0, 1.5);
                //}

                dmath::Vector3D g = goal_lc_;
                Fs += get_potential_force(g, 200, 0, 1.5, 1);

                dmath::Vector3D vel = Fs * force;
                cmd.linear.x = vel.y;
                cmd.linear.y = vel.x;
                cmd.linear.z = vel.z;

                cmd_pub_.publish(cmd);
            }
            r.sleep();
            ros::spinOnce();
        }
    }

private:
    dmath::Vector3D get_potential_force(const dmath::Vector3D &dest_lc, double A = 1, double B = 1, double n = 1, double m = 1){
        dmath::Vector3D u = dest_lc;
        u = normalize(u);

        const double d = magnitude(dest_lc);
        double U = 0;
        if(fabs(d) > dmath::tol){
            U = -A/pow(d, n) + B/pow(d, m);
        }

        return U * u;
    }

    void obstacleCallback(const octomap_msgs::OctomapPtr &obs_msg){
        collision_map_ = *obs_msg;
    }

    void goalCallback(const geometry_msgs::PointStamped &goal_msg){
        geometry_msgs::PointStamped g_lc;
        try{
            tf_listener_.transformPoint(base_link_, goal_msg, g_lc);
            goal_lc_ = dmath::Vector3D(g_lc.point.x, g_lc.point.y, g_lc.point.z);
        }catch(tf::TransformException &ex){
            ROS_ERROR_STREAM("Exception trying to transform octomap: " << ex.what());
            goal_lc_ = dmath::Vector3D();
        }
    }

    octomap_msgs::Octomap collision_map_;
    ros::Publisher cmd_pub_;
    ros::Subscriber obs_sub_, goal_sub_;
    tf::TransformListener tf_listener_;
    std::string base_link_;
    dmath::Vector3D goal_lc_;
};

int main(int argc, char *argv[]){
    ros::init(argc, argv, "apf_planner");

    ros::NodeHandle node;
    ArtificialPotentialField apf(node);
    apf.spin();

    return 0;
}

<|endoftext|>


<commit_before>// Basic tests.

#include "utils/if_test_helper.hxx"

#include "nmranet/NMRAnetEventRegistry.hxx"
#include "if/nmranet_if.h"

TEST_F(IfTest, Setup) {}

TEST_F(IfTest, WriteMessageSync) {
  // We write a message using the WriteFlow class directly into the interface.
  ExpectPacket(":X195B412DN0102030405060708;");
  event_write_helper1.WriteAsync(node_, MTI_EVENT_REPORT, WriteHelper::Global(),
                                 EventIdToBuffer(0x0102030405060708ULL),
                                 nullptr);
}

TEST_F(IfTest, WriteMessageASync) {
  // We write a message using the WriteFlow class asynchronously.
  ExpectPacket(":X195B412DN0102030405060708;");
  SyncNotifiable n;
  event_write_helper1.WriteAsync(node_, MTI_EVENT_REPORT, WriteHelper::Global(),
                                 EventIdToBuffer(0x0102030405060708ULL),
                                 &n);
  n.WaitForNotification();
}

TEST_F(IfTest, ReadMessageAndReply) {
  // We send an alias mapping enquiry frame and expect the node ID back.
  ExpectPacket(":X1070112DN02010d000003;");
  SendPacket(  ":X10702000N;");
}
<commit_msg>Fixes if_test_test for the c++ api.<commit_after>// Basic tests.

#include "utils/if_test_helper.hxx"

#include "nmranet/NMRAnetEventRegistry.hxx"
#include "nmranet/NMRAnetIf.hxx"

namespace NMRAnet {

TEST_F(IfTest, Setup) {}

TEST_F(IfTest, WriteMessageSync) {
  // We write a message using the WriteFlow class directly into the interface.
  ExpectPacket(":X195B412DN0102030405060708;");
  event_write_helper1.WriteAsync(node_, If::MTI_EVENT_REPORT, WriteHelper::global(),
                                 EventIdToBuffer(0x0102030405060708ULL),
                                 nullptr);
}

TEST_F(IfTest, WriteMessageASync) {
  // We write a message using the WriteFlow class asynchronously.
  ExpectPacket(":X195B412DN0102030405060708;");
  SyncNotifiable n;
  event_write_helper1.WriteAsync(node_, If::MTI_EVENT_REPORT, WriteHelper::global(),
                                 EventIdToBuffer(0x0102030405060708ULL),
                                 &n);
  n.WaitForNotification();
}

TEST_F(IfTest, ReadMessageAndReply) {
  // We send an alias mapping enquiry frame and expect the node ID back.
  ExpectPacket(":X1070112DN02010d000003;");
  SendPacket(  ":X10702001N;");
}

}  // namespace NMRAnet
<|endoftext|>


<commit_before>/*
   Copyright (c) by respective owners including Yahoo!, Microsoft, and
   individual contributors. All rights reserved.  Released under a BSD (revised)
   license as described in the file LICENSE.
   */
#include "gd.h"

using namespace std;
using namespace LEARNER;

#define W_XT 0   // current parameter w(XT)
#define W_ZT 1   // accumulated z(t) = z(t-1) + g(t) + sigma*w(t)
#define W_G2 2   // accumulated gradient squre n(t) = n(t-1) + g(t)*g(t)

/********************************************************************/
/* mem & w definition ***********************************************/
/********************************************************************/
// w[0] = current weight
// w[1] = accumulated zt
// w[2] = accumulated g2

//nonrentrant
struct ftrl {
  vw* all; //features, finalize, l1, l2,
  float ftrl_alpha;
  float ftrl_beta;
};

void predict(ftrl& b, base_learner& base, example& ec)
{
  ec.partial_prediction = GD::inline_predict(*b.all, ec);
  ec.pred.scalar = GD::finalize_prediction(b.all->sd, ec.partial_prediction);
}

inline float sign(float w){ if (w < 0.) return -1.; else  return 1.;}

struct update_data {
  float update;
  float ftrl_alpha;
  float ftrl_beta;
  float l1_lambda;
  float l2_lambda;
};

void inner_update(update_data& d, float x, float& wref) {
  float* w = &wref;
  float gradient = d.update * x;
  float ng2 = w[W_G2] + gradient * gradient;
  float sigma = (sqrtf(ng2) - sqrtf(w[W_G2]))/ d.ftrl_alpha;
  w[W_ZT] += gradient - sigma * w[W_XT];
  w[W_G2] = ng2;
  float flag = sign(w[W_ZT]);
  float fabs_zt = w[W_ZT] * flag;
  if (fabs_zt <= d.l1_lambda)
    w[W_XT] = 0.;
  else {
    float step = 1/(d.l2_lambda + (d.ftrl_beta + sqrtf(w[W_G2]))/d.ftrl_alpha);
    w[W_XT] = step * flag * (d.l1_lambda - fabs_zt);
  }
}

void update(ftrl& b, example& ec)
{
  struct update_data data;
  data.update = b.all->loss->first_derivative(b.all->sd, ec.pred.scalar, ec.l.simple.label)
    *ec.l.simple.weight;
  data.ftrl_alpha = b.ftrl_alpha;
  data.ftrl_beta = b.ftrl_beta;
  data.l1_lambda = b.all->l1_lambda;
  data.l2_lambda = b.all->l2_lambda;

  GD::foreach_feature<update_data, inner_update>(*b.all, ec, data);
}

void learn(ftrl& a, base_learner& base, example& ec) {
  assert(ec.in_use);
  // predict w*x
  predict(a, base, ec);
  //updat state
  update(a,ec);
}

void save_load(ftrl& b, io_buf& model_file, bool read, bool text)
{
  vw* all = b.all;
  if (read)
    initialize_regressor(*all);

  if (model_file.files.size() > 0) {
    bool resume = all->save_resume;
    char buff[512];
    uint32_t text_len = sprintf(buff, ":%d\n", resume);
    bin_text_read_write_fixed(model_file,(char *)&resume, sizeof (resume), "", read, buff, text_len, text);

    if (resume)
      GD::save_load_online_state(*all, model_file, read, text);
    else
      GD::save_load_regressor(*all, model_file, read, text);
  }
}

base_learner* ftrl_setup(vw& all)
{
  if (missing_option(all, false, "ftrl", "Follow the Regularized Leader"))
    return NULL;
  new_options(all, "FTRL options")
    ("ftrl_alpha", po::value<float>()->default_value(1.0), "Learning rate for FTRL-proximal optimization")
    ("ftrl_beta", po::value<float>()->default_value(0.1f), "FTRL beta");
  add_options(all);

  ftrl& b = calloc_or_die<ftrl>();
  b.all = &all;
  b.ftrl_beta = all.vm["ftrl_beta"].as<float>();
  b.ftrl_alpha = all.vm["ftrl_alpha"].as<float>();

  all.reg.stride_shift = 2; // NOTE: for more parameter storage

  if (!all.quiet) {
    cerr << "Enabling FTRL-Proximal based optimization" << endl;
    cerr << "ftrl_alpha = " << b.ftrl_alpha << endl;
    cerr << "ftrl_beta = " << b.ftrl_beta << endl;
  }

  learner<ftrl>& l = init_learner(&b, learn, 1 << all.reg.stride_shift);
  l.set_predict(predict);
  l.set_save_load(save_load);
  return make_base(l);
}
<commit_msg>better ftrl_alpha default<commit_after>/*
   Copyright (c) by respective owners including Yahoo!, Microsoft, and
   individual contributors. All rights reserved.  Released under a BSD (revised)
   license as described in the file LICENSE.
   */
#include "gd.h"

using namespace std;
using namespace LEARNER;

#define W_XT 0   // current parameter w(XT)
#define W_ZT 1   // accumulated z(t) = z(t-1) + g(t) + sigma*w(t)
#define W_G2 2   // accumulated gradient squre n(t) = n(t-1) + g(t)*g(t)

/********************************************************************/
/* mem & w definition ***********************************************/
/********************************************************************/
// w[0] = current weight
// w[1] = accumulated zt
// w[2] = accumulated g2

//nonrentrant
struct ftrl {
  vw* all; //features, finalize, l1, l2,
  float ftrl_alpha;
  float ftrl_beta;
};

void predict(ftrl& b, base_learner& base, example& ec)
{
  ec.partial_prediction = GD::inline_predict(*b.all, ec);
  ec.pred.scalar = GD::finalize_prediction(b.all->sd, ec.partial_prediction);
}

inline float sign(float w){ if (w < 0.) return -1.; else  return 1.;}

struct update_data {
  float update;
  float ftrl_alpha;
  float ftrl_beta;
  float l1_lambda;
  float l2_lambda;
};

void inner_update(update_data& d, float x, float& wref) {
  float* w = &wref;
  float gradient = d.update * x;
  float ng2 = w[W_G2] + gradient * gradient;
  float sigma = (sqrtf(ng2) - sqrtf(w[W_G2]))/ d.ftrl_alpha;
  w[W_ZT] += gradient - sigma * w[W_XT];
  w[W_G2] = ng2;
  float flag = sign(w[W_ZT]);
  float fabs_zt = w[W_ZT] * flag;
  if (fabs_zt <= d.l1_lambda)
    w[W_XT] = 0.;
  else {
    float step = 1/(d.l2_lambda + (d.ftrl_beta + sqrtf(w[W_G2]))/d.ftrl_alpha);
    w[W_XT] = step * flag * (d.l1_lambda - fabs_zt);
  }
}

void update(ftrl& b, example& ec)
{
  struct update_data data;
  data.update = b.all->loss->first_derivative(b.all->sd, ec.pred.scalar, ec.l.simple.label)
    *ec.l.simple.weight;
  data.ftrl_alpha = b.ftrl_alpha;
  data.ftrl_beta = b.ftrl_beta;
  data.l1_lambda = b.all->l1_lambda;
  data.l2_lambda = b.all->l2_lambda;

  GD::foreach_feature<update_data, inner_update>(*b.all, ec, data);
}

void learn(ftrl& a, base_learner& base, example& ec) {
  assert(ec.in_use);
  // predict w*x
  predict(a, base, ec);
  //updat state
  update(a,ec);
}

void save_load(ftrl& b, io_buf& model_file, bool read, bool text)
{
  vw* all = b.all;
  if (read)
    initialize_regressor(*all);

  if (model_file.files.size() > 0) {
    bool resume = all->save_resume;
    char buff[512];
    uint32_t text_len = sprintf(buff, ":%d\n", resume);
    bin_text_read_write_fixed(model_file,(char *)&resume, sizeof (resume), "", read, buff, text_len, text);

    if (resume)
      GD::save_load_online_state(*all, model_file, read, text);
    else
      GD::save_load_regressor(*all, model_file, read, text);
  }
}

base_learner* ftrl_setup(vw& all)
{
  if (missing_option(all, false, "ftrl", "Follow the Regularized Leader"))
    return NULL;
  new_options(all, "FTRL options")
    ("ftrl_alpha", po::value<float>()->default_value(0.005f), "Learning rate for FTRL-proximal optimization")
    ("ftrl_beta", po::value<float>()->default_value(0.1f), "FTRL beta");
  add_options(all);

  ftrl& b = calloc_or_die<ftrl>();
  b.all = &all;
  b.ftrl_beta = all.vm["ftrl_beta"].as<float>();
  b.ftrl_alpha = all.vm["ftrl_alpha"].as<float>();

  all.reg.stride_shift = 2; // NOTE: for more parameter storage

  if (!all.quiet) {
    cerr << "Enabling FTRL-Proximal based optimization" << endl;
    cerr << "ftrl_alpha = " << b.ftrl_alpha << endl;
    cerr << "ftrl_beta = " << b.ftrl_beta << endl;
  }

  learner<ftrl>& l = init_learner(&b, learn, 1 << all.reg.stride_shift);
  l.set_predict(predict);
  l.set_save_load(save_load);
  return make_base(l);
}
<|endoftext|>


<commit_before>
#include <QApplication>
#include <QTextEdit>
#include <QtGui>
#include <QTextCodec>
#include "mainwindow.h"
#include "login.h"
#include "desktopimage.h"
#include "mdi_background.h"

#include <kernel/sched/waitq.h>
#include <fcntl.h>
#include <framework/mod/options.h>
#include <module/platform/zrv/cmd/texteditor.h>

#define DEFAULT_WIDTH \
		OPTION_MODULE_GET(platform__zrv__cmd__texteditor, NUMBER, root_window_width)

#define DEFAULT_HEIGHT \
		OPTION_MODULE_GET(platform__zrv__cmd__texteditor, NUMBER, root_window_height)

#define FSIZE 64
#define SEP ':'

static QString defaultImagePath = ":/images/default.png";

QMdiAreaWBackground *emarea;
static DesktopImageDialog *wallpaperDialog;
static QStringList desktopImagesList;
static QApplication *__qt_app;
static QMenu *__qt_menu;

static struct waitq texteditor_inited_wq;
static char texteditor_inited;
static int curuid;

static void emboxQtShowLoginForm();

class EmboxRootWindow : public QMainWindow
{
    Q_OBJECT

    public:

	QAction *closeAllEditorsAction;
	EmboxRootWindow() {
	fileMenu = new QMenu(QString("&Пуск"), this);
	menuBar()->addMenu(fileMenu);

	__qt_menu = fileMenu;

	textEditorAction = new QAction(QString("&Текстовый редактор"), this);
	fileMenu->addAction(textEditorAction);
	connect(textEditorAction, SIGNAL(triggered()), this, SLOT(textEditorRun()));

	closeAllEditorsAction = new QAction(QString("&Закрыть все окна"), this);
	fileMenu->addAction(closeAllEditorsAction);
	connect(closeAllEditorsAction, SIGNAL(triggered()), this, SLOT(closeAllEditors()));

	logoutAction = new QAction(QString("&Завершение сеанса"), this);
	fileMenu->addAction(logoutAction);
	connect(logoutAction, SIGNAL(triggered()), this, SLOT(logout()));

	saveAction = new QAction(QString("&Сохранить конфигурацию"), this);
	fileMenu->addAction(saveAction);
	connect(saveAction, SIGNAL(triggered()), this, SLOT(savedefault()));

	wallpaperAction = new QAction(QString("&Графические настройки"), this);
	fileMenu->addAction(wallpaperAction);
	connect(wallpaperAction, SIGNAL(triggered()), this, SLOT(wallpaper()));
    }

    private slots:
	void textEditorRun() {
		TextEditor *textEditor = new TextEditor(emarea);
		textEditor->show();
	}

	void closeAllEditors() {
		TextEditor::closeAllEditors();
	}

	void logout() {
		emboxQtHideDesktop();
		emboxQtShowLoginForm();
	}

	void wallpaper() {
		wallpaperDialog = new DesktopImageDialog(desktopImagesList);
		wallpaperDialog->show();
	}

	void savedefault() {

	}

    private:
	QAction *logoutAction;
	QAction *textEditorAction;
	QAction *wallpaperAction;
	QAction *saveAction;
	QMenu *fileMenu;
};

static EmboxRootWindow *emroot;

static char *parse(char **buf) {
	char *ret = *buf;
	char *ch;

	if ((ch = strchr(*buf, SEP))) {
		*ch++ = '\0';
	}

	*buf = ch;

	return ret;
}

void emboxQtSetfont(const QString &fontFamily, int fontPt) {
	QFont serifFont(fontFamily, fontPt);
	__qt_app->setFont(serifFont);
	__qt_menu->setFont(serifFont);
}

static void load_pref(void) {
	int fd, ret;
	char cbuf[FSIZE];
	const char *wall = "default.png";
	const char *font = "Times";
	int font_pt = 10;

	snprintf(cbuf, FSIZE, "/mnt/pref_%d", curuid);
	fd = open(cbuf, O_RDONLY, 0755);

	if (fd == -1)
		goto set_default;

	lseek(fd, 0, 0);
	if (0 < (ret = read(fd, cbuf, FSIZE))) {
		char *buf = cbuf;

		buf[ret] = '\0';

		wall = parse(&buf);
		font = parse(&buf);
		font_pt = atoi(parse(&buf));
	}
	close(fd);

set_default:
	QString imagePath = QString(":/images/").append(QString(wall));
	emarea->setBackgroundPath(imagePath);

	emboxQtSetfont(font, font_pt);

}

void emboxQtSavePref(char *wall, char *font, int font_pt) {
	int fd, len;
	char cbuf[FSIZE];

	snprintf(cbuf, FSIZE, "/mnt/pref_%d", curuid);

	fd = creat(cbuf, 0755);

	len = snprintf(cbuf, FSIZE, "%s:%s:%d", wall, font, font_pt);

	write(fd, cbuf, len);

	ftruncate(fd, len);

	close(fd);
}

void emboxQtShowDesktop(uid_t uid) {
	int fd = -1;
	bool enabled = uid ? false : true;

	curuid = uid;
	emroot->menuBar()->show();
	emroot->closeAllEditorsAction->setEnabled(enabled);

	load_pref();
}

void emboxQtHideDesktop() {
	emarea->closeAllSubWindows();
	emroot->menuBar()->hide();
}

void emboxRootWindowShow(int width, int height) {
	emroot->setGeometry(QRect(0,0, width, height));
	texteditor_inited = 1;
	waitq_wakeup_all(&texteditor_inited_wq);
}

static void emboxQtShowLoginForm() {
	LoginDialog *loginDialog = new LoginDialog(0, emarea);
	loginDialog->show();

	emarea->setBackgroundPath(defaultImagePath);
}

int main(int argv, char **args)
{
	//Q_INIT_RESOURCE(texteditor);

	waitq_init(&texteditor_inited_wq);

	QApplication app(argv, args);

	__qt_app = &app;

	QFont serifFont("Times", 10);
	app.setFont(serifFont);
	qDebug() << "Supported formats:" << QImageReader::supportedImageFormats();
	desktopImagesList << "cats.jpg" << "default.png";

	QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
	QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
	QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));

	emroot = new EmboxRootWindow();
	emarea = new QMdiAreaWBackground(defaultImagePath);

	emroot->setCentralWidget(emarea);

	if (DEFAULT_WIDTH == 0 || DEFAULT_HEIGHT == 0) {
		WAITQ_WAIT(&texteditor_inited_wq, texteditor_inited); /* EMBOXVC plugin*/
	} else {
		emroot->setGeometry(QRect(0,0, DEFAULT_WIDTH, DEFAULT_HEIGHT)); /* VNC plugin */
	}

	emroot->show();

	emboxQtHideDesktop();

	emboxQtShowLoginForm();

	return app.exec();
}

#include "main.moc"
<commit_msg>qt-pro: Fix texteditor options references<commit_after>
#include <QApplication>
#include <QTextEdit>
#include <QtGui>
#include <QTextCodec>
#include "mainwindow.h"
#include "login.h"
#include "desktopimage.h"
#include "mdi_background.h"

#include <kernel/sched/waitq.h>
#include <fcntl.h>
#include <framework/mod/options.h>
#include <module/zrv/cmd/texteditor.h>

#define DEFAULT_WIDTH \
		OPTION_MODULE_GET(zrv__cmd__texteditor, NUMBER, root_window_width)

#define DEFAULT_HEIGHT \
		OPTION_MODULE_GET(zrv__cmd__texteditor, NUMBER, root_window_height)

#define FSIZE 64
#define SEP ':'

static QString defaultImagePath = ":/images/default.png";

QMdiAreaWBackground *emarea;
static DesktopImageDialog *wallpaperDialog;
static QStringList desktopImagesList;
static QApplication *__qt_app;
static QMenu *__qt_menu;

static struct waitq texteditor_inited_wq;
static char texteditor_inited;
static int curuid;

static void emboxQtShowLoginForm();

class EmboxRootWindow : public QMainWindow
{
    Q_OBJECT

    public:

	QAction *closeAllEditorsAction;
	EmboxRootWindow() {
	fileMenu = new QMenu(QString("&Пуск"), this);
	menuBar()->addMenu(fileMenu);

	__qt_menu = fileMenu;

	textEditorAction = new QAction(QString("&Текстовый редактор"), this);
	fileMenu->addAction(textEditorAction);
	connect(textEditorAction, SIGNAL(triggered()), this, SLOT(textEditorRun()));

	closeAllEditorsAction = new QAction(QString("&Закрыть все окна"), this);
	fileMenu->addAction(closeAllEditorsAction);
	connect(closeAllEditorsAction, SIGNAL(triggered()), this, SLOT(closeAllEditors()));

	logoutAction = new QAction(QString("&Завершение сеанса"), this);
	fileMenu->addAction(logoutAction);
	connect(logoutAction, SIGNAL(triggered()), this, SLOT(logout()));

	saveAction = new QAction(QString("&Сохранить конфигурацию"), this);
	fileMenu->addAction(saveAction);
	connect(saveAction, SIGNAL(triggered()), this, SLOT(savedefault()));

	wallpaperAction = new QAction(QString("&Графические настройки"), this);
	fileMenu->addAction(wallpaperAction);
	connect(wallpaperAction, SIGNAL(triggered()), this, SLOT(wallpaper()));
    }

    private slots:
	void textEditorRun() {
		TextEditor *textEditor = new TextEditor(emarea);
		textEditor->show();
	}

	void closeAllEditors() {
		TextEditor::closeAllEditors();
	}

	void logout() {
		emboxQtHideDesktop();
		emboxQtShowLoginForm();
	}

	void wallpaper() {
		wallpaperDialog = new DesktopImageDialog(desktopImagesList);
		wallpaperDialog->show();
	}

	void savedefault() {

	}

    private:
	QAction *logoutAction;
	QAction *textEditorAction;
	QAction *wallpaperAction;
	QAction *saveAction;
	QMenu *fileMenu;
};

static EmboxRootWindow *emroot;

static char *parse(char **buf) {
	char *ret = *buf;
	char *ch;

	if ((ch = strchr(*buf, SEP))) {
		*ch++ = '\0';
	}

	*buf = ch;

	return ret;
}

void emboxQtSetfont(const QString &fontFamily, int fontPt) {
	QFont serifFont(fontFamily, fontPt);
	__qt_app->setFont(serifFont);
	__qt_menu->setFont(serifFont);
}

static void load_pref(void) {
	int fd, ret;
	char cbuf[FSIZE];
	const char *wall = "default.png";
	const char *font = "Times";
	int font_pt = 10;

	snprintf(cbuf, FSIZE, "/mnt/pref_%d", curuid);
	fd = open(cbuf, O_RDONLY, 0755);

	if (fd == -1)
		goto set_default;

	lseek(fd, 0, 0);
	if (0 < (ret = read(fd, cbuf, FSIZE))) {
		char *buf = cbuf;

		buf[ret] = '\0';

		wall = parse(&buf);
		font = parse(&buf);
		font_pt = atoi(parse(&buf));
	}
	close(fd);

set_default:
	QString imagePath = QString(":/images/").append(QString(wall));
	emarea->setBackgroundPath(imagePath);

	emboxQtSetfont(font, font_pt);

}

void emboxQtSavePref(char *wall, char *font, int font_pt) {
	int fd, len;
	char cbuf[FSIZE];

	snprintf(cbuf, FSIZE, "/mnt/pref_%d", curuid);

	fd = creat(cbuf, 0755);

	len = snprintf(cbuf, FSIZE, "%s:%s:%d", wall, font, font_pt);

	write(fd, cbuf, len);

	ftruncate(fd, len);

	close(fd);
}

void emboxQtShowDesktop(uid_t uid) {
	int fd = -1;
	bool enabled = uid ? false : true;

	curuid = uid;
	emroot->menuBar()->show();
	emroot->closeAllEditorsAction->setEnabled(enabled);

	load_pref();
}

void emboxQtHideDesktop() {
	emarea->closeAllSubWindows();
	emroot->menuBar()->hide();
}

void emboxRootWindowShow(int width, int height) {
	emroot->setGeometry(QRect(0,0, width, height));
	texteditor_inited = 1;
	waitq_wakeup_all(&texteditor_inited_wq);
}

static void emboxQtShowLoginForm() {
	LoginDialog *loginDialog = new LoginDialog(0, emarea);
	loginDialog->show();

	emarea->setBackgroundPath(defaultImagePath);
}

int main(int argv, char **args)
{
	//Q_INIT_RESOURCE(texteditor);

	waitq_init(&texteditor_inited_wq);

	QApplication app(argv, args);

	__qt_app = &app;

	QFont serifFont("Times", 10);
	app.setFont(serifFont);
	qDebug() << "Supported formats:" << QImageReader::supportedImageFormats();
	desktopImagesList << "cats.jpg" << "default.png";

	QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
	QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
	QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));

	emroot = new EmboxRootWindow();
	emarea = new QMdiAreaWBackground(defaultImagePath);

	emroot->setCentralWidget(emarea);

	if (DEFAULT_WIDTH == 0 || DEFAULT_HEIGHT == 0) {
		WAITQ_WAIT(&texteditor_inited_wq, texteditor_inited); /* EMBOXVC plugin*/
	} else {
		emroot->setGeometry(QRect(0,0, DEFAULT_WIDTH, DEFAULT_HEIGHT)); /* VNC plugin */
	}

	emroot->show();

	emboxQtHideDesktop();

	emboxQtShowLoginForm();

	return app.exec();
}

#include "main.moc"
<|endoftext|>