mirror of
https://github.com/Icinga/icinga2.git
synced 2025-04-08 17:05:25 +02:00
parent
9b73205481
commit
c37a23ccba
.travis.ymlCMakeLists.txt
icinga-studio
CMakeLists.txtIcingaStudio.fbpMacOSXBundleInfo.plist.inaboutform.cppaboutform.hppapi.cppapi.hppconnectform.cppconnectform.hppforms.cppforms.hicinga-studio.cppicinga.icnsicinga.icoicinga.rcicinga.xpmmainform.cppmainform.hpp
lib
base
CMakeLists.txtexception.hppsocketevents.cppsocketevents.hpptlsstream.cpptlsstream.hpptlsutility.cpptlsutility.hppwin32.hpp
config
remote
third-party
@ -16,6 +16,8 @@ addons:
|
||||
- libmysqlclient-dev
|
||||
- libedit-dev
|
||||
- libyajl-dev
|
||||
- libwxbase3.0-dev
|
||||
- libwxgtk3.0-dev
|
||||
|
||||
before_script:
|
||||
- mkdir build
|
||||
|
@ -37,6 +37,7 @@ option(ICINGA2_WITH_HELLO "Build the hello module" OFF)
|
||||
option(ICINGA2_WITH_LIVESTATUS "Build the Livestatus module" ON)
|
||||
option(ICINGA2_WITH_NOTIFICATION "Build the notification module" ON)
|
||||
option(ICINGA2_WITH_PERFDATA "Build the perfdata module" ON)
|
||||
option(ICINGA2_WITH_STUDIO "Build the Icinga Studio application" OFF)
|
||||
|
||||
file(STRINGS icinga2.spec VERSION_LINE REGEX "^Version: ")
|
||||
string(REPLACE "Version: " "" ICINGA2_VERSION ${VERSION_LINE})
|
||||
@ -244,6 +245,10 @@ add_subdirectory(test)
|
||||
add_subdirectory(agent)
|
||||
add_subdirectory(plugins)
|
||||
|
||||
if(ICINGA2_WITH_STUDIO)
|
||||
add_subdirectory(icinga-studio)
|
||||
endif()
|
||||
|
||||
set(CPACK_PACKAGE_NAME "Icinga2")
|
||||
set(CPACK_PACKAGE_VENDOR "Icinga Development Team")
|
||||
set(CPACK_PACKAGE_VERSION ${ICINGA2_VERSION})
|
||||
|
65
icinga-studio/CMakeLists.txt
Normal file
65
icinga-studio/CMakeLists.txt
Normal file
@ -0,0 +1,65 @@
|
||||
# Icinga 2
|
||||
# Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
set(wxWidgets_CONFIGURATION mswu)
|
||||
find_package(wxWidgets COMPONENTS core base propgrid REQUIRED)
|
||||
include(${wxWidgets_USE_FILE})
|
||||
|
||||
if(MSVC)
|
||||
set(WindowsSources icinga.rc)
|
||||
else()
|
||||
set(WindowsSources "")
|
||||
endif()
|
||||
|
||||
add_executable(icinga-studio MACOSX_BUNDLE WIN32 icinga-studio.cpp
|
||||
forms.cpp aboutform.cpp connectform.cpp mainform.cpp
|
||||
icinga.icns api.cpp ${WindowsSources})
|
||||
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
target_link_libraries(icinga-studio ${Boost_LIBRARIES} ${wxWidgets_LIBRARIES} base remote)
|
||||
|
||||
if(APPLE)
|
||||
set_source_files_properties(icinga.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
endif()
|
||||
|
||||
set_target_properties (
|
||||
icinga-studio PROPERTIES
|
||||
INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2
|
||||
FOLDER Bin
|
||||
OUTPUT_NAME icinga-studio
|
||||
MACOSX_BUNDLE_INFO_STRING "Icinga Studio"
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "Icinga Studio"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "Icinga Studio"
|
||||
MACOSX_BUNDLE_ICON_FILE icinga.icns
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${GIT_VERSION}"
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING "${GIT_VERSION}"
|
||||
MACOSX_BUNDLE_COPYRIGHT "(c) Icinga Development Team"
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/MacOSXBundleInfo.plist.in"
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
set(InstallPath "${CMAKE_INSTALL_SBINDIR}")
|
||||
else()
|
||||
set(InstallPath "${CMAKE_INSTALL_BINDIR}")
|
||||
endif()
|
||||
|
||||
install(
|
||||
TARGETS icinga-studio
|
||||
RUNTIME DESTINATION ${InstallPath}
|
||||
BUNDLE DESTINATION ${InstallPath}
|
||||
)
|
||||
|
2128
icinga-studio/IcingaStudio.fbp
Normal file
2128
icinga-studio/IcingaStudio.fbp
Normal file
File diff suppressed because it is too large
Load Diff
38
icinga-studio/MacOSXBundleInfo.plist.in
Normal file
38
icinga-studio/MacOSXBundleInfo.plist.in
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleLongVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
||||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
<key>LSRequiresCarbon</key>
|
||||
<false/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
30
icinga-studio/aboutform.cpp
Normal file
30
icinga-studio/aboutform.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "base/application.hpp"
|
||||
#include "icinga-studio/aboutform.hpp"
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
AboutForm::AboutForm(wxWindow *parent)
|
||||
: AboutFormBase(parent)
|
||||
{
|
||||
std::string version = "Version " + Application::GetVersion();
|
||||
m_VersionLabel->SetLabelText(version);
|
||||
}
|
36
icinga-studio/aboutform.hpp
Normal file
36
icinga-studio/aboutform.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef ABOUTFORM_H
|
||||
#define ABOUTFORM_H
|
||||
|
||||
#include "icinga-studio/forms.h"
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
class AboutForm : public AboutFormBase
|
||||
{
|
||||
public:
|
||||
AboutForm(wxWindow *parent);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* ABOUTFORM_H */
|
165
icinga-studio/api.cpp
Normal file
165
icinga-studio/api.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "icinga-studio/api.hpp"
|
||||
#include "remote/base64.hpp"
|
||||
#include "base/json.hpp"
|
||||
#include "base/logger.hpp"
|
||||
#include "base/exception.hpp"
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
ApiClient::ApiClient(const String& host, const String& port,
|
||||
const String& user, const String& password)
|
||||
: m_Connection(new HttpClientConnection(host, port, true)), m_User(user), m_Password(password)
|
||||
{
|
||||
m_Connection->Start();
|
||||
}
|
||||
|
||||
void ApiClient::GetTypes(const TypesCompletionCallback& callback) const
|
||||
{
|
||||
boost::shared_ptr<HttpRequest> req = m_Connection->NewRequest();
|
||||
req->RequestMethod = "GET";
|
||||
req->RequestUrl = new Url("https://" + m_Connection->GetHost() + ":" + m_Connection->GetPort() + "/v1/types");
|
||||
req->AddHeader("Authorization", "Basic " + Base64::Encode(m_User + ":" + m_Password));
|
||||
m_Connection->SubmitRequest(req, boost::bind(TypesHttpCompletionCallback, _1, _2, callback));
|
||||
}
|
||||
|
||||
void ApiClient::TypesHttpCompletionCallback(HttpRequest& request, HttpResponse& response,
|
||||
const TypesCompletionCallback& callback)
|
||||
{
|
||||
Dictionary::Ptr result;
|
||||
|
||||
String body;
|
||||
char buffer[1024];
|
||||
size_t count;
|
||||
|
||||
while ((count = response.ReadBody(buffer, sizeof(buffer))) > 0)
|
||||
body += String(buffer, buffer + count);
|
||||
|
||||
std::vector<ApiType::Ptr> types;
|
||||
|
||||
try {
|
||||
result = JsonDecode(body);
|
||||
|
||||
Array::Ptr results = result->Get("results");
|
||||
|
||||
ObjectLock olock(results);
|
||||
BOOST_FOREACH(const Dictionary::Ptr typeInfo, results)
|
||||
{
|
||||
ApiType::Ptr type = new ApiType();;
|
||||
type->Abstract = typeInfo->Get("abstract");
|
||||
type->BaseName = typeInfo->Get("base");
|
||||
type->Name = typeInfo->Get("name");
|
||||
type->PluralName = typeInfo->Get("plural_name");
|
||||
// TODO: attributes
|
||||
types.push_back(type);
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
Log(LogCritical, "ApiClient")
|
||||
<< "Error while decoding response: " << DiagnosticInformation(ex);
|
||||
}
|
||||
|
||||
callback(types);
|
||||
}
|
||||
|
||||
void ApiClient::GetObjects(const String& pluralType, const ObjectsCompletionCallback& callback,
|
||||
const std::vector<String>& names, const std::vector<String>& attrs) const
|
||||
{
|
||||
String url = "https://" + m_Connection->GetHost() + ":" + m_Connection->GetPort() + "/v1/" + pluralType;
|
||||
String qp;
|
||||
|
||||
BOOST_FOREACH(const String& name, names) {
|
||||
if (!qp.IsEmpty())
|
||||
qp += "&";
|
||||
|
||||
qp += pluralType.ToLower() + "=" + name;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const String& attr, attrs) {
|
||||
if (!qp.IsEmpty())
|
||||
qp += "&";
|
||||
|
||||
qp += "attrs[]=" + attr;
|
||||
}
|
||||
|
||||
boost::shared_ptr<HttpRequest> req = m_Connection->NewRequest();
|
||||
req->RequestMethod = "GET";
|
||||
req->RequestUrl = new Url(url + "?" + qp);
|
||||
req->AddHeader("Authorization", "Basic " + Base64::Encode(m_User + ":" + m_Password));
|
||||
m_Connection->SubmitRequest(req, boost::bind(ObjectsHttpCompletionCallback, _1, _2, callback));
|
||||
}
|
||||
|
||||
void ApiClient::ObjectsHttpCompletionCallback(HttpRequest& request,
|
||||
HttpResponse& response, const ObjectsCompletionCallback& callback)
|
||||
{
|
||||
Dictionary::Ptr result;
|
||||
|
||||
String body;
|
||||
char buffer[1024];
|
||||
size_t count;
|
||||
|
||||
while ((count = response.ReadBody(buffer, sizeof(buffer))) > 0)
|
||||
body += String(buffer, buffer + count);
|
||||
|
||||
std::vector<ApiObject::Ptr> objects;
|
||||
|
||||
try {
|
||||
result = JsonDecode(body);
|
||||
|
||||
Array::Ptr results = result->Get("results");
|
||||
|
||||
ObjectLock olock(results);
|
||||
BOOST_FOREACH(const Dictionary::Ptr objectInfo, results)
|
||||
{
|
||||
ApiObject::Ptr object = new ApiObject();
|
||||
|
||||
Dictionary::Ptr attrs = objectInfo->Get("attrs");
|
||||
|
||||
{
|
||||
ObjectLock olock(attrs);
|
||||
BOOST_FOREACH(const Dictionary::Pair& kv, attrs)
|
||||
{
|
||||
object->Attrs[kv.first] = kv.second;
|
||||
}
|
||||
}
|
||||
|
||||
Array::Ptr used_by = objectInfo->Get("used_by");
|
||||
|
||||
{
|
||||
ObjectLock olock(used_by);
|
||||
BOOST_FOREACH(const Dictionary::Ptr& refInfo, used_by)
|
||||
{
|
||||
ApiObjectReference ref;
|
||||
ref.Name = refInfo->Get("name");
|
||||
ref.Type = refInfo->Get("type");
|
||||
object->UsedBy.push_back(ref);
|
||||
}
|
||||
}
|
||||
|
||||
objects.push_back(object);
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
Log(LogCritical, "ApiClient")
|
||||
<< "Error while decoding response: " << DiagnosticInformation(ex);
|
||||
}
|
||||
|
||||
callback(objects);
|
||||
}
|
111
icinga-studio/api.hpp
Normal file
111
icinga-studio/api.hpp
Normal file
@ -0,0 +1,111 @@
|
||||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef API_H
|
||||
#define API_H
|
||||
|
||||
#include "remote/httpclientconnection.hpp"
|
||||
#include "base/value.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
struct ApiFieldAttributes
|
||||
{
|
||||
public:
|
||||
bool Config;
|
||||
bool Internal;
|
||||
bool Required;
|
||||
bool State;
|
||||
};
|
||||
|
||||
class ApiType;
|
||||
|
||||
struct ApiField
|
||||
{
|
||||
public:
|
||||
String Name;
|
||||
int ID;
|
||||
int ArrayRank;
|
||||
ApiFieldAttributes FieldAttributes;
|
||||
String TypeName;
|
||||
intrusive_ptr<ApiType> Type;
|
||||
};
|
||||
|
||||
class ApiType : public Object
|
||||
{
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(ApiType);
|
||||
|
||||
String Name;
|
||||
String PluralName;
|
||||
String BaseName;
|
||||
ApiType::Ptr Base;
|
||||
bool Abstract;
|
||||
std::map<String, ApiField> Fields;
|
||||
std::vector<String> PrototypeKeys;
|
||||
};
|
||||
|
||||
struct ApiObjectReference
|
||||
{
|
||||
public:
|
||||
String Name;
|
||||
String Type;
|
||||
};
|
||||
|
||||
struct ApiObject : public Object
|
||||
{
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(ApiObject);
|
||||
|
||||
std::map<String, Value> Attrs;
|
||||
std::vector<ApiObjectReference> UsedBy;
|
||||
};
|
||||
|
||||
class ApiClient : public Object
|
||||
{
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(ApiClient);
|
||||
|
||||
ApiClient(const String& host, const String& port,
|
||||
const String& user, const String& password);
|
||||
|
||||
typedef boost::function<void(const std::vector<ApiType::Ptr>&)> TypesCompletionCallback;
|
||||
void GetTypes(const TypesCompletionCallback& callback) const;
|
||||
|
||||
typedef boost::function<void(const std::vector<ApiObject::Ptr>&)> ObjectsCompletionCallback;
|
||||
void GetObjects(const String& pluralType, const ObjectsCompletionCallback& callback,
|
||||
const std::vector<String>& names = std::vector<String>(),
|
||||
const std::vector<String>& attrs = std::vector<String>()) const;
|
||||
|
||||
private:
|
||||
HttpClientConnection::Ptr m_Connection;
|
||||
String m_User;
|
||||
String m_Password;
|
||||
|
||||
static void TypesHttpCompletionCallback(HttpRequest& request,
|
||||
HttpResponse& response, const TypesCompletionCallback& callback);
|
||||
static void ObjectsHttpCompletionCallback(HttpRequest& request,
|
||||
HttpResponse& response, const ObjectsCompletionCallback& callback);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* API_H */
|
63
icinga-studio/connectform.cpp
Normal file
63
icinga-studio/connectform.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "icinga-studio/connectform.hpp"
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
ConnectForm::ConnectForm(wxWindow *parent, const Url::Ptr& url)
|
||||
: ConnectFormBase(parent)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SetIcon(wxICON(icinga));
|
||||
#endif /* _WIN32 */
|
||||
|
||||
std::string authority = url->GetAuthority();
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
boost::algorithm::split(tokens, authority, boost::is_any_of("@"));
|
||||
|
||||
if (tokens.size() > 1) {
|
||||
std::vector<std::string> userinfo;
|
||||
boost::algorithm::split(userinfo, tokens[0], boost::is_any_of(":"));
|
||||
|
||||
m_UserText->SetValue(userinfo[0]);
|
||||
m_PasswordText->SetValue(userinfo[1]);
|
||||
}
|
||||
|
||||
std::vector<std::string> hostport;
|
||||
boost::algorithm::split(hostport, tokens.size() > 1 ? tokens[1] : tokens[0], boost::is_any_of(":"));
|
||||
|
||||
m_HostText->SetValue(hostport[0]);
|
||||
|
||||
if (hostport.size() > 1)
|
||||
m_PortText->SetValue(hostport[1]);
|
||||
else
|
||||
m_PortText->SetValue("5665");
|
||||
}
|
||||
|
||||
Url::Ptr ConnectForm::GetUrl(void) const
|
||||
{
|
||||
wxString url = "https://" + m_UserText->GetValue() + ":" + m_PasswordText->GetValue()
|
||||
+ "@" + m_HostText->GetValue() + ":" + m_PortText->GetValue() + "/";
|
||||
|
||||
return new Url(url.ToStdString());
|
||||
}
|
39
icinga-studio/connectform.hpp
Normal file
39
icinga-studio/connectform.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef CONNECTFORM_H
|
||||
#define CONNECTFORM_H
|
||||
|
||||
#include "remote/url.hpp"
|
||||
#include "icinga-studio/forms.h"
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
class ConnectForm : public ConnectFormBase
|
||||
{
|
||||
public:
|
||||
ConnectForm(wxWindow *parent, const Url::Ptr& url);
|
||||
|
||||
Url::Ptr GetUrl(void) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* CONNECTFORM_H */
|
242
icinga-studio/forms.cpp
Normal file
242
icinga-studio/forms.cpp
Normal file
@ -0,0 +1,242 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version Jun 17 2015)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO "NOT" EDIT THIS FILE!
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "forms.h"
|
||||
|
||||
#include "icinga.xpm"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MainFormBase::MainFormBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
|
||||
{
|
||||
this->SetSizeHints( wxSize( 800,569 ), wxDefaultSize );
|
||||
|
||||
m_MenuBar = new wxMenuBar( 0 );
|
||||
wxMenu* m_FileMenu;
|
||||
m_FileMenu = new wxMenu();
|
||||
wxMenuItem* m_QuitMenuItem;
|
||||
m_QuitMenuItem = new wxMenuItem( m_FileMenu, wxID_EXIT, wxString( wxT("&Quit") ) , wxEmptyString, wxITEM_NORMAL );
|
||||
m_FileMenu->Append( m_QuitMenuItem );
|
||||
|
||||
m_MenuBar->Append( m_FileMenu, wxT("&File") );
|
||||
|
||||
wxMenu* m_HelpMenu;
|
||||
m_HelpMenu = new wxMenu();
|
||||
wxMenuItem* m_AboutMenuItem;
|
||||
m_AboutMenuItem = new wxMenuItem( m_HelpMenu, wxID_ABOUT, wxString( wxT("&About Icinga Studio...") ) , wxEmptyString, wxITEM_NORMAL );
|
||||
m_HelpMenu->Append( m_AboutMenuItem );
|
||||
|
||||
m_MenuBar->Append( m_HelpMenu, wxT("&Help") );
|
||||
|
||||
this->SetMenuBar( m_MenuBar );
|
||||
|
||||
wxBoxSizer* m_DialogSizer;
|
||||
m_DialogSizer = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
wxBoxSizer* m_ConnectionDetailsSizer;
|
||||
m_ConnectionDetailsSizer = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
m_TypesTree = new wxTreeCtrl( this, wxID_ANY, wxDefaultPosition, wxSize( 315,-1 ), wxTR_DEFAULT_STYLE|wxTR_HIDE_ROOT );
|
||||
m_ConnectionDetailsSizer->Add( m_TypesTree, 0, wxALL|wxEXPAND, 2 );
|
||||
|
||||
wxBoxSizer* m_ObjectDetailsSizer;
|
||||
m_ObjectDetailsSizer = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
m_ObjectsList = new wxListCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT );
|
||||
m_ObjectDetailsSizer->Add( m_ObjectsList, 1, wxALL|wxEXPAND, 2 );
|
||||
|
||||
m_PropertyGrid = new wxPropertyGrid(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPG_DEFAULT_STYLE);
|
||||
m_ObjectDetailsSizer->Add( m_PropertyGrid, 1, wxALL|wxEXPAND, 5 );
|
||||
|
||||
|
||||
m_ConnectionDetailsSizer->Add( m_ObjectDetailsSizer, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
m_DialogSizer->Add( m_ConnectionDetailsSizer, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
this->SetSizer( m_DialogSizer );
|
||||
this->Layout();
|
||||
m_StatusBar = this->CreateStatusBar( 1, wxST_SIZEGRIP, wxID_ANY );
|
||||
|
||||
this->Centre( wxBOTH );
|
||||
|
||||
// Connect Events
|
||||
this->Connect( m_QuitMenuItem->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFormBase::OnQuitClicked ) );
|
||||
this->Connect( m_AboutMenuItem->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFormBase::OnAboutClicked ) );
|
||||
m_TypesTree->Connect( wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler( MainFormBase::OnTypeSelected ), NULL, this );
|
||||
m_ObjectsList->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( MainFormBase::OnObjectSelected ), NULL, this );
|
||||
}
|
||||
|
||||
MainFormBase::~MainFormBase()
|
||||
{
|
||||
// Disconnect Events
|
||||
this->Disconnect( wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFormBase::OnQuitClicked ) );
|
||||
this->Disconnect( wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFormBase::OnAboutClicked ) );
|
||||
m_TypesTree->Disconnect( wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler( MainFormBase::OnTypeSelected ), NULL, this );
|
||||
m_ObjectsList->Disconnect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( MainFormBase::OnObjectSelected ), NULL, this );
|
||||
|
||||
}
|
||||
|
||||
ConnectFormBase::ConnectFormBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
|
||||
{
|
||||
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
|
||||
|
||||
wxBoxSizer* m_DialogSizer;
|
||||
m_DialogSizer = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
wxPanel* m_ConnectionDetailsPanel;
|
||||
m_ConnectionDetailsPanel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
|
||||
wxStaticBoxSizer* m_DetailsSizer;
|
||||
m_DetailsSizer = new wxStaticBoxSizer( new wxStaticBox( m_ConnectionDetailsPanel, wxID_ANY, wxT("Connection Details") ), wxVERTICAL );
|
||||
|
||||
wxStaticText* m_HostLabel;
|
||||
m_HostLabel = new wxStaticText( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxT("Host:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_HostLabel->Wrap( -1 );
|
||||
m_DetailsSizer->Add( m_HostLabel, 0, wxALL, 5 );
|
||||
|
||||
m_HostText = new wxTextCtrl( m_DetailsSizer->GetStaticBox(), wxID_OK, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_DetailsSizer->Add( m_HostText, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
wxStaticText* m_PortLabel;
|
||||
m_PortLabel = new wxStaticText( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxT("Port:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_PortLabel->Wrap( -1 );
|
||||
m_DetailsSizer->Add( m_PortLabel, 0, wxALL, 5 );
|
||||
|
||||
m_PortText = new wxTextCtrl( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_DetailsSizer->Add( m_PortText, 0, wxALL, 5 );
|
||||
|
||||
wxStaticText* m_UserLabel;
|
||||
m_UserLabel = new wxStaticText( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxT("API User:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_UserLabel->Wrap( -1 );
|
||||
m_DetailsSizer->Add( m_UserLabel, 0, wxALL, 5 );
|
||||
|
||||
m_UserText = new wxTextCtrl( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_DetailsSizer->Add( m_UserText, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
wxStaticText* m_PasswordLabel;
|
||||
m_PasswordLabel = new wxStaticText( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxT("API Password:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_PasswordLabel->Wrap( -1 );
|
||||
m_DetailsSizer->Add( m_PasswordLabel, 0, wxALL, 5 );
|
||||
|
||||
m_PasswordText = new wxTextCtrl( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD );
|
||||
m_DetailsSizer->Add( m_PasswordText, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
wxStaticText* m_InfoLabel;
|
||||
m_InfoLabel = new wxStaticText( m_DetailsSizer->GetStaticBox(), wxID_ANY, wxT("You can find the username and password for the default user in /etc/icinga2/conf.d/api-users.conf."), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_InfoLabel->Wrap( 270 );
|
||||
m_DetailsSizer->Add( m_InfoLabel, 0, wxALL, 5 );
|
||||
|
||||
|
||||
m_ConnectionDetailsPanel->SetSizer( m_DetailsSizer );
|
||||
m_ConnectionDetailsPanel->Layout();
|
||||
m_DetailsSizer->Fit( m_ConnectionDetailsPanel );
|
||||
m_DialogSizer->Add( m_ConnectionDetailsPanel, 1, wxEXPAND | wxALL, 5 );
|
||||
|
||||
wxPanel* m_ButtonsPanel;
|
||||
m_ButtonsPanel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
|
||||
wxBoxSizer* m_ButtonsSizer;
|
||||
m_ButtonsSizer = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
wxStdDialogButtonSizer* m_Buttons;
|
||||
wxButton* m_ButtonsOK;
|
||||
wxButton* m_ButtonsCancel;
|
||||
m_Buttons = new wxStdDialogButtonSizer();
|
||||
m_ButtonsOK = new wxButton( m_ButtonsPanel, wxID_OK );
|
||||
m_Buttons->AddButton( m_ButtonsOK );
|
||||
m_ButtonsCancel = new wxButton( m_ButtonsPanel, wxID_CANCEL );
|
||||
m_Buttons->AddButton( m_ButtonsCancel );
|
||||
m_Buttons->Realize();
|
||||
|
||||
m_ButtonsSizer->Add( m_Buttons, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
m_ButtonsPanel->SetSizer( m_ButtonsSizer );
|
||||
m_ButtonsPanel->Layout();
|
||||
m_ButtonsSizer->Fit( m_ButtonsPanel );
|
||||
m_DialogSizer->Add( m_ButtonsPanel, 0, wxEXPAND | wxALL, 5 );
|
||||
|
||||
|
||||
this->SetSizer( m_DialogSizer );
|
||||
this->Layout();
|
||||
m_DialogSizer->Fit( this );
|
||||
|
||||
this->Centre( wxBOTH );
|
||||
}
|
||||
|
||||
ConnectFormBase::~ConnectFormBase()
|
||||
{
|
||||
}
|
||||
|
||||
AboutFormBase::AboutFormBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
|
||||
{
|
||||
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
|
||||
|
||||
wxBoxSizer* m_DialogSizer;
|
||||
m_DialogSizer = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
wxBoxSizer* m_InfoSizer;
|
||||
m_InfoSizer = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
wxStaticBitmap* m_ProductIcon;
|
||||
m_ProductIcon = new wxStaticBitmap( this, wxID_ANY, wxBitmap( icinga_xpm ), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_InfoSizer->Add( m_ProductIcon, 0, wxALL, 5 );
|
||||
|
||||
wxBoxSizer* m_AboutInfoSizer;
|
||||
m_AboutInfoSizer = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
wxStaticText* m_ProductNameLabel;
|
||||
m_ProductNameLabel = new wxStaticText( this, wxID_ANY, wxT("Icinga Studio"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_ProductNameLabel->Wrap( -1 );
|
||||
m_AboutInfoSizer->Add( m_ProductNameLabel, 0, wxALL, 5 );
|
||||
|
||||
m_VersionLabel = new wxStaticText( this, wxID_ANY, wxT("Version"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_VersionLabel->Wrap( -1 );
|
||||
m_AboutInfoSizer->Add( m_VersionLabel, 0, wxALL, 5 );
|
||||
|
||||
wxStaticText* m_CopyrightLabel;
|
||||
m_CopyrightLabel = new wxStaticText( this, wxID_ANY, wxT("Copyright (c) 2015 Icinga Development Team"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_CopyrightLabel->Wrap( -1 );
|
||||
m_AboutInfoSizer->Add( m_CopyrightLabel, 0, wxALL, 5 );
|
||||
|
||||
|
||||
m_InfoSizer->Add( m_AboutInfoSizer, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
m_DialogSizer->Add( m_InfoSizer, 1, wxEXPAND, 5 );
|
||||
|
||||
wxPanel* m_ButtonsPanel;
|
||||
m_ButtonsPanel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
|
||||
wxBoxSizer* m_ButtonsSizer;
|
||||
m_ButtonsSizer = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
wxStdDialogButtonSizer* m_Buttons;
|
||||
wxButton* m_ButtonsOK;
|
||||
m_Buttons = new wxStdDialogButtonSizer();
|
||||
m_ButtonsOK = new wxButton( m_ButtonsPanel, wxID_OK );
|
||||
m_Buttons->AddButton( m_ButtonsOK );
|
||||
m_Buttons->Realize();
|
||||
|
||||
m_ButtonsSizer->Add( m_Buttons, 0, wxEXPAND, 5 );
|
||||
|
||||
|
||||
m_ButtonsPanel->SetSizer( m_ButtonsSizer );
|
||||
m_ButtonsPanel->Layout();
|
||||
m_ButtonsSizer->Fit( m_ButtonsPanel );
|
||||
m_DialogSizer->Add( m_ButtonsPanel, 0, wxEXPAND | wxALL, 5 );
|
||||
|
||||
|
||||
this->SetSizer( m_DialogSizer );
|
||||
this->Layout();
|
||||
m_DialogSizer->Fit( this );
|
||||
|
||||
this->Centre( wxBOTH );
|
||||
}
|
||||
|
||||
AboutFormBase::~AboutFormBase()
|
||||
{
|
||||
}
|
105
icinga-studio/forms.h
Normal file
105
icinga-studio/forms.h
Normal file
@ -0,0 +1,105 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version Jun 17 2015)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO "NOT" EDIT THIS FILE!
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef __FORMS_H__
|
||||
#define __FORMS_H__
|
||||
|
||||
#include <wx/artprov.h>
|
||||
#include <wx/xrc/xmlres.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/icon.h>
|
||||
#include <wx/menu.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/font.h>
|
||||
#include <wx/colour.h>
|
||||
#include <wx/settings.h>
|
||||
#include <wx/treectrl.h>
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/propgrid/propgrid.h>
|
||||
#include <wx/propgrid/advprops.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/statusbr.h>
|
||||
#include <wx/frame.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/statbox.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/statbmp.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Class MainFormBase
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class MainFormBase : public wxFrame
|
||||
{
|
||||
private:
|
||||
|
||||
protected:
|
||||
wxMenuBar* m_MenuBar;
|
||||
wxTreeCtrl* m_TypesTree;
|
||||
wxListCtrl* m_ObjectsList;
|
||||
wxPropertyGrid* m_PropertyGrid;
|
||||
wxStatusBar* m_StatusBar;
|
||||
|
||||
// Virtual event handlers, overide them in your derived class
|
||||
virtual void OnQuitClicked( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnAboutClicked( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnTypeSelected( wxTreeEvent& event ) { event.Skip(); }
|
||||
virtual void OnObjectSelected( wxListEvent& event ) { event.Skip(); }
|
||||
|
||||
|
||||
public:
|
||||
|
||||
MainFormBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Icinga Studio"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 800,569 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
|
||||
|
||||
~MainFormBase();
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Class ConnectFormBase
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class ConnectFormBase : public wxDialog
|
||||
{
|
||||
private:
|
||||
|
||||
protected:
|
||||
wxTextCtrl* m_HostText;
|
||||
wxTextCtrl* m_PortText;
|
||||
wxTextCtrl* m_UserText;
|
||||
wxTextCtrl* m_PasswordText;
|
||||
|
||||
public:
|
||||
|
||||
ConnectFormBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Icinga Studio - Connect"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE );
|
||||
~ConnectFormBase();
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Class AboutFormBase
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class AboutFormBase : public wxDialog
|
||||
{
|
||||
private:
|
||||
|
||||
protected:
|
||||
wxStaticText* m_VersionLabel;
|
||||
|
||||
public:
|
||||
|
||||
AboutFormBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("About Icinga Studio"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE );
|
||||
~AboutFormBase();
|
||||
|
||||
};
|
||||
|
||||
#endif //__FORMS_H__
|
66
icinga-studio/icinga-studio.cpp
Normal file
66
icinga-studio/icinga-studio.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "icinga-studio/connectform.hpp"
|
||||
#include "icinga-studio/mainform.hpp"
|
||||
#include "base/application.hpp"
|
||||
#include <wx/wx.h>
|
||||
#include <wx/app.h>
|
||||
#include <wx/config.h>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
class IcingaStudio : public wxApp
|
||||
{
|
||||
public:
|
||||
virtual bool OnInit(void) override
|
||||
{
|
||||
Application::InitializeBase();
|
||||
|
||||
Url::Ptr pUrl;
|
||||
|
||||
if (argc < 2) {
|
||||
wxConfig config("IcingaStudio");
|
||||
wxString wUrl;
|
||||
|
||||
if (!config.Read("url", &wUrl))
|
||||
wUrl = "https://localhost:5665/";
|
||||
|
||||
std::string url = wUrl.ToStdString();
|
||||
|
||||
ConnectForm f(NULL, new Url(url));
|
||||
if (f.ShowModal() != wxID_OK)
|
||||
return false;
|
||||
|
||||
pUrl = f.GetUrl();
|
||||
url = pUrl->Format();
|
||||
wUrl = url;
|
||||
config.Write("url", wUrl);
|
||||
} else {
|
||||
pUrl = new Url(argv[1].ToStdString());
|
||||
}
|
||||
|
||||
MainForm *m = new MainForm(NULL, pUrl);
|
||||
m->Show();
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
wxIMPLEMENT_APP(IcingaStudio);
|
BIN
icinga-studio/icinga.icns
Normal file
BIN
icinga-studio/icinga.icns
Normal file
Binary file not shown.
BIN
icinga-studio/icinga.ico
Normal file
BIN
icinga-studio/icinga.ico
Normal file
Binary file not shown.
After (image error) Size: 766 B |
34
icinga-studio/icinga.rc
Normal file
34
icinga-studio/icinga.rc
Normal file
@ -0,0 +1,34 @@
|
||||
#include <windows.h>
|
||||
#include "icinga-version.h"
|
||||
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
icinga ICON "icinga.ico"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,0
|
||||
PRODUCTVERSION 1,0,0,0
|
||||
FILEOS VOS__WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Icinga Development Team"
|
||||
VALUE "FileDescription", "Icinga Studio"
|
||||
VALUE "FileVersion", VERSION
|
||||
VALUE "InternalName", "icinga-studio.exe"
|
||||
VALUE "LegalCopyright", "© Icinga Development Team"
|
||||
VALUE "OriginalFilename", "icinga-studio.exe"
|
||||
VALUE "ProductName", "Icinga 2"
|
||||
VALUE "ProductVersion", VERSION
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 0x04E4
|
||||
END
|
||||
END
|
40
icinga-studio/icinga.xpm
Normal file
40
icinga-studio/icinga.xpm
Normal file
@ -0,0 +1,40 @@
|
||||
/* XPM */
|
||||
static const char *icinga_xpm[] = {
|
||||
"32 32 5 1",
|
||||
" c None",
|
||||
". c #808080",
|
||||
"+ c #000000",
|
||||
"@ c #C0C0C0",
|
||||
"# c #FFFFFF",
|
||||
" ",
|
||||
" .++++++++++++++++++++++++. ",
|
||||
" .+++++++++++++++..+++++++++. ",
|
||||
" .+++++++++++++++@##@+++++++++. ",
|
||||
" +++++++++++++++.####.+++++++++ ",
|
||||
" +++++++++++++++.####.+++++++++ ",
|
||||
" ++++++++++++++++####++++++++++ ",
|
||||
" ++++++++++++++++@@..++++++++++ ",
|
||||
" +++++..+++++++++#.++++++++++++ ",
|
||||
" ++++.##@+++++++@#+++++++++++++ ",
|
||||
" ++++.###+++++++#.+++++++++.+++ ",
|
||||
" ++++.###@++.@@@#+++++++++@##.+ ",
|
||||
" +++++++.@#######.+++++++.###@+ ",
|
||||
" +++++++++########++++..@####.+ ",
|
||||
" ++++++++.########@@###@...@.++ ",
|
||||
" ++++++++.#########@..+++++++++ ",
|
||||
" ++++++++.########@++++++++++++ ",
|
||||
" ++++++++.########.++++++++++++ ",
|
||||
" +++++++++########+++++++++++++ ",
|
||||
" +++++++++.######.+++++++++++++ ",
|
||||
" +++++++++.#....#.+++++++++++++ ",
|
||||
" ++++++++.#.++++.#.++++++++++++ ",
|
||||
" ++++++++@@++++++##.+++++++++++ ",
|
||||
" ++++@##@#+++++++##@+++++++++++ ",
|
||||
" +++@####@+++++++..++++++++++++ ",
|
||||
" +++######.++++++++++++++++++++ ",
|
||||
" +++######.++++++++++++++++++++ ",
|
||||
" +++######+++++++++++++++++++++ ",
|
||||
" .++.####.++++++++++++++++++++. ",
|
||||
" .+++..+++++++++++++++++++++. ",
|
||||
" .++++++++++++++++++++++++. ",
|
||||
" "};
|
258
icinga-studio/mainform.cpp
Normal file
258
icinga-studio/mainform.cpp
Normal file
@ -0,0 +1,258 @@
|
||||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "icinga-studio/mainform.hpp"
|
||||
#include "icinga-studio/aboutform.hpp"
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
MainForm::MainForm(wxWindow *parent, const Url::Ptr& url)
|
||||
: MainFormBase(parent)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SetIcon(wxICON(icinga));
|
||||
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
|
||||
#endif /* _WIN32 */
|
||||
|
||||
String host, port, user, pass;
|
||||
|
||||
std::string authority = url->GetAuthority();
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
boost::algorithm::split(tokens, authority, boost::is_any_of("@"));
|
||||
|
||||
if (tokens.size() > 1) {
|
||||
std::vector<std::string> userinfo;
|
||||
boost::algorithm::split(userinfo, tokens[0], boost::is_any_of(":"));
|
||||
|
||||
user = userinfo[0];
|
||||
pass = userinfo[1];
|
||||
}
|
||||
|
||||
std::vector<std::string> hostport;
|
||||
boost::algorithm::split(hostport, tokens.size() > 1 ? tokens[1] : tokens[0], boost::is_any_of(":"));
|
||||
|
||||
host = hostport[0];
|
||||
|
||||
if (hostport.size() > 1)
|
||||
port = hostport[1];
|
||||
else
|
||||
port = "5665";
|
||||
|
||||
m_ApiClient = new ApiClient(host, port, user, pass);
|
||||
m_ApiClient->GetTypes(boost::bind(&MainForm::TypesCompletionHandler, this, _1, true));
|
||||
|
||||
std::string title = host;
|
||||
|
||||
if (port != "5665")
|
||||
title += +":" + port;
|
||||
|
||||
title += " - Icinga Studio";
|
||||
SetTitle(title);
|
||||
|
||||
m_ObjectsList->InsertColumn(0, "Name", 0, 300);
|
||||
}
|
||||
|
||||
void MainForm::TypesCompletionHandler(const std::vector<ApiType::Ptr>& types, bool forward)
|
||||
{
|
||||
if (forward) {
|
||||
CallAfter(boost::bind(&MainForm::TypesCompletionHandler, this, types, false));
|
||||
return;
|
||||
}
|
||||
|
||||
m_TypesTree->DeleteAllItems();
|
||||
wxTreeItemId rootNode = m_TypesTree->AddRoot("root");
|
||||
|
||||
bool all = false;
|
||||
std::map<String, wxTreeItemId> items;
|
||||
|
||||
m_Types.clear();
|
||||
|
||||
while (!all) {
|
||||
all = true;
|
||||
|
||||
BOOST_FOREACH(const ApiType::Ptr& type, types) {
|
||||
std::string name = type->Name;
|
||||
|
||||
if (items.find(name) != items.end())
|
||||
continue;
|
||||
|
||||
all = false;
|
||||
|
||||
wxTreeItemId parent;
|
||||
|
||||
if (type->BaseName.IsEmpty())
|
||||
parent = rootNode;
|
||||
else {
|
||||
std::map<String, wxTreeItemId>::const_iterator it = items.find(type->BaseName);
|
||||
|
||||
if (it == items.end())
|
||||
continue;
|
||||
|
||||
parent = it->second;
|
||||
}
|
||||
|
||||
m_Types[name] = type;
|
||||
items[name] = m_TypesTree->AppendItem(parent, name, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainForm::OnTypeSelected(wxTreeEvent& event)
|
||||
{
|
||||
wxTreeItemId selectedId = m_TypesTree->GetSelection();
|
||||
wxString typeName = m_TypesTree->GetItemText(selectedId);
|
||||
ApiType::Ptr type = m_Types[typeName.ToStdString()];
|
||||
|
||||
std::vector<String> attrs;
|
||||
attrs.push_back(type->Name.ToLower() + ".__name");
|
||||
|
||||
m_ApiClient->GetObjects(type->PluralName, boost::bind(&MainForm::ObjectsCompletionHandler, this, _1, true),
|
||||
std::vector<String>(), attrs);
|
||||
}
|
||||
|
||||
void MainForm::ObjectsCompletionHandler(const std::vector<ApiObject::Ptr>& objects, bool forward)
|
||||
{
|
||||
if (forward) {
|
||||
CallAfter(boost::bind(&MainForm::ObjectsCompletionHandler, this, objects, false));
|
||||
return;
|
||||
}
|
||||
|
||||
wxTreeItemId selectedId = m_TypesTree->GetSelection();
|
||||
wxString typeName = m_TypesTree->GetItemText(selectedId);
|
||||
ApiType::Ptr type = m_Types[typeName.ToStdString()];
|
||||
|
||||
String nameAttr = type->Name.ToLower() + ".__name";
|
||||
|
||||
m_ObjectsList->DeleteAllItems();
|
||||
|
||||
BOOST_FOREACH(const ApiObject::Ptr& object, objects) {
|
||||
std::map<String, Value>::const_iterator it = object->Attrs.find(nameAttr);
|
||||
if (it == object->Attrs.end())
|
||||
continue;
|
||||
String name = it->second;
|
||||
m_ObjectsList->InsertItem(0, name.GetData());
|
||||
}
|
||||
}
|
||||
|
||||
void MainForm::OnObjectSelected(wxListEvent& event)
|
||||
{
|
||||
wxTreeItemId selectedId = m_TypesTree->GetSelection();
|
||||
wxString typeName = m_TypesTree->GetItemText(selectedId);
|
||||
ApiType::Ptr type = m_Types[typeName.ToStdString()];
|
||||
|
||||
long itemIndex = -1;
|
||||
std::string objectName;
|
||||
|
||||
while ((itemIndex = m_ObjectsList->GetNextItem(itemIndex,
|
||||
wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)) != wxNOT_FOUND) {
|
||||
objectName = m_ObjectsList->GetItemText(itemIndex);
|
||||
break;
|
||||
}
|
||||
|
||||
if (objectName.empty())
|
||||
return;
|
||||
|
||||
std::vector<String> names;
|
||||
names.push_back(objectName);
|
||||
|
||||
m_ApiClient->GetObjects(type->PluralName, boost::bind(&MainForm::ObjectDetailsCompletionHandler, this, _1, true), names);
|
||||
}
|
||||
|
||||
wxPGProperty *MainForm::ValueToProperty(const String& name, const Value& value)
|
||||
{
|
||||
wxPGProperty *prop;
|
||||
|
||||
if (value.IsNumber()) {
|
||||
double val = value;
|
||||
return new wxFloatProperty(name.GetData(), wxPG_LABEL, value);
|
||||
} else if (value.IsBoolean()) {
|
||||
bool val = value;
|
||||
return new wxBoolProperty(name.GetData(), wxPG_LABEL, value);
|
||||
} else if (value.IsObjectType<Array>()) {
|
||||
wxArrayString val;
|
||||
Array::Ptr arr = value;
|
||||
ObjectLock olock(arr);
|
||||
BOOST_FOREACH(const Value& aitem, arr)
|
||||
{
|
||||
String val1 = aitem;
|
||||
val.Add(val1.GetData());
|
||||
}
|
||||
|
||||
return new wxArrayStringProperty(name.GetData(), wxPG_LABEL, val);
|
||||
} else if (value.IsObjectType<Dictionary>()) {
|
||||
wxStringProperty *prop = new wxStringProperty(name.GetData(), wxPG_LABEL, "<dictionary>");
|
||||
|
||||
Dictionary::Ptr dict = value;
|
||||
ObjectLock olock(dict);
|
||||
BOOST_FOREACH(const Dictionary::Pair& kv, dict) {
|
||||
prop->AppendChild(ValueToProperty(kv.first, kv.second));
|
||||
}
|
||||
|
||||
return prop;
|
||||
} else {
|
||||
String val = value;
|
||||
return new wxStringProperty(name.GetData(), wxPG_LABEL, val.GetData());
|
||||
}
|
||||
}
|
||||
|
||||
void MainForm::ObjectDetailsCompletionHandler(const std::vector<ApiObject::Ptr>& objects, bool forward)
|
||||
{
|
||||
if (forward) {
|
||||
CallAfter(boost::bind(&MainForm::ObjectDetailsCompletionHandler, this, objects, false));
|
||||
return;
|
||||
}
|
||||
|
||||
wxTreeItemId selectedId = m_TypesTree->GetSelection();
|
||||
wxString typeName = m_TypesTree->GetItemText(selectedId);
|
||||
ApiType::Ptr type = m_Types[typeName.ToStdString()];
|
||||
|
||||
String nameAttr = type->Name.ToLower() + ".__name";
|
||||
|
||||
m_PropertyGrid->Clear();
|
||||
|
||||
if (objects.empty())
|
||||
return;
|
||||
|
||||
ApiObject::Ptr object = objects[0];
|
||||
|
||||
typedef std::pair<String, Value> kv_pair;
|
||||
BOOST_FOREACH(const kv_pair& kv, object->Attrs) {
|
||||
std::vector<String> tokens;
|
||||
boost::algorithm::split(tokens, kv.first, boost::is_any_of("."));
|
||||
|
||||
wxPGProperty *prop = ValueToProperty(tokens[1], kv.second);
|
||||
m_PropertyGrid->Append(prop);
|
||||
m_PropertyGrid->SetPropertyReadOnly(prop);
|
||||
}
|
||||
}
|
||||
|
||||
void MainForm::OnQuitClicked(wxCommandEvent& event)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void MainForm::OnAboutClicked(wxCommandEvent& event)
|
||||
{
|
||||
AboutForm form(this);
|
||||
form.ShowModal();
|
||||
}
|
53
icinga-studio/mainform.hpp
Normal file
53
icinga-studio/mainform.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef MAINFORM_H
|
||||
#define MAINFORM_H
|
||||
|
||||
#include "icinga-studio/api.hpp"
|
||||
#include "remote/url.hpp"
|
||||
#include "icinga-studio/forms.h"
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
class MainForm : public MainFormBase
|
||||
{
|
||||
public:
|
||||
MainForm(wxWindow *parent, const Url::Ptr& url);
|
||||
|
||||
virtual void OnQuitClicked(wxCommandEvent& event) override;
|
||||
virtual void OnAboutClicked(wxCommandEvent& event) override;
|
||||
virtual void OnTypeSelected(wxTreeEvent& event) override;
|
||||
virtual void OnObjectSelected(wxListEvent& event) override;
|
||||
|
||||
private:
|
||||
ApiClient::Ptr m_ApiClient;
|
||||
std::map<String, ApiType::Ptr> m_Types;
|
||||
|
||||
void TypesCompletionHandler(const std::vector<ApiType::Ptr>& types, bool forward);
|
||||
void ObjectsCompletionHandler(const std::vector<ApiObject::Ptr>& objects, bool forward);
|
||||
void ObjectDetailsCompletionHandler(const std::vector<ApiObject::Ptr>& objects, bool forward);
|
||||
|
||||
wxPGProperty *ValueToProperty(const String& name, const Value& value);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* MAINFORM_H */
|
@ -86,4 +86,11 @@ install(
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
install(
|
||||
TARGETS base
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}/icinga-studio.app/Contents
|
||||
)
|
||||
endif()
|
||||
|
||||
set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}" PARENT_SCOPE)
|
||||
|
@ -147,7 +147,15 @@ typedef boost::error_info<struct errinfo_getaddrinfo_error_, int> errinfo_getadd
|
||||
|
||||
inline std::string to_string(const errinfo_getaddrinfo_error& e)
|
||||
{
|
||||
return "[errinfo_getaddrinfo_error] = " + String(gai_strerror(e.value())) + "\n";
|
||||
String msg;
|
||||
|
||||
#ifdef _WIN32
|
||||
msg = gai_strerrorA(e.value());
|
||||
#else /* _WIN32 */
|
||||
msg = gai_strerror(e.value());
|
||||
#endif /* _WIN32 */
|
||||
|
||||
return "[errinfo_getaddrinfo_error] = " + String(msg) + "\n";
|
||||
}
|
||||
|
||||
struct errinfo_message_;
|
||||
|
@ -207,6 +207,8 @@ void SocketEvents::Register(Object *lifesupportObject)
|
||||
|
||||
l_SocketIOSockets[m_FD] = desc;
|
||||
|
||||
m_Events = true;
|
||||
|
||||
/* There's no need to wake up the I/O thread here. */
|
||||
}
|
||||
|
||||
@ -220,6 +222,8 @@ void SocketEvents::Unregister(void)
|
||||
|
||||
l_SocketIOSockets.erase(m_FD);
|
||||
m_FD = INVALID_SOCKET;
|
||||
|
||||
m_Events = false;
|
||||
}
|
||||
|
||||
WakeUpThread(true);
|
||||
@ -244,6 +248,12 @@ void SocketEvents::ChangeEvents(int events)
|
||||
WakeUpThread();
|
||||
}
|
||||
|
||||
bool SocketEvents::IsHandlingEvents(void) const
|
||||
{
|
||||
boost::mutex::scoped_lock lock(l_SocketIOMutex);
|
||||
return m_Events;
|
||||
}
|
||||
|
||||
void SocketEvents::OnEvent(int revents)
|
||||
{
|
||||
|
||||
|
@ -42,11 +42,14 @@ public:
|
||||
|
||||
void ChangeEvents(int events);
|
||||
|
||||
bool IsHandlingEvents(void) const;
|
||||
|
||||
protected:
|
||||
SocketEvents(const Socket::Ptr& socket, Object *lifesupportObject);
|
||||
|
||||
private:
|
||||
SOCKET m_FD;
|
||||
bool m_Events;
|
||||
|
||||
static void InitializeThread(void);
|
||||
static void ThreadProc(void);
|
||||
|
@ -191,7 +191,7 @@ void TlsStream::OnEvent(int revents)
|
||||
|
||||
lock.unlock();
|
||||
|
||||
while (m_RecvQ->IsDataAvailable())
|
||||
while (m_RecvQ->IsDataAvailable() && IsHandlingEvents())
|
||||
SignalDataAvailable();
|
||||
|
||||
if (m_Shutdown && !m_SendQ->IsDataAvailable())
|
||||
@ -318,6 +318,8 @@ void TlsStream::Close(void)
|
||||
|
||||
boost::mutex::scoped_lock lock(m_Mutex);
|
||||
|
||||
m_Eof = true;
|
||||
|
||||
if (!m_SSL)
|
||||
return;
|
||||
|
||||
@ -326,8 +328,6 @@ void TlsStream::Close(void)
|
||||
|
||||
m_Socket->Close();
|
||||
m_Socket.reset();
|
||||
|
||||
m_Eof = true;
|
||||
}
|
||||
|
||||
bool TlsStream::IsEof(void) const
|
||||
|
@ -48,7 +48,7 @@ class I2_BASE_API TlsStream : public Stream, private SocketEvents
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(TlsStream);
|
||||
|
||||
TlsStream(const Socket::Ptr& socket, const String& hostname, ConnectionRole role, const boost::shared_ptr<SSL_CTX>& sslContext);
|
||||
TlsStream(const Socket::Ptr& socket, const String& hostname, ConnectionRole role, const boost::shared_ptr<SSL_CTX>& sslContext = MakeSSLContext());
|
||||
~TlsStream(void);
|
||||
|
||||
boost::shared_ptr<X509> GetClientCertificate(void) const;
|
||||
|
@ -88,30 +88,34 @@ boost::shared_ptr<SSL_CTX> MakeSSLContext(const String& pubkey, const String& pr
|
||||
SSL_CTX_set_mode(sslContext.get(), SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
SSL_CTX_set_session_id_context(sslContext.get(), (const unsigned char *)"Icinga 2", 8);
|
||||
|
||||
if (!SSL_CTX_use_certificate_chain_file(sslContext.get(), pubkey.CStr())) {
|
||||
Log(LogCritical, "SSL")
|
||||
<< "Error with public key file '" << pubkey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
||||
BOOST_THROW_EXCEPTION(openssl_error()
|
||||
<< boost::errinfo_api_function("SSL_CTX_use_certificate_chain_file")
|
||||
<< errinfo_openssl_error(ERR_peek_error())
|
||||
<< boost::errinfo_file_name(pubkey));
|
||||
if (!pubkey.IsEmpty()) {
|
||||
if (!SSL_CTX_use_certificate_chain_file(sslContext.get(), pubkey.CStr())) {
|
||||
Log(LogCritical, "SSL")
|
||||
<< "Error with public key file '" << pubkey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
||||
BOOST_THROW_EXCEPTION(openssl_error()
|
||||
<< boost::errinfo_api_function("SSL_CTX_use_certificate_chain_file")
|
||||
<< errinfo_openssl_error(ERR_peek_error())
|
||||
<< boost::errinfo_file_name(pubkey));
|
||||
}
|
||||
}
|
||||
|
||||
if (!SSL_CTX_use_PrivateKey_file(sslContext.get(), privkey.CStr(), SSL_FILETYPE_PEM)) {
|
||||
Log(LogCritical, "SSL")
|
||||
<< "Error with private key file '" << privkey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
||||
BOOST_THROW_EXCEPTION(openssl_error()
|
||||
<< boost::errinfo_api_function("SSL_CTX_use_PrivateKey_file")
|
||||
<< errinfo_openssl_error(ERR_peek_error())
|
||||
<< boost::errinfo_file_name(privkey));
|
||||
}
|
||||
if (!privkey.IsEmpty()) {
|
||||
if (!SSL_CTX_use_PrivateKey_file(sslContext.get(), privkey.CStr(), SSL_FILETYPE_PEM)) {
|
||||
Log(LogCritical, "SSL")
|
||||
<< "Error with private key file '" << privkey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
||||
BOOST_THROW_EXCEPTION(openssl_error()
|
||||
<< boost::errinfo_api_function("SSL_CTX_use_PrivateKey_file")
|
||||
<< errinfo_openssl_error(ERR_peek_error())
|
||||
<< boost::errinfo_file_name(privkey));
|
||||
}
|
||||
|
||||
if (!SSL_CTX_check_private_key(sslContext.get())) {
|
||||
Log(LogCritical, "SSL")
|
||||
<< "Error checking private key '" << privkey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
||||
BOOST_THROW_EXCEPTION(openssl_error()
|
||||
<< boost::errinfo_api_function("SSL_CTX_check_private_key")
|
||||
<< errinfo_openssl_error(ERR_peek_error()));
|
||||
if (!SSL_CTX_check_private_key(sslContext.get())) {
|
||||
Log(LogCritical, "SSL")
|
||||
<< "Error checking private key '" << privkey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
||||
BOOST_THROW_EXCEPTION(openssl_error()
|
||||
<< boost::errinfo_api_function("SSL_CTX_check_private_key")
|
||||
<< errinfo_openssl_error(ERR_peek_error()));
|
||||
}
|
||||
}
|
||||
|
||||
if (!cakey.IsEmpty()) {
|
||||
|
@ -38,7 +38,7 @@ namespace icinga
|
||||
{
|
||||
|
||||
void I2_BASE_API InitializeOpenSSL(void);
|
||||
boost::shared_ptr<SSL_CTX> I2_BASE_API MakeSSLContext(const String& pubkey, const String& privkey, const String& cakey = String());
|
||||
boost::shared_ptr<SSL_CTX> I2_BASE_API MakeSSLContext(const String& pubkey = String(), const String& privkey = String(), const String& cakey = String());
|
||||
void I2_BASE_API AddCRLToSSLContext(const boost::shared_ptr<SSL_CTX>& context, const String& crlPath);
|
||||
String I2_BASE_API GetCertificateCN(const boost::shared_ptr<X509>& certificate);
|
||||
boost::shared_ptr<X509> I2_BASE_API GetX509Certificate(const String& pemfile);
|
||||
|
@ -21,10 +21,12 @@
|
||||
#define WIN32_H
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||
#endif /* _WIN32_WINNT */
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <imagehlp.h>
|
||||
#include <shlwapi.h>
|
||||
|
@ -61,3 +61,10 @@ install(
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
install(
|
||||
TARGETS config
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}/icinga-studio.app/Contents
|
||||
)
|
||||
endif()
|
||||
|
@ -27,7 +27,7 @@ set(remote_SOURCES
|
||||
configfileshandler.cpp configmoduleshandler.cpp configmoduleutility.cpp configobjectutility.cpp
|
||||
configstageshandler.cpp createobjecthandler.cpp deleteobjecthandler.cpp
|
||||
endpoint.cpp endpoint.thpp filterutility.cpp
|
||||
httpchunkedencoding.cpp httpconnection.cpp httphandler.cpp httprequest.cpp httpresponse.cpp
|
||||
httpchunkedencoding.cpp httpclientconnection.cpp httpserverconnection.cpp httphandler.cpp httprequest.cpp httpresponse.cpp
|
||||
httputility.cpp jsonrpc.cpp jsonrpcconnection.cpp jsonrpcconnection-heartbeat.cpp
|
||||
messageorigin.cpp modifyobjecthandler.cpp statusqueryhandler.cpp typequeryhandler.cpp
|
||||
url.cpp zone.cpp zone.thpp
|
||||
@ -55,6 +55,13 @@ install(
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
install(
|
||||
TARGETS remote
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}/icinga-studio.app/Contents
|
||||
)
|
||||
endif()
|
||||
|
||||
#install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/api\")")
|
||||
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/api/log\")")
|
||||
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/api/repository\")")
|
||||
|
@ -386,7 +386,7 @@ void ApiListener::NewClientHandlerInternal(const Socket::Ptr& client, const Stri
|
||||
} else {
|
||||
Log(LogInformation, "ApiListener", "New HTTP client");
|
||||
|
||||
HttpConnection::Ptr aclient = new HttpConnection(identity, verify_ok, tlsStream);
|
||||
HttpServerConnection::Ptr aclient = new HttpServerConnection(identity, verify_ok, tlsStream);
|
||||
aclient->Start();
|
||||
AddHttpClient(aclient);
|
||||
}
|
||||
@ -908,19 +908,19 @@ std::set<JsonRpcConnection::Ptr> ApiListener::GetAnonymousClients(void) const
|
||||
return m_AnonymousClients;
|
||||
}
|
||||
|
||||
void ApiListener::AddHttpClient(const HttpConnection::Ptr& aclient)
|
||||
void ApiListener::AddHttpClient(const HttpServerConnection::Ptr& aclient)
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
m_HttpClients.insert(aclient);
|
||||
}
|
||||
|
||||
void ApiListener::RemoveHttpClient(const HttpConnection::Ptr& aclient)
|
||||
void ApiListener::RemoveHttpClient(const HttpServerConnection::Ptr& aclient)
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
m_HttpClients.erase(aclient);
|
||||
}
|
||||
|
||||
std::set<HttpConnection::Ptr> ApiListener::GetHttpClients(void) const
|
||||
std::set<HttpServerConnection::Ptr> ApiListener::GetHttpClients(void) const
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
return m_HttpClients;
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
#include "remote/apilistener.thpp"
|
||||
#include "remote/jsonrpcconnection.hpp"
|
||||
#include "remote/httpconnection.hpp"
|
||||
#include "remote/httpserverconnection.hpp"
|
||||
#include "remote/endpoint.hpp"
|
||||
#include "remote/messageorigin.hpp"
|
||||
#include "base/configobject.hpp"
|
||||
@ -69,9 +69,9 @@ public:
|
||||
void RemoveAnonymousClient(const JsonRpcConnection::Ptr& aclient);
|
||||
std::set<JsonRpcConnection::Ptr> GetAnonymousClients(void) const;
|
||||
|
||||
void AddHttpClient(const HttpConnection::Ptr& aclient);
|
||||
void RemoveHttpClient(const HttpConnection::Ptr& aclient);
|
||||
std::set<HttpConnection::Ptr> GetHttpClients(void) const;
|
||||
void AddHttpClient(const HttpServerConnection::Ptr& aclient);
|
||||
void RemoveHttpClient(const HttpServerConnection::Ptr& aclient);
|
||||
std::set<HttpServerConnection::Ptr> GetHttpClients(void) const;
|
||||
|
||||
static Value ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
|
||||
|
||||
@ -85,7 +85,7 @@ private:
|
||||
boost::shared_ptr<SSL_CTX> m_SSLContext;
|
||||
std::set<TcpSocket::Ptr> m_Servers;
|
||||
std::set<JsonRpcConnection::Ptr> m_AnonymousClients;
|
||||
std::set<HttpConnection::Ptr> m_HttpClients;
|
||||
std::set<HttpServerConnection::Ptr> m_HttpClients;
|
||||
Timer::Ptr m_Timer;
|
||||
|
||||
void ApiTimerHandler(void);
|
||||
|
@ -28,6 +28,7 @@ StreamReadStatus HttpChunkedEncoding::ReadChunkFromStream(const Stream::Ptr& str
|
||||
if (context.LengthIndicator == -1) {
|
||||
String line;
|
||||
StreamReadStatus status = stream->ReadLine(&line, context.StreamContext, may_wait);
|
||||
may_wait = false;
|
||||
|
||||
if (status != StatusNewItem)
|
||||
return status;
|
||||
@ -36,35 +37,36 @@ StreamReadStatus HttpChunkedEncoding::ReadChunkFromStream(const Stream::Ptr& str
|
||||
msgbuf << std::hex << line;
|
||||
msgbuf >> context.LengthIndicator;
|
||||
|
||||
return StatusNeedData;
|
||||
} else {
|
||||
StreamReadContext& scontext = context.StreamContext;
|
||||
if (scontext.Eof)
|
||||
return StatusEof;
|
||||
|
||||
if (scontext.MustRead) {
|
||||
if (!scontext.FillFromStream(stream, may_wait)) {
|
||||
scontext.Eof = true;
|
||||
return StatusEof;
|
||||
}
|
||||
|
||||
scontext.MustRead = false;
|
||||
}
|
||||
|
||||
if (scontext.Size < (size_t)context.LengthIndicator) {
|
||||
scontext.MustRead = true;
|
||||
return StatusNeedData;
|
||||
}
|
||||
|
||||
*data = new char[context.LengthIndicator];
|
||||
*size = context.LengthIndicator;
|
||||
memcpy(data, scontext.Buffer, context.LengthIndicator);
|
||||
|
||||
scontext.DropData(context.LengthIndicator);
|
||||
context.LengthIndicator = -1;
|
||||
|
||||
return StatusNewItem;
|
||||
}
|
||||
|
||||
StreamReadContext& scontext = context.StreamContext;
|
||||
if (scontext.Eof)
|
||||
return StatusEof;
|
||||
|
||||
if (scontext.MustRead) {
|
||||
if (!scontext.FillFromStream(stream, may_wait)) {
|
||||
scontext.Eof = true;
|
||||
return StatusEof;
|
||||
}
|
||||
|
||||
scontext.MustRead = false;
|
||||
}
|
||||
|
||||
size_t NewlineLength = context.LengthIndicator ? 2 : 0;
|
||||
|
||||
if (scontext.Size < (size_t)context.LengthIndicator + NewlineLength) {
|
||||
scontext.MustRead = true;
|
||||
return StatusNeedData;
|
||||
}
|
||||
|
||||
*data = new char[context.LengthIndicator];
|
||||
*size = context.LengthIndicator;
|
||||
memcpy(*data, scontext.Buffer, context.LengthIndicator);
|
||||
|
||||
scontext.DropData(context.LengthIndicator + NewlineLength);
|
||||
context.LengthIndicator = -1;
|
||||
|
||||
return StatusNewItem;
|
||||
}
|
||||
|
||||
void HttpChunkedEncoding::WriteChunkToStream(const Stream::Ptr& stream, const char *data, size_t count)
|
||||
|
156
lib/remote/httpclientconnection.cpp
Normal file
156
lib/remote/httpclientconnection.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "remote/httpclientconnection.hpp"
|
||||
#include "remote/base64.hpp"
|
||||
#include "base/configtype.hpp"
|
||||
#include "base/objectlock.hpp"
|
||||
#include "base/utility.hpp"
|
||||
#include "base/logger.hpp"
|
||||
#include "base/exception.hpp"
|
||||
#include "base/convert.hpp"
|
||||
#include "base/tcpsocket.hpp"
|
||||
#include "base/tlsstream.hpp"
|
||||
#include "base/networkstream.hpp"
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
HttpClientConnection::HttpClientConnection(const String& host, const String& port, bool tls)
|
||||
: m_Host(host), m_Port(port), m_Tls(tls)
|
||||
{ }
|
||||
|
||||
void HttpClientConnection::Start(void)
|
||||
{
|
||||
/* Nothing to do here atm. */
|
||||
}
|
||||
|
||||
void HttpClientConnection::Reconnect(void)
|
||||
{
|
||||
if (m_Stream)
|
||||
m_Stream->Close();
|
||||
|
||||
m_Context.~StreamReadContext();
|
||||
new (&m_Context) StreamReadContext();
|
||||
|
||||
TcpSocket::Ptr socket = new TcpSocket();
|
||||
socket->Connect(m_Host, m_Port);
|
||||
|
||||
if (m_Tls)
|
||||
m_Stream = new TlsStream(socket, m_Host, RoleClient);
|
||||
else
|
||||
ASSERT(!"Non-TLS HTTP connections not supported.");
|
||||
//m_Stream = new NetworkStream(socket); -- does not currently work because the NetworkStream class doesn't support async I/O
|
||||
|
||||
m_Stream->RegisterDataHandler(boost::bind(&HttpClientConnection::DataAvailableHandler, this));
|
||||
if (m_Stream->IsDataAvailable())
|
||||
DataAvailableHandler();
|
||||
}
|
||||
|
||||
Stream::Ptr HttpClientConnection::GetStream(void) const
|
||||
{
|
||||
return m_Stream;
|
||||
}
|
||||
|
||||
String HttpClientConnection::GetHost(void) const
|
||||
{
|
||||
return m_Host;
|
||||
}
|
||||
|
||||
String HttpClientConnection::GetPort(void) const
|
||||
{
|
||||
return m_Port;
|
||||
}
|
||||
|
||||
bool HttpClientConnection::GetTls(void) const
|
||||
{
|
||||
return m_Tls;
|
||||
}
|
||||
|
||||
void HttpClientConnection::Disconnect(void)
|
||||
{
|
||||
Log(LogDebug, "HttpClientConnection", "Http client disconnected");
|
||||
|
||||
m_Stream->Shutdown();
|
||||
}
|
||||
|
||||
bool HttpClientConnection::ProcessMessage(void)
|
||||
{
|
||||
bool res;
|
||||
|
||||
if (m_Requests.empty())
|
||||
return false;
|
||||
|
||||
const std::pair<boost::shared_ptr<HttpRequest>, HttpCompletionCallback>& currentRequest = *m_Requests.begin();
|
||||
HttpRequest& request = *currentRequest.first.get();
|
||||
const HttpCompletionCallback& callback = currentRequest.second;
|
||||
|
||||
if (!m_CurrentResponse)
|
||||
m_CurrentResponse = boost::make_shared<HttpResponse>(m_Stream, request);
|
||||
|
||||
boost::shared_ptr<HttpResponse> currentResponse = m_CurrentResponse;
|
||||
HttpResponse& response = *currentResponse.get();
|
||||
|
||||
try {
|
||||
res = response.Parse(m_Context, false);
|
||||
} catch (const std::exception& ex) {
|
||||
callback(request, response);
|
||||
|
||||
m_Stream->Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (response.Complete) {
|
||||
callback(request, response);
|
||||
|
||||
m_Requests.pop_front();
|
||||
m_CurrentResponse.reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void HttpClientConnection::DataAvailableHandler(void)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_DataHandlerMutex);
|
||||
|
||||
try {
|
||||
while (ProcessMessage())
|
||||
; /* empty loop body */
|
||||
} catch (const std::exception& ex) {
|
||||
Log(LogWarning, "HttpClientConnection")
|
||||
<< "Error while reading Http request: " << DiagnosticInformation(ex);
|
||||
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
boost::shared_ptr<HttpRequest> HttpClientConnection::NewRequest(void)
|
||||
{
|
||||
Reconnect();
|
||||
return boost::make_shared<HttpRequest>(m_Stream);
|
||||
}
|
||||
|
||||
void HttpClientConnection::SubmitRequest(const boost::shared_ptr<HttpRequest>& request, const HttpCompletionCallback& callback)
|
||||
{
|
||||
m_Requests.push_back(std::make_pair(request, callback));
|
||||
request->Finish();
|
||||
}
|
78
lib/remote/httpclientconnection.hpp
Normal file
78
lib/remote/httpclientconnection.hpp
Normal file
@ -0,0 +1,78 @@
|
||||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef HTTPCLIENTCONNECTION_H
|
||||
#define HTTPCLIENTCONNECTION_H
|
||||
|
||||
#include "remote/httprequest.hpp"
|
||||
#include "remote/httpresponse.hpp"
|
||||
#include "base/stream.hpp"
|
||||
#include "base/timer.hpp"
|
||||
#include <deque>
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
/**
|
||||
* An HTTP client connection.
|
||||
*
|
||||
* @ingroup remote
|
||||
*/
|
||||
class I2_REMOTE_API HttpClientConnection : public Object
|
||||
{
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(HttpClientConnection);
|
||||
|
||||
HttpClientConnection(const String& host, const String& port, bool tls = true);
|
||||
|
||||
void Start(void);
|
||||
|
||||
Stream::Ptr GetStream(void) const;
|
||||
String GetHost(void) const;
|
||||
String GetPort(void) const;
|
||||
bool GetTls(void) const;
|
||||
|
||||
void Disconnect(void);
|
||||
|
||||
boost::shared_ptr<HttpRequest> NewRequest(void);
|
||||
|
||||
typedef boost::function<void(HttpRequest&, HttpResponse&)> HttpCompletionCallback;
|
||||
void SubmitRequest(const boost::shared_ptr<HttpRequest>& request, const HttpCompletionCallback& callback);
|
||||
|
||||
private:
|
||||
String m_Host;
|
||||
String m_Port;
|
||||
bool m_Tls;
|
||||
Stream::Ptr m_Stream;
|
||||
std::deque<std::pair<boost::shared_ptr<HttpRequest>, HttpCompletionCallback> > m_Requests;
|
||||
boost::shared_ptr<HttpResponse> m_CurrentResponse;
|
||||
boost::mutex m_DataHandlerMutex;
|
||||
|
||||
StreamReadContext m_Context;
|
||||
|
||||
void Reconnect(void);
|
||||
bool ProcessMessage(void);
|
||||
void DataAvailableHandler(void);
|
||||
|
||||
void ProcessMessageAsync(HttpRequest& request);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* HTTPCLIENTCONNECTION_H */
|
@ -19,27 +19,29 @@
|
||||
|
||||
#include "remote/httprequest.hpp"
|
||||
#include "base/logger.hpp"
|
||||
#include "base/application.hpp"
|
||||
#include "base/convert.hpp"
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
HttpRequest::HttpRequest(StreamReadContext& src)
|
||||
HttpRequest::HttpRequest(const Stream::Ptr& stream)
|
||||
: Complete(false),
|
||||
ProtocolVersion(HttpVersion10),
|
||||
ProtocolVersion(HttpVersion11),
|
||||
Headers(new Dictionary()),
|
||||
m_Context(src),
|
||||
m_ChunkContext(m_Context),
|
||||
m_Stream(stream),
|
||||
m_State(HttpRequestStart)
|
||||
{ }
|
||||
|
||||
bool HttpRequest::Parse(const Stream::Ptr& stream, StreamReadContext& src, bool may_wait)
|
||||
bool HttpRequest::Parse(StreamReadContext& src, bool may_wait)
|
||||
{
|
||||
if (m_State != HttpRequestBody) {
|
||||
String line;
|
||||
StreamReadStatus srs = stream->ReadLine(&line, src, may_wait);
|
||||
StreamReadStatus srs = m_Stream->ReadLine(&line, src, may_wait);
|
||||
|
||||
if (srs != StatusNewItem)
|
||||
return false;
|
||||
@ -95,9 +97,12 @@ bool HttpRequest::Parse(const Stream::Ptr& stream, StreamReadContext& src, bool
|
||||
}
|
||||
} else if (m_State == HttpRequestBody) {
|
||||
if (Headers->Get("transfer-encoding") == "chunked") {
|
||||
if (!m_ChunkContext)
|
||||
m_ChunkContext = boost::make_shared<ChunkReadContext>(src);
|
||||
|
||||
char *data;
|
||||
size_t size;
|
||||
StreamReadStatus srs = HttpChunkedEncoding::ReadChunkFromStream(stream, &data, &size, m_ChunkContext, false);
|
||||
StreamReadStatus srs = HttpChunkedEncoding::ReadChunkFromStream(m_Stream, &data, &size, *m_ChunkContext.get(), may_wait);
|
||||
|
||||
if (srs != StatusNewItem)
|
||||
return false;
|
||||
@ -114,27 +119,27 @@ bool HttpRequest::Parse(const Stream::Ptr& stream, StreamReadContext& src, bool
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (m_Context.Eof)
|
||||
if (src.Eof)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Unexpected EOF in HTTP body"));
|
||||
|
||||
if (m_Context.MustRead) {
|
||||
if (!m_Context.FillFromStream(stream, false)) {
|
||||
m_Context.Eof = true;
|
||||
if (src.MustRead) {
|
||||
if (!src.FillFromStream(m_Stream, false)) {
|
||||
src.Eof = true;
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Unexpected EOF in HTTP body"));
|
||||
}
|
||||
|
||||
m_Context.MustRead = false;
|
||||
src.MustRead = false;
|
||||
}
|
||||
|
||||
size_t length_indicator = Convert::ToLong(Headers->Get("content-length"));
|
||||
|
||||
if (m_Context.Size < length_indicator) {
|
||||
m_Context.MustRead = true;
|
||||
if (src.Size < length_indicator) {
|
||||
src.MustRead = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Body->Write(m_Context.Buffer, length_indicator);
|
||||
m_Context.DropData(length_indicator);
|
||||
m_Body->Write(src.Buffer, length_indicator);
|
||||
src.DropData(length_indicator);
|
||||
Complete = true;
|
||||
return true;
|
||||
}
|
||||
@ -151,3 +156,77 @@ size_t HttpRequest::ReadBody(char *data, size_t count)
|
||||
return m_Body->Read(data, count, true);
|
||||
}
|
||||
|
||||
void HttpRequest::AddHeader(const String& key, const String& value)
|
||||
{
|
||||
ASSERT(m_State == HttpRequestStart || m_State == HttpRequestHeaders);
|
||||
Headers->Set(key.ToLower(), value);
|
||||
}
|
||||
|
||||
void HttpRequest::FinishHeaders(void)
|
||||
{
|
||||
if (m_State == HttpRequestStart) {
|
||||
String rqline = RequestMethod + " " + RequestUrl->Format() + " HTTP/1." + (ProtocolVersion == HttpVersion10 ? "0" : "1") + "\n";
|
||||
m_Stream->Write(rqline.CStr(), rqline.GetLength());
|
||||
m_State = HttpRequestHeaders;
|
||||
}
|
||||
|
||||
if (m_State == HttpRequestHeaders) {
|
||||
AddHeader("User-Agent", "Icinga/" + Application::GetVersion());
|
||||
|
||||
if (ProtocolVersion == HttpVersion11)
|
||||
AddHeader("Transfer-Encoding", "chunked");
|
||||
|
||||
ObjectLock olock(Headers);
|
||||
BOOST_FOREACH(const Dictionary::Pair& kv, Headers)
|
||||
{
|
||||
String header = kv.first + ": " + kv.second + "\n";
|
||||
m_Stream->Write(header.CStr(), header.GetLength());
|
||||
}
|
||||
|
||||
m_Stream->Write("\n", 1);
|
||||
|
||||
m_State = HttpRequestBody;
|
||||
}
|
||||
}
|
||||
|
||||
void HttpRequest::WriteBody(const char *data, size_t count)
|
||||
{
|
||||
ASSERT(m_State == HttpRequestStart || m_State == HttpRequestHeaders || m_State == HttpRequestBody);
|
||||
|
||||
if (ProtocolVersion == HttpVersion10) {
|
||||
if (!m_Body)
|
||||
m_Body = new FIFO();
|
||||
|
||||
m_Body->Write(data, count);
|
||||
} else {
|
||||
FinishHeaders();
|
||||
|
||||
HttpChunkedEncoding::WriteChunkToStream(m_Stream, data, count);
|
||||
}
|
||||
}
|
||||
|
||||
void HttpRequest::Finish(void)
|
||||
{
|
||||
ASSERT(m_State != HttpRequestEnd);
|
||||
|
||||
if (ProtocolVersion == HttpVersion10) {
|
||||
if (m_Body)
|
||||
AddHeader("Content-Length", Convert::ToString(m_Body->GetAvailableBytes()));
|
||||
|
||||
FinishHeaders();
|
||||
|
||||
while (m_Body && m_Body->IsDataAvailable()) {
|
||||
char buffer[1024];
|
||||
size_t rc = m_Body->Read(buffer, sizeof(buffer), true);
|
||||
m_Stream->Write(buffer, rc);
|
||||
}
|
||||
} else {
|
||||
if (m_State == HttpRequestStart || m_State == HttpRequestHeaders)
|
||||
FinishHeaders();
|
||||
|
||||
WriteBody(NULL, 0);
|
||||
m_Stream->Write("\r\n", 2);
|
||||
}
|
||||
|
||||
m_State = HttpRequestEnd;
|
||||
}
|
||||
|
@ -40,7 +40,8 @@ enum HttpRequestState
|
||||
{
|
||||
HttpRequestStart,
|
||||
HttpRequestHeaders,
|
||||
HttpRequestBody
|
||||
HttpRequestBody,
|
||||
HttpRequestEnd
|
||||
};
|
||||
|
||||
/**
|
||||
@ -59,17 +60,22 @@ public:
|
||||
|
||||
Dictionary::Ptr Headers;
|
||||
|
||||
HttpRequest(StreamReadContext& ctx);
|
||||
|
||||
bool Parse(const Stream::Ptr& stream, StreamReadContext& src, bool may_wait);
|
||||
HttpRequest(const Stream::Ptr& stream);
|
||||
|
||||
bool Parse(StreamReadContext& src, bool may_wait);
|
||||
size_t ReadBody(char *data, size_t count);
|
||||
|
||||
void AddHeader(const String& key, const String& value);
|
||||
void WriteBody(const char *data, size_t count);
|
||||
void Finish(void);
|
||||
|
||||
private:
|
||||
StreamReadContext& m_Context;
|
||||
ChunkReadContext m_ChunkContext;
|
||||
Stream::Ptr m_Stream;
|
||||
boost::shared_ptr<ChunkReadContext> m_ChunkContext;
|
||||
HttpRequestState m_State;
|
||||
FIFO::Ptr m_Body;
|
||||
|
||||
void FinishHeaders(void);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -20,13 +20,16 @@
|
||||
#include "remote/httpresponse.hpp"
|
||||
#include "remote/httpchunkedencoding.hpp"
|
||||
#include "base/logger.hpp"
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include "base/application.hpp"
|
||||
#include "base/convert.hpp"
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
HttpResponse::HttpResponse(const Stream::Ptr& stream, const HttpRequest& request)
|
||||
: m_State(HttpResponseStart), m_Request(request), m_Stream(stream)
|
||||
: Complete(false), m_State(HttpResponseStart), m_Request(request), m_Stream(stream)
|
||||
{ }
|
||||
|
||||
void HttpResponse::SetStatus(int code, const String& message)
|
||||
@ -109,3 +112,123 @@ void HttpResponse::Finish(void)
|
||||
if (m_Request.ProtocolVersion == HttpVersion10 || m_Request.Headers->Get("connection") == "close")
|
||||
m_Stream->Shutdown();
|
||||
}
|
||||
|
||||
bool HttpResponse::Parse(StreamReadContext& src, bool may_wait)
|
||||
{
|
||||
if (m_State != HttpResponseBody) {
|
||||
String line;
|
||||
StreamReadStatus srs = m_Stream->ReadLine(&line, src, may_wait);
|
||||
|
||||
if (srs != StatusNewItem)
|
||||
return false;
|
||||
|
||||
if (m_State == HttpResponseStart) {
|
||||
/* ignore trailing new-lines */
|
||||
if (line == "")
|
||||
return true;
|
||||
|
||||
std::vector<String> tokens;
|
||||
boost::algorithm::split(tokens, line, boost::is_any_of(" "));
|
||||
Log(LogDebug, "HttpRequest")
|
||||
<< "line: " << line << ", tokens: " << tokens.size();
|
||||
if (tokens.size() < 3)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid HTTP request"));
|
||||
|
||||
if (tokens[0] == "HTTP/1.0")
|
||||
ProtocolVersion = HttpVersion10;
|
||||
else if (tokens[0] == "HTTP/1.1") {
|
||||
ProtocolVersion = HttpVersion11;
|
||||
} else
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Unsupported HTTP version"));
|
||||
|
||||
StatusCode = Convert::ToLong(tokens[1]);
|
||||
StatusMessage = tokens[2]; // TODO: Join tokens[2..end]
|
||||
|
||||
m_State = HttpResponseHeaders;
|
||||
} else if (m_State == HttpResponseHeaders) {
|
||||
if (!Headers)
|
||||
Headers = new Dictionary();
|
||||
|
||||
if (line == "") {
|
||||
m_State = HttpResponseBody;
|
||||
|
||||
/* we're done if the request doesn't contain a message body */
|
||||
if (!Headers->Contains("content-length") && !Headers->Contains("transfer-encoding"))
|
||||
Complete = true;
|
||||
else
|
||||
m_Body = new FIFO();
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
String::SizeType pos = line.FindFirstOf(":");
|
||||
if (pos == String::NPos)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid HTTP request"));
|
||||
String key = line.SubStr(0, pos).ToLower().Trim();
|
||||
|
||||
String value = line.SubStr(pos + 1).Trim();
|
||||
Headers->Set(key, value);
|
||||
}
|
||||
} else {
|
||||
VERIFY(!"Invalid HTTP request state.");
|
||||
}
|
||||
} else if (m_State == HttpResponseBody) {
|
||||
if (Headers->Get("transfer-encoding") == "chunked") {
|
||||
if (!m_ChunkContext)
|
||||
m_ChunkContext = boost::make_shared<ChunkReadContext>(src);
|
||||
|
||||
char *data;
|
||||
size_t size;
|
||||
StreamReadStatus srs = HttpChunkedEncoding::ReadChunkFromStream(m_Stream, &data, &size, *m_ChunkContext.get(), may_wait);
|
||||
|
||||
if (srs != StatusNewItem)
|
||||
return false;
|
||||
|
||||
Log(LogInformation, "HttpResponse")
|
||||
<< "Read " << size << " bytes";
|
||||
|
||||
m_Body->Write(data, size);
|
||||
|
||||
delete[] data;
|
||||
|
||||
if (size == 0) {
|
||||
Complete = true;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (src.Eof)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Unexpected EOF in HTTP body"));
|
||||
|
||||
if (src.MustRead) {
|
||||
if (!src.FillFromStream(m_Stream, false)) {
|
||||
src.Eof = true;
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Unexpected EOF in HTTP body"));
|
||||
}
|
||||
|
||||
src.MustRead = false;
|
||||
}
|
||||
|
||||
size_t length_indicator = Convert::ToLong(Headers->Get("content-length"));
|
||||
|
||||
if (src.Size < length_indicator) {
|
||||
src.MustRead = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Body->Write(src.Buffer, length_indicator);
|
||||
src.DropData(length_indicator);
|
||||
Complete = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t HttpResponse::ReadBody(char *data, size_t count)
|
||||
{
|
||||
if (!m_Body)
|
||||
return 0;
|
||||
else
|
||||
return m_Body->Read(data, count, true);
|
||||
}
|
@ -43,8 +43,19 @@ enum HttpResponseState
|
||||
struct I2_REMOTE_API HttpResponse
|
||||
{
|
||||
public:
|
||||
bool Complete;
|
||||
|
||||
HttpVersion ProtocolVersion;
|
||||
int StatusCode;
|
||||
String StatusMessage;
|
||||
|
||||
Dictionary::Ptr Headers;
|
||||
|
||||
HttpResponse(const Stream::Ptr& stream, const HttpRequest& request);
|
||||
|
||||
bool Parse(StreamReadContext& src, bool may_wait);
|
||||
size_t ReadBody(char *data, size_t count);
|
||||
|
||||
void SetStatus(int code, const String& message);
|
||||
void AddHeader(const String& key, const String& value);
|
||||
void WriteBody(const char *data, size_t count);
|
||||
@ -52,6 +63,7 @@ public:
|
||||
|
||||
private:
|
||||
HttpResponseState m_State;
|
||||
boost::shared_ptr<ChunkReadContext> m_ChunkContext;
|
||||
const HttpRequest& m_Request;
|
||||
Stream::Ptr m_Stream;
|
||||
FIFO::Ptr m_Body;
|
||||
|
@ -17,7 +17,7 @@
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "remote/httpconnection.hpp"
|
||||
#include "remote/httpserverconnection.hpp"
|
||||
#include "remote/httphandler.hpp"
|
||||
#include "remote/apilistener.hpp"
|
||||
#include "remote/apifunction.hpp"
|
||||
@ -33,47 +33,46 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
static boost::once_flag l_HttpConnectionOnceFlag = BOOST_ONCE_INIT;
|
||||
static Timer::Ptr l_HttpConnectionTimeoutTimer;
|
||||
static boost::once_flag l_HttpServerConnectionOnceFlag = BOOST_ONCE_INIT;
|
||||
static Timer::Ptr l_HttpServerConnectionTimeoutTimer;
|
||||
|
||||
HttpConnection::HttpConnection(const String& identity, bool authenticated, const TlsStream::Ptr& stream)
|
||||
: m_Stream(stream), m_Seen(Utility::GetTime()),
|
||||
m_CurrentRequest(m_Context), m_PendingRequests(0)
|
||||
HttpServerConnection::HttpServerConnection(const String& identity, bool authenticated, const TlsStream::Ptr& stream)
|
||||
: m_Stream(stream), m_CurrentRequest(stream), m_Seen(Utility::GetTime()), m_PendingRequests(0)
|
||||
{
|
||||
boost::call_once(l_HttpConnectionOnceFlag, &HttpConnection::StaticInitialize);
|
||||
boost::call_once(l_HttpServerConnectionOnceFlag, &HttpServerConnection::StaticInitialize);
|
||||
|
||||
if (authenticated)
|
||||
m_ApiUser = ApiUser::GetByClientCN(identity);
|
||||
}
|
||||
|
||||
void HttpConnection::StaticInitialize(void)
|
||||
void HttpServerConnection::StaticInitialize(void)
|
||||
{
|
||||
l_HttpConnectionTimeoutTimer = new Timer();
|
||||
l_HttpConnectionTimeoutTimer->OnTimerExpired.connect(boost::bind(&HttpConnection::TimeoutTimerHandler));
|
||||
l_HttpConnectionTimeoutTimer->SetInterval(15);
|
||||
l_HttpConnectionTimeoutTimer->Start();
|
||||
l_HttpServerConnectionTimeoutTimer = new Timer();
|
||||
l_HttpServerConnectionTimeoutTimer->OnTimerExpired.connect(boost::bind(&HttpServerConnection::TimeoutTimerHandler));
|
||||
l_HttpServerConnectionTimeoutTimer->SetInterval(15);
|
||||
l_HttpServerConnectionTimeoutTimer->Start();
|
||||
}
|
||||
|
||||
void HttpConnection::Start(void)
|
||||
void HttpServerConnection::Start(void)
|
||||
{
|
||||
m_Stream->RegisterDataHandler(boost::bind(&HttpConnection::DataAvailableHandler, this));
|
||||
m_Stream->RegisterDataHandler(boost::bind(&HttpServerConnection::DataAvailableHandler, this));
|
||||
if (m_Stream->IsDataAvailable())
|
||||
DataAvailableHandler();
|
||||
}
|
||||
|
||||
ApiUser::Ptr HttpConnection::GetApiUser(void) const
|
||||
ApiUser::Ptr HttpServerConnection::GetApiUser(void) const
|
||||
{
|
||||
return m_ApiUser;
|
||||
}
|
||||
|
||||
TlsStream::Ptr HttpConnection::GetStream(void) const
|
||||
TlsStream::Ptr HttpServerConnection::GetStream(void) const
|
||||
{
|
||||
return m_Stream;
|
||||
}
|
||||
|
||||
void HttpConnection::Disconnect(void)
|
||||
void HttpServerConnection::Disconnect(void)
|
||||
{
|
||||
Log(LogDebug, "HttpConnection", "Http client disconnected");
|
||||
Log(LogDebug, "HttpServerConnection", "Http client disconnected");
|
||||
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
listener->RemoveHttpClient(this);
|
||||
@ -81,12 +80,12 @@ void HttpConnection::Disconnect(void)
|
||||
m_Stream->Shutdown();
|
||||
}
|
||||
|
||||
bool HttpConnection::ProcessMessage(void)
|
||||
bool HttpServerConnection::ProcessMessage(void)
|
||||
{
|
||||
bool res;
|
||||
|
||||
try {
|
||||
res = m_CurrentRequest.Parse(m_Stream, m_Context, false);
|
||||
res = m_CurrentRequest.Parse(m_Context, false);
|
||||
} catch (const std::exception& ex) {
|
||||
HttpResponse response(m_Stream, m_CurrentRequest);
|
||||
response.SetStatus(400, "Bad request");
|
||||
@ -99,13 +98,13 @@ bool HttpConnection::ProcessMessage(void)
|
||||
}
|
||||
|
||||
if (m_CurrentRequest.Complete) {
|
||||
m_RequestQueue.Enqueue(boost::bind(&HttpConnection::ProcessMessageAsync, HttpConnection::Ptr(this), m_CurrentRequest));
|
||||
m_RequestQueue.Enqueue(boost::bind(&HttpServerConnection::ProcessMessageAsync, HttpServerConnection::Ptr(this), m_CurrentRequest));
|
||||
|
||||
m_Seen = Utility::GetTime();
|
||||
m_PendingRequests++;
|
||||
|
||||
m_CurrentRequest.~HttpRequest();
|
||||
new (&m_CurrentRequest) HttpRequest(m_Context);
|
||||
new (&m_CurrentRequest) HttpRequest(m_Stream);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -113,9 +112,9 @@ bool HttpConnection::ProcessMessage(void)
|
||||
return res;
|
||||
}
|
||||
|
||||
void HttpConnection::ProcessMessageAsync(HttpRequest& request)
|
||||
void HttpServerConnection::ProcessMessageAsync(HttpRequest& request)
|
||||
{
|
||||
Log(LogInformation, "HttpConnection", "Processing Http message");
|
||||
Log(LogInformation, "HttpServerConnection", "Processing Http message");
|
||||
|
||||
String auth_header = request.Headers->Get("authorization");
|
||||
|
||||
@ -169,7 +168,7 @@ void HttpConnection::ProcessMessageAsync(HttpRequest& request)
|
||||
m_PendingRequests--;
|
||||
}
|
||||
|
||||
void HttpConnection::DataAvailableHandler(void)
|
||||
void HttpServerConnection::DataAvailableHandler(void)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_DataHandlerMutex);
|
||||
|
||||
@ -177,27 +176,27 @@ void HttpConnection::DataAvailableHandler(void)
|
||||
while (ProcessMessage())
|
||||
; /* empty loop body */
|
||||
} catch (const std::exception& ex) {
|
||||
Log(LogWarning, "HttpConnection")
|
||||
Log(LogWarning, "HttpServerConnection")
|
||||
<< "Error while reading Http request: " << DiagnosticInformation(ex);
|
||||
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void HttpConnection::CheckLiveness(void)
|
||||
void HttpServerConnection::CheckLiveness(void)
|
||||
{
|
||||
if (m_Seen < Utility::GetTime() - 10 && m_PendingRequests == 0) {
|
||||
Log(LogInformation, "HttpConnection")
|
||||
Log(LogInformation, "HttpServerConnection")
|
||||
<< "No messages for Http connection have been received in the last 10 seconds.";
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void HttpConnection::TimeoutTimerHandler(void)
|
||||
void HttpServerConnection::TimeoutTimerHandler(void)
|
||||
{
|
||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||
|
||||
BOOST_FOREACH(const HttpConnection::Ptr& client, listener->GetHttpClients()) {
|
||||
BOOST_FOREACH(const HttpServerConnection::Ptr& client, listener->GetHttpClients()) {
|
||||
client->CheckLiveness();
|
||||
}
|
||||
}
|
@ -17,8 +17,8 @@
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef HTTPCONNECTION_H
|
||||
#define HTTPCONNECTION_H
|
||||
#ifndef HTTPSERVERCONNECTION_H
|
||||
#define HTTPSERVERCONNECTION_H
|
||||
|
||||
#include "remote/httprequest.hpp"
|
||||
#include "remote/apiuser.hpp"
|
||||
@ -34,12 +34,12 @@ namespace icinga
|
||||
*
|
||||
* @ingroup remote
|
||||
*/
|
||||
class I2_REMOTE_API HttpConnection : public Object
|
||||
class I2_REMOTE_API HttpServerConnection : public Object
|
||||
{
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(HttpConnection);
|
||||
DECLARE_PTR_TYPEDEFS(HttpServerConnection);
|
||||
|
||||
HttpConnection(const String& identity, bool authenticated, const TlsStream::Ptr& stream);
|
||||
HttpServerConnection(const String& identity, bool authenticated, const TlsStream::Ptr& stream);
|
||||
|
||||
void Start(void);
|
||||
|
||||
@ -72,4 +72,4 @@ private:
|
||||
|
||||
}
|
||||
|
||||
#endif /* HTTPCONNECTION_H */
|
||||
#endif /* HTTPSERVERCONNECTION_H */
|
6
third-party/execvpe/CMakeLists.txt
vendored
6
third-party/execvpe/CMakeLists.txt
vendored
@ -29,3 +29,9 @@ install(
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
install(
|
||||
TARGETS execvpe
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}/icinga-studio.app/Contents
|
||||
)
|
||||
endif()
|
||||
|
7
third-party/mmatch/CMakeLists.txt
vendored
7
third-party/mmatch/CMakeLists.txt
vendored
@ -28,3 +28,10 @@ install(
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
install(
|
||||
TARGETS mmatch
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}/icinga-studio.app/Contents
|
||||
)
|
||||
endif()
|
||||
|
6
third-party/socketpair/CMakeLists.txt
vendored
6
third-party/socketpair/CMakeLists.txt
vendored
@ -33,3 +33,9 @@ install(
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
install(
|
||||
TARGETS socketpair
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}/icinga-studio.app/Contents
|
||||
)
|
||||
endif()
|
||||
|
7
third-party/yajl/src/CMakeLists.txt
vendored
7
third-party/yajl/src/CMakeLists.txt
vendored
@ -60,3 +60,10 @@ INCLUDE_DIRECTORIES(${incDir}/..)
|
||||
INSTALL(TARGETS yajl
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2)
|
||||
|
||||
if(APPLE)
|
||||
install(
|
||||
TARGETS yajl
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}/icinga-studio.app/Contents
|
||||
)
|
||||
endif()
|
||||
|
Loading…
x
Reference in New Issue
Block a user