dmpservermanager.cpp 10.7 KB
/**************************************************************************
* file:              dmpservermanager.cpp

* Author:            wanzhongping
* Date:              2021-07-27 21:59:46
* Email:             zhongpingw@chinadci.com
* copyright:         广州城市信息研究所有限公司
***************************************************************************/
#include "dmpservermanager.h"
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>

#include "dmpserver.h"

using namespace std;
namespace
{

    string MakeServerKey(const string &name, const string &version)
    {
        boost::format fmt = boost::format("%1%_%2%") % name % version;
        return fmt.str();
    }

    bool IsVersionGreater(const string &v1, const string &v2)
    {
        vector<string> vecSeg1;
        boost::split(vecSeg1, v1, boost::is_any_of("."), boost::token_compress_on);
        vector<string> vecSeg2;
        boost::split(vecSeg2, v2, boost::is_any_of("."), boost::token_compress_on);

        vector<string>::iterator it1 = vecSeg1.begin();
        vector<string>::iterator it2 = vecSeg2.begin();
        bool isint;
        while (it1 != vecSeg1.end() && it2 != vecSeg2.end())
        {
            if (*it1 != *it2)
            {
                // Compare as numbers
                int i1 = atoi(it1->c_str());
                int i2 = atoi(it2->c_str());
                if (i1 != i2)
                {
                    return i1 > i2;
                }
            }
            ++it1;
            ++it2;
        }
        return false;
    }
} // namespace

DmpServerManager::DmpServerManager(const std::string& root_path)
   :root_path_(root_path)
{

}

DmpServerManager::~DmpServerManager()
{
    CleanUp();
    std::cout << "Destructing DmpServerManager" << std::endl;
}

void DmpServerManager::Init(const boost::filesystem::path &module_path)
{
    nativeLoader_.LoadModules(module_path, *this);
    
    LoadServices();
}

int DmpServerManager::GetServicePaths(const std::string& service_dir, std::vector<std::string>& service_paths)
{
    if (!boost::filesystem::exists(service_dir))
    {
      return -1;
    }
    boost::filesystem::directory_iterator end_iter;
    for (boost::filesystem::directory_iterator iter(service_dir); iter != end_iter; ++iter)
    {
      if (boost::filesystem::is_regular_file(iter->status()) && iter->path().extension() == ".json")
      {
        std::string file_name = iter->path().filename().string();
        boost::cmatch what;
        boost::regex reg("(^\\w+)\\.(\\w+)\\.(\\w+)$",  boost::regex_constants::icase);
        if(boost::regex_match(file_name.c_str(), what, reg) && what.size() == 4) 
        {
            service_paths.push_back(iter->path().string());
        }
      }
      else if (boost::filesystem::is_directory(iter->status()))
      {
        GetServicePaths(iter->path().string(), service_paths);
      }
    }
    return service_paths.size();
}

bool DmpServerManager::LoadServices()
{
    //获取服务的路径
    std::vector<std::string> service_paths;
    int size = GetServicePaths(root_path_, service_paths);
    if(size < 1) {
      return false;
    }
    for (const auto &service_path : service_paths) 
    {
        //获取服务名称和服务类型vev[0],vec[1]
        std::string::size_type pos = service_path.find_last_of("/");
        if(pos != std::string::npos) {
            std::vector<std::string> vec;
            std::string file_name = service_path.substr(pos + 1);
            boost::split(vec, file_name, boost::is_any_of("."), boost::token_compress_on);
            std::string service_name = vec[0];

            if(boost::iequals(vec[1], "MapServer")) 
            {
                DmpMapService* mapservice = new DmpMapService(service_name, service_path);
                //通知所有服务器,注册到MapServer中;为什么不由MapServer直接Add,因为MapServer不知道有多少Server,Server是动态注册到系统中的
                for (const auto &server : servers_) {
                    server.second->Register(mapservice);
                }
                if(mapservice->Read())
                {
                    services_[service_name] = mapservice;
                    mapservice->set_state(ServiceState::STARTED);
                }
            }   
        }
    }
}

std::shared_ptr<DmpServer> DmpServerManager::GetServer(const string &name, const string &version)
{
    std::shared_ptr<DmpServer> sp_server = nullptr;
    string key;
    string nameUpper = boost::to_upper_copy(name);
    VersionMap::const_iterator it = serverVersions_.find(nameUpper);
    if (it != serverVersions_.end())
    {
        key = version.empty() ? it->second.second : MakeServerKey(nameUpper, version);
        ServerMap::const_iterator iter = servers_.find(key);
        if (iter != servers_.end())
        {
            sp_server = iter->second;
        }
        else
        {
            sp_server = servers_[it->second.second];
        }
    }
    else
    {
    }
    return sp_server;
}
void DmpServerManager::RegisterServer(std::shared_ptr<DmpServer> server)
{
    string name = server->Name();
    boost::to_upper(name);
    string version = server->Version();

    string key = MakeServerKey(name, version);
    if (servers_.find(key) != servers_.end()){
        return;
    }
    servers_[key] = server;
    if (serverVersions_.find(name) == serverVersions_.end()){
        serverVersions_.insert(pair<string, pair<string, string>>(name, pair<string, string>(version, key)));
    }
}

int DmpServerManager::UnregisterServer(const string &name, const string &version)
{
    int removed = 0;
    VersionMap::const_iterator it = serverVersions_.find(name);
    if (it != serverVersions_.end())
    {
        if (version.empty())
        {
            ServerMap::iterator iter = servers_.begin();
            while (iter != servers_.end())
            {
                if (iter->second->Name() == name)
                {
                    iter = servers_.erase(iter);
                    ++removed;
                }
                else
                {
                    ++iter;
                }
            }
            serverVersions_.erase(it);
        }
        else
        {
            string key = MakeServerKey(name, version);
            ServerMap::iterator found = servers_.find(key);
            if (found != servers_.end())
            {
                servers_.erase(found);
                removed = 1;

                //findGreaterVersion为匿名函数
                string maxVer;
                std::function<void(const ServerMap::value_type &)>
                    findGreaterVersion = [name, &maxVer](const ServerMap::value_type &item) {
                        if (item.second->Name() == name &&
                            (maxVer.empty() || IsVersionGreater(item.second->Version(), maxVer)))
                            maxVer = item.second->Version();
                    };

                serverVersions_.erase(name);

                std::for_each(servers_.begin(), servers_.end(), findGreaterVersion);
                if (!maxVer.empty())
                {
                    // Set the new default service
                    string key = MakeServerKey(name, maxVer);
                    serverVersions_.insert(pair<string, pair<string, string>>(name, pair<string, string>(version, key)));
                }
            }
        }
    }
    return removed;
}

void DmpServerManager::CleanUp()
{
    serverVersions_.clear();
    servers_.clear();
    nativeLoader_.UnloadModules();
}

std::shared_ptr<DmpServer> DmpServerManager::ServerForRequest(const DmpServerRequest &request)
{
  for (const auto &server : servers_) 
  {
    if(server.second->Accept(request.path()))
    {
        return server.second;
    }
  }
  return nullptr;  
}

bool DmpServerManager::PublishMapServer(const std::string& service_name, const std::string& capabilities, 
                                        const std::string& project_data, const std::string& service_title, 
                                        const std::string& catalog)
{
  std::string map_dir;
  std::string service_file;
  std::string proj_file;
  if(catalog.empty()) {
    map_dir = root_path_ + "/" + service_name + ".MapServer";
  } else {
    map_dir = root_path_ + "/" + catalog + "/" + service_name + ".MapServer";
  }
  if (!boost::filesystem::exists(map_dir))
  {
    boost::filesystem::create_directories(map_dir);
  }
  service_file = map_dir + "/" + service_name + ".MapServer.json";
  proj_file =    map_dir + "/" + service_name + ".MapServer.dmd";

  //project
  std::string proj_data;
  if(!DmpServerUtils::Base64Decode(project_data, &proj_data)){
    return false;
  }
  DmpProject project;
  if(!project.Write(proj_file, proj_data)){
    return false;
  }

  //services
  vector<string> vec_cap;
  boost::split(vec_cap, capabilities, boost::is_any_of(","), boost::token_compress_on);
  if(vec_cap.size() == 0){
    return false;
  }
  DmpMapService* mapserver = new DmpMapService(service_name,service_file);
  for (const auto &cap : vec_cap)
  {
    std::shared_ptr<DmpServer> server = GetServer(cap, "");
    if(!server->Register(mapserver)){
        return false;
    }
  }

  if (mapserver->Write()) {
    services_[service_name] = mapserver;
    mapserver->set_state(ServiceState::STARTED);
  }
  return true;
}

bool DmpServerManager::PublishTileServer(const std::string& service_name,const std::string& type,const std::string& vendor,
                        const std::string& srs,const std::string& path,const std::string& abstract,const std::string& layerinfo,
                        const std::string& project_data,const std::string& service_title,const std::string& catalog)
{

  std::string map_dir;
  std::string service_file;
  std::string proj_file;
   if(catalog.empty()) {
    map_dir = root_path_ + "/" + service_name + ".MapServer";
  } else {
    map_dir = root_path_ + "/" + catalog + "/" + service_name + ".MapServer";
  }
  if (!boost::filesystem::exists(map_dir))
  {
    boost::filesystem::create_directories(map_dir);
  }
  service_file = map_dir + "/" + service_name + ".MapServer.json";
  proj_file =    map_dir + "/" + service_name + ".MapServer.dmd";
  
  DmpProject project;
  if(!project.Write(proj_file, project_data)){
    return false;
  }
  
  //services
  vector<string> vec_cap;
  boost::split(vec_cap, type, boost::is_any_of(","), boost::token_compress_on);
  if(vec_cap.size() == 0){
    return false;
  }
  DmpMapService* mapserver = new DmpMapService(service_name,service_file);
  for (const auto &cap : vec_cap)
  {
    std::shared_ptr<DmpServer> server = GetServer(cap, "");
    if(!server->Register(mapserver)){
        return false;
    }
  }
  if (mapserver->Write()) {
    services_[service_name] = mapserver;
    mapserver->set_state(ServiceState::STARTED);
  }

  return true;
}