Merge pull request #6870 from birarda/console
Your Stack Manager is now a Server Console
1
.gitattributes
vendored
|
@ -25,3 +25,4 @@
|
|||
*.svg binary
|
||||
*.ttf binary
|
||||
*.wav binary
|
||||
*.rsrc binary
|
||||
|
|
6
.gitignore
vendored
|
@ -36,7 +36,7 @@ interface/external/*/*
|
|||
# Ignore interfaceCache for Linux users
|
||||
interface/interfaceCache/
|
||||
|
||||
# ignore audio-client externals
|
||||
# ignore audio-client externals
|
||||
libraries/audio-client/external/*/*
|
||||
!libraries/audio-client/external/*/readme.txt
|
||||
|
||||
|
@ -46,3 +46,7 @@ gvr-interface/libs/*
|
|||
# ignore files for various dev environments
|
||||
TAGS
|
||||
*.swp
|
||||
|
||||
# ignore node files for the console
|
||||
node_modules
|
||||
npm-debug.log
|
||||
|
|
|
@ -15,7 +15,7 @@ endif ()
|
|||
|
||||
if (POLICY CMP0043)
|
||||
cmake_policy(SET CMP0043 OLD)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (POLICY CMP0042)
|
||||
cmake_policy(SET CMP0042 OLD)
|
||||
|
@ -26,24 +26,32 @@ set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMakeTargets")
|
|||
|
||||
project(hifi)
|
||||
add_definitions(-DGLM_FORCE_RADIANS)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
|
||||
|
||||
if (WIN32)
|
||||
add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)
|
||||
# set path for Microsoft SDKs
|
||||
# if get build error about missing 'glu32' this path is likely wrong
|
||||
# Uncomment the line with 8.1 if running Windows 8.1
|
||||
|
||||
if (NOT WINDOW_SDK_PATH)
|
||||
set(DEBUG_DISCOVERED_SDK_PATH TRUE)
|
||||
endif()
|
||||
|
||||
# sets path for Microsoft SDKs
|
||||
# if you get build error about missing 'glu32' this path is likely wrong
|
||||
if (MSVC10)
|
||||
set(WINDOW_SDK_PATH "C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1 ")
|
||||
set(WINDOW_SDK_PATH "C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1 " CACHE PATH "Windows SDK PATH")
|
||||
elseif (MSVC12)
|
||||
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
set(WINDOW_SDK_FOLDER "x64")
|
||||
set(WINDOW_SDK_FOLDER "x64")
|
||||
else()
|
||||
set(WINDOW_SDK_FOLDER "x86")
|
||||
set(WINDOW_SDK_FOLDER "x86")
|
||||
endif()
|
||||
set(WINDOW_SDK_PATH "C:\\Program Files (x86)\\Windows Kits\\8.1\\Lib\\winv6.3\\um\\${WINDOW_SDK_FOLDER}")
|
||||
set(WINDOW_SDK_PATH "C:\\Program Files (x86)\\Windows Kits\\8.1\\Lib\\winv6.3\\um\\${WINDOW_SDK_FOLDER}" CACHE PATH "Windows SDK PATH")
|
||||
endif ()
|
||||
message (WINDOW_SDK_PATH= ${WINDOW_SDK_PATH})
|
||||
|
||||
if (DEBUG_DISCOVERED_SDK_PATH)
|
||||
message(STATUS "The discovered Windows SDK path is ${WINDOW_SDK_PATH}")
|
||||
endif ()
|
||||
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${WINDOW_SDK_PATH})
|
||||
# /wd4351 disables warning C4351: new behavior: elements of array will be default initialized
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /wd4351")
|
||||
|
@ -75,7 +83,7 @@ if ((NOT MSVC12) AND (NOT MSVC14))
|
|||
endif()
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
if (APPLE)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++0x")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --stdlib=libc++")
|
||||
|
@ -85,16 +93,16 @@ if (NOT ANDROID_LIB_DIR)
|
|||
set(ANDROID_LIB_DIR $ENV{ANDROID_LIB_DIR})
|
||||
endif ()
|
||||
|
||||
if (ANDROID)
|
||||
if (ANDROID)
|
||||
if (NOT ANDROID_QT_CMAKE_PREFIX_PATH)
|
||||
set(QT_CMAKE_PREFIX_PATH ${ANDROID_LIB_DIR}/Qt/5.4/android_armv7/lib/cmake)
|
||||
else ()
|
||||
set(QT_CMAKE_PREFIX_PATH ${ANDROID_QT_CMAKE_PREFIX_PATH})
|
||||
endif ()
|
||||
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
|
||||
|
||||
|
||||
if (ANDROID_LIB_DIR)
|
||||
list(APPEND CMAKE_FIND_ROOT_PATH ${ANDROID_LIB_DIR})
|
||||
endif ()
|
||||
|
@ -107,6 +115,8 @@ else ()
|
|||
endif ()
|
||||
endif ()
|
||||
|
||||
set(QT_DIR $ENV{QT_DIR})
|
||||
|
||||
if (WIN32)
|
||||
if (NOT EXISTS ${QT_CMAKE_PREFIX_PATH})
|
||||
message(FATAL_ERROR "Could not determine QT_CMAKE_PREFIX_PATH.")
|
||||
|
@ -119,34 +129,34 @@ get_filename_component(QT_DIR "${QT_CMAKE_PREFIX_PATH}/../../" ABSOLUTE)
|
|||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${QT_CMAKE_PREFIX_PATH})
|
||||
|
||||
if (APPLE)
|
||||
|
||||
|
||||
exec_program(sw_vers ARGS -productVersion OUTPUT_VARIABLE OSX_VERSION)
|
||||
string(REGEX MATCH "^[0-9]+\\.[0-9]+" OSX_VERSION ${OSX_VERSION})
|
||||
message(STATUS "Detected OS X version = ${OSX_VERSION}")
|
||||
|
||||
|
||||
set(OSX_SDK "${OSX_VERSION}" CACHE String "OS X SDK version to look for inside Xcode bundle or at OSX_SDK_PATH")
|
||||
|
||||
|
||||
# set our OS X deployment target
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.8)
|
||||
|
||||
|
||||
# find the SDK path for the desired SDK
|
||||
find_path(
|
||||
_OSX_DESIRED_SDK_PATH
|
||||
NAME MacOSX${OSX_SDK}.sdk
|
||||
_OSX_DESIRED_SDK_PATH
|
||||
NAME MacOSX${OSX_SDK}.sdk
|
||||
HINTS ${OSX_SDK_PATH}
|
||||
PATHS /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/
|
||||
/Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/
|
||||
)
|
||||
|
||||
|
||||
if (NOT _OSX_DESIRED_SDK_PATH)
|
||||
message(STATUS "Could not find OS X ${OSX_SDK} SDK. Will fall back to default. If you want a specific SDK, please pass OSX_SDK and optionally OSX_SDK_PATH to CMake.")
|
||||
else ()
|
||||
message(STATUS "Found OS X ${OSX_SDK} SDK at ${_OSX_DESIRED_SDK_PATH}/MacOSX${OSX_SDK}.sdk")
|
||||
|
||||
|
||||
# set that as the SDK to use
|
||||
set(CMAKE_OSX_SYSROOT ${_OSX_DESIRED_SDK_PATH}/MacOSX${OSX_SDK}.sdk)
|
||||
endif ()
|
||||
|
||||
|
||||
endif ()
|
||||
|
||||
# Hide automoc folders (for IDEs)
|
||||
|
@ -170,9 +180,9 @@ else ()
|
|||
set(UPPER_CMAKE_BUILD_TYPE DEBUG)
|
||||
endif ()
|
||||
|
||||
set(HIFI_CMAKE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
set(MACRO_DIR "${HIFI_CMAKE_DIR}/macros")
|
||||
set(EXTERNAL_PROJECT_DIR "${HIFI_CMAKE_DIR}/externals")
|
||||
set(HF_CMAKE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
set(MACRO_DIR "${HF_CMAKE_DIR}/macros")
|
||||
set(EXTERNAL_PROJECT_DIR "${HF_CMAKE_DIR}/externals")
|
||||
|
||||
file(GLOB HIFI_CUSTOM_MACROS "cmake/macros/*.cmake")
|
||||
foreach(CUSTOM_MACRO ${HIFI_CUSTOM_MACROS})
|
||||
|
@ -198,9 +208,11 @@ if (WIN32)
|
|||
endif ()
|
||||
|
||||
if (NOT DEFINED SERVER_ONLY)
|
||||
set(SERVER_ONLY 0)
|
||||
set(SERVER_ONLY 0)
|
||||
endif()
|
||||
|
||||
set_packaging_parameters()
|
||||
|
||||
# add subdirectories for all targets
|
||||
if (NOT ANDROID)
|
||||
add_subdirectory(assignment-client)
|
||||
|
@ -209,8 +221,7 @@ if (NOT ANDROID)
|
|||
set_target_properties(domain-server PROPERTIES FOLDER "Apps")
|
||||
add_subdirectory(ice-server)
|
||||
set_target_properties(ice-server PROPERTIES FOLDER "Apps")
|
||||
add_subdirectory(stack-manager)
|
||||
set_target_properties(stack-manager PROPERTIES FOLDER "Apps")
|
||||
add_subdirectory(server-console)
|
||||
if (NOT SERVER_ONLY)
|
||||
add_subdirectory(interface)
|
||||
set_target_properties(interface PROPERTIES FOLDER "Apps")
|
||||
|
@ -233,5 +244,4 @@ if (HIFI_MEMORY_DEBUGGING)
|
|||
endif (UNIX)
|
||||
endif ()
|
||||
|
||||
include_application_version()
|
||||
generate_installers()
|
||||
generate_installers()
|
||||
|
|
25
INSTALL.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
Follow the [build guide](BUILD.md) to figure out how to build High Fidelity for your platform.
|
||||
|
||||
During generation, CMake should produce an `install` target and a `package` target.
|
||||
|
||||
###Install
|
||||
|
||||
The `install` target will copy the High Fidelity targets and their dependencies to your `CMAKE_INSTALL_PREFIX`.
|
||||
|
||||
###Packaging
|
||||
|
||||
To produce an installer, run the `package` target.
|
||||
|
||||
####Windows
|
||||
|
||||
To produce an executable installer on Windows, the following are required:
|
||||
|
||||
- [Nullsoft Scriptable Install System](http://nsis.sourceforge.net/Download) - 3.0b3
|
||||
- [UAC Plug-in for Nullsoft](http://nsis.sourceforge.net/UAC_plug-in) - 0.2.4c
|
||||
- [nsProcess Plug-in for Nullsoft](http://nsis.sourceforge.net/NsProcess_plugin) - 1.6
|
||||
|
||||
Run the `package` target to create an executable installer using the Nullsoft Scriptable Install System.
|
||||
|
||||
####OS X
|
||||
|
||||
Run the `package` target to create an Apple Disk Image (.dmg).
|
25
LICENSE
|
@ -1,13 +1,12 @@
|
|||
Copyright 2014 High Fidelity, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Copyright (c) 2013-2016, High Fidelity, Inc.
|
||||
All rights reserved.
|
||||
licensing@highfidelity.io
|
||||
|
||||
Licensed under the Apache License version 2.0 (the "License");
|
||||
You may not use this software except in compliance with the License.
|
||||
You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This software includes third-party software.
|
||||
Please see each individual software license for additional details.
|
||||
|
||||
This software is distributed "as-is" without any warranties, conditions, or representations whether express or implied, including without limitation the implied warranties and conditions of merchantability, merchantable quality, fitness for a particular purpose, performance, durability, title, non-infringement, and those arising from statute or from custom or usage of trade or course of dealing.
|
||||
|
|
|
@ -3,12 +3,14 @@ set(TARGET_NAME assignment-client)
|
|||
setup_hifi_project(Core Gui Network Script Quick Widgets WebSockets)
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(
|
||||
audio avatars octree environment gpu model fbx entities
|
||||
link_hifi_libraries(
|
||||
audio avatars octree environment gpu model fbx entities
|
||||
networking animation recording shared script-engine embedded-webserver
|
||||
controllers physics
|
||||
)
|
||||
|
||||
include_application_version()
|
||||
package_libraries_for_deployment()
|
||||
consolidate_stack_components()
|
||||
if (WIN32)
|
||||
package_libraries_for_deployment()
|
||||
endif()
|
||||
|
||||
install_beside_console()
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <QCommandLineParser>
|
||||
#include <QThread>
|
||||
|
||||
#include <ApplicationVersion.h>
|
||||
#include <BuildInfo.h>
|
||||
#include <LogHandler.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <HifiConfigVariantMap.h>
|
||||
|
@ -22,6 +22,8 @@
|
|||
#include "AssignmentClient.h"
|
||||
#include "AssignmentClientMonitor.h"
|
||||
#include "AssignmentClientApp.h"
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QStandardPaths>
|
||||
|
||||
|
||||
AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
||||
|
@ -30,7 +32,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
// to work around the Qt constant wireless scanning, set the env for polling interval very high
|
||||
const QByteArray EXTREME_BEARER_POLL_TIMEOUT = QString::number(INT_MAX).toLocal8Bit();
|
||||
qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT);
|
||||
|
||||
|
||||
# ifndef WIN32
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
# endif
|
||||
|
@ -42,10 +44,10 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
ShutdownEventListener::getInstance();
|
||||
# endif
|
||||
|
||||
setOrganizationName("High Fidelity");
|
||||
setOrganizationName(BuildInfo::MODIFIED_ORGANIZATION);
|
||||
setOrganizationDomain("highfidelity.io");
|
||||
setApplicationName("assignment-client");
|
||||
setApplicationName(BUILD_VERSION);
|
||||
setApplicationVersion(BuildInfo::VERSION);
|
||||
|
||||
// use the verbose message handler in Logging
|
||||
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||
|
@ -63,7 +65,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
|
||||
const QCommandLineOption poolOption(ASSIGNMENT_POOL_OPTION, "set assignment pool", "pool-name");
|
||||
parser.addOption(poolOption);
|
||||
|
||||
|
||||
const QCommandLineOption portOption(ASSIGNMENT_CLIENT_LISTEN_PORT_OPTION,
|
||||
"UDP port for this assignment client (or monitor)", "port");
|
||||
parser.addOption(portOption);
|
||||
|
@ -92,6 +94,12 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
const QCommandLineOption monitorPortOption(ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION, "assignment-client monitor port", "port");
|
||||
parser.addOption(monitorPortOption);
|
||||
|
||||
const QCommandLineOption httpStatusPortOption(ASSIGNMENT_HTTP_STATUS_PORT, "http status server port", "http-status-port");
|
||||
parser.addOption(httpStatusPortOption);
|
||||
|
||||
const QCommandLineOption logDirectoryOption(ASSIGNMENT_LOG_DIRECTORY, "directory to store logs", "log-directory");
|
||||
parser.addOption(logDirectoryOption);
|
||||
|
||||
if (!parser.parse(QCoreApplication::arguments())) {
|
||||
qCritical() << parser.errorText() << endl;
|
||||
parser.showHelp();
|
||||
|
@ -130,6 +138,18 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
numForks = minForks;
|
||||
}
|
||||
|
||||
quint16 httpStatusPort { 0 };
|
||||
if (parser.isSet(httpStatusPortOption)) {
|
||||
httpStatusPort = parser.value(httpStatusPortOption).toUShort();
|
||||
}
|
||||
|
||||
QDir logDirectory { "." };
|
||||
if (parser.isSet(logDirectoryOption)) {
|
||||
logDirectory = parser.value(logDirectoryOption);
|
||||
} else {
|
||||
logDirectory = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||
}
|
||||
|
||||
Assignment::Type requestAssignmentType = Assignment::AllTypes;
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_TYPE_OVERRIDE_OPTION)) {
|
||||
requestAssignmentType = (Assignment::Type) argumentVariantMap.value(ASSIGNMENT_TYPE_OVERRIDE_OPTION).toInt();
|
||||
|
@ -168,11 +188,11 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||
assignmentServerPort = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toUInt();
|
||||
}
|
||||
|
||||
|
||||
if (parser.isSet(assignmentServerPortOption)) {
|
||||
assignmentServerPort = parser.value(assignmentServerPortOption).toInt();
|
||||
}
|
||||
|
||||
|
||||
// check for an overidden listen port
|
||||
quint16 listenPort = 0;
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_CLIENT_LISTEN_PORT_OPTION)) {
|
||||
|
@ -200,7 +220,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks,
|
||||
requestAssignmentType, assignmentPool,
|
||||
listenPort, walletUUID, assignmentServerHostname,
|
||||
assignmentServerPort);
|
||||
assignmentServerPort, httpStatusPort, logDirectory);
|
||||
monitor->setParent(this);
|
||||
connect(this, &QCoreApplication::aboutToQuit, monitor, &AssignmentClientMonitor::aboutToQuit);
|
||||
} else {
|
||||
|
|
|
@ -25,6 +25,8 @@ const QString ASSIGNMENT_NUM_FORKS_OPTION = "n";
|
|||
const QString ASSIGNMENT_MIN_FORKS_OPTION = "min";
|
||||
const QString ASSIGNMENT_MAX_FORKS_OPTION = "max";
|
||||
const QString ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION = "monitor-port";
|
||||
const QString ASSIGNMENT_HTTP_STATUS_PORT = "http-status-port";
|
||||
const QString ASSIGNMENT_LOG_DIRECTORY = "log-directory";
|
||||
|
||||
class AssignmentClientApp : public QCoreApplication {
|
||||
Q_OBJECT
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#include <memory>
|
||||
#include <signal.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include <AddressManager.h>
|
||||
#include <LogHandler.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
|
@ -20,6 +23,7 @@
|
|||
#include "AssignmentClientApp.h"
|
||||
#include "AssignmentClientChildData.h"
|
||||
#include "SharedUtil.h"
|
||||
#include <QtCore/QJsonDocument>
|
||||
|
||||
const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor";
|
||||
const int WAIT_FOR_CHILD_MSECS = 1000;
|
||||
|
@ -29,7 +33,9 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen
|
|||
const unsigned int maxAssignmentClientForks,
|
||||
Assignment::Type requestAssignmentType, QString assignmentPool,
|
||||
quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname,
|
||||
quint16 assignmentServerPort) :
|
||||
quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory) :
|
||||
_logDirectory(logDirectory),
|
||||
_httpManager(QHostAddress::LocalHost, httpStatusServerPort, "", this),
|
||||
_numAssignmentClientForks(numAssignmentClientForks),
|
||||
_minAssignmentClientForks(minAssignmentClientForks),
|
||||
_maxAssignmentClientForks(maxAssignmentClientForks),
|
||||
|
@ -38,6 +44,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen
|
|||
_walletUUID(walletUUID),
|
||||
_assignmentServerHostname(assignmentServerHostname),
|
||||
_assignmentServerPort(assignmentServerPort)
|
||||
|
||||
{
|
||||
qDebug() << "_requestAssignmentType =" << _requestAssignmentType;
|
||||
|
||||
|
@ -80,24 +87,21 @@ void AssignmentClientMonitor::simultaneousWaitOnChildren(int waitMsecs) {
|
|||
}
|
||||
}
|
||||
|
||||
void AssignmentClientMonitor::childProcessFinished() {
|
||||
QProcess* childProcess = qobject_cast<QProcess*>(sender());
|
||||
qint64 processID = _childProcesses.key(childProcess);
|
||||
|
||||
if (processID > 0) {
|
||||
qDebug() << "Child process" << processID << "has finished. Removing from internal map.";
|
||||
_childProcesses.remove(processID);
|
||||
void AssignmentClientMonitor::childProcessFinished(qint64 pid) {
|
||||
if (_childProcesses.remove(pid)) {
|
||||
qDebug() << "Child process" << pid << "has finished. Removed from internal map.";
|
||||
}
|
||||
}
|
||||
|
||||
void AssignmentClientMonitor::stopChildProcesses() {
|
||||
qDebug() << "Stopping child processes";
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
// ask child processes to terminate
|
||||
foreach(QProcess* childProcess, _childProcesses) {
|
||||
if (childProcess->processId() > 0) {
|
||||
qDebug() << "Attempting to terminate child process" << childProcess->processId();
|
||||
childProcess->terminate();
|
||||
for (auto& ac : _childProcesses) {
|
||||
if (ac.process->processId() > 0) {
|
||||
qDebug() << "Attempting to terminate child process" << ac.process->processId();
|
||||
ac.process->terminate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,10 +109,10 @@ void AssignmentClientMonitor::stopChildProcesses() {
|
|||
|
||||
if (_childProcesses.size() > 0) {
|
||||
// ask even more firmly
|
||||
foreach(QProcess* childProcess, _childProcesses) {
|
||||
if (childProcess->processId() > 0) {
|
||||
qDebug() << "Attempting to kill child process" << childProcess->processId();
|
||||
childProcess->kill();
|
||||
for (auto& ac : _childProcesses) {
|
||||
if (ac.process->processId() > 0) {
|
||||
qDebug() << "Attempting to kill child process" << ac.process->processId();
|
||||
ac.process->kill();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,18 +159,61 @@ void AssignmentClientMonitor::spawnChildClient() {
|
|||
_childArguments.append("--" + ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION);
|
||||
_childArguments.append(QString::number(DependencyManager::get<NodeList>()->getLocalSockAddr().getPort()));
|
||||
|
||||
// Setup log files
|
||||
const QString DATETIME_FORMAT = "yyyyMMdd.hh.mm.ss.zzz";
|
||||
|
||||
if (!_logDirectory.exists()) {
|
||||
qDebug() << "Log directory (" << _logDirectory.absolutePath() << ") does not exist, creating.";
|
||||
_logDirectory.mkpath(_logDirectory.absolutePath());
|
||||
}
|
||||
|
||||
auto nowString = QDateTime::currentDateTime().toString(DATETIME_FORMAT);
|
||||
auto stdoutFilenameTemp = QString("ac-%1-stdout.txt").arg(nowString);
|
||||
auto stderrFilenameTemp = QString("ac-%1-stderr.txt").arg(nowString);
|
||||
QString stdoutPathTemp = _logDirectory.absoluteFilePath(stdoutFilenameTemp);
|
||||
QString stderrPathTemp = _logDirectory.absoluteFilePath(stderrFilenameTemp);
|
||||
|
||||
// reset our output and error files
|
||||
assignmentClient->setStandardOutputFile(stdoutPathTemp);
|
||||
assignmentClient->setStandardErrorFile(stderrPathTemp);
|
||||
|
||||
// make sure that the output from the child process appears in our output
|
||||
assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
|
||||
assignmentClient->start(QCoreApplication::applicationFilePath(), _childArguments);
|
||||
|
||||
|
||||
// Update log path to use PID in filename
|
||||
auto stdoutFilename = QString("ac-%1_%2-stdout.txt").arg(nowString).arg(assignmentClient->processId());
|
||||
auto stderrFilename = QString("ac-%1_%2-stderr.txt").arg(nowString).arg(assignmentClient->processId());
|
||||
QString stdoutPath = _logDirectory.absoluteFilePath(stdoutFilename);
|
||||
QString stderrPath = _logDirectory.absoluteFilePath(stderrFilename);
|
||||
|
||||
qDebug() << "Renaming " << stdoutPathTemp << " to " << stdoutPath;
|
||||
if (!_logDirectory.rename(stdoutFilenameTemp, stdoutFilename)) {
|
||||
qDebug() << "Failed to rename " << stdoutFilenameTemp;
|
||||
stdoutPath = stdoutPathTemp;
|
||||
stdoutFilename = stdoutFilenameTemp;
|
||||
}
|
||||
|
||||
qDebug() << "Renaming " << stderrPathTemp << " to " << stderrPath;
|
||||
if (!QFile::rename(stderrPathTemp, stderrPath)) {
|
||||
qDebug() << "Failed to rename " << stderrFilenameTemp;
|
||||
stderrPath = stderrPathTemp;
|
||||
stderrFilename = stderrFilenameTemp;
|
||||
}
|
||||
|
||||
qDebug() << "Child stdout being written to: " << stdoutFilename;
|
||||
qDebug() << "Child stderr being written to: " << stderrFilename;
|
||||
|
||||
if (assignmentClient->processId() > 0) {
|
||||
auto pid = assignmentClient->processId();
|
||||
// make sure we hear that this process has finished when it does
|
||||
connect(assignmentClient, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(childProcessFinished()));
|
||||
|
||||
connect(assignmentClient, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||
this, [this, pid]() { childProcessFinished(pid); });
|
||||
|
||||
qDebug() << "Spawned a child client with PID" << assignmentClient->processId();
|
||||
_childProcesses.insert(assignmentClient->processId(), assignmentClient);
|
||||
}
|
||||
_childProcesses.insert(assignmentClient->processId(), { assignmentClient, stdoutPath, stderrPath });
|
||||
}
|
||||
}
|
||||
|
||||
void AssignmentClientMonitor::checkSpares() {
|
||||
|
@ -222,12 +269,12 @@ void AssignmentClientMonitor::handleChildStatusPacket(QSharedPointer<ReceivedMes
|
|||
// The parent only expects to be talking with prorams running on this same machine.
|
||||
if (senderSockAddr.getAddress() == QHostAddress::LocalHost ||
|
||||
senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
|
||||
|
||||
|
||||
if (!senderID.isNull()) {
|
||||
// We don't have this node yet - we should add it
|
||||
matchingNode = DependencyManager::get<LimitedNodeList>()->addOrUpdateNode
|
||||
(senderID, NodeType::Unassigned, senderSockAddr, senderSockAddr, false, false);
|
||||
|
||||
|
||||
auto childData = std::unique_ptr<AssignmentClientChildData>
|
||||
{ new AssignmentClientChildData(Assignment::Type::AllTypes) };
|
||||
matchingNode->setLinkedData(std::move(childData));
|
||||
|
@ -252,10 +299,39 @@ void AssignmentClientMonitor::handleChildStatusPacket(QSharedPointer<ReceivedMes
|
|||
// get child's assignment type out of the packet
|
||||
quint8 assignmentType;
|
||||
message->readPrimitive(&assignmentType);
|
||||
|
||||
childData->setChildType((Assignment::Type) assignmentType);
|
||||
|
||||
|
||||
childData->setChildType(Assignment::Type(assignmentType));
|
||||
|
||||
// note when this child talked
|
||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
}
|
||||
}
|
||||
|
||||
bool AssignmentClientMonitor::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) {
|
||||
if (url.path() == "/status") {
|
||||
QByteArray response;
|
||||
|
||||
QJsonObject status;
|
||||
QJsonObject servers;
|
||||
for (auto& ac : _childProcesses) {
|
||||
QJsonObject server;
|
||||
|
||||
server["pid"] = ac.process->processId();
|
||||
server["logStdout"] = ac.logStdoutPath;
|
||||
server["logStderr"] = ac.logStderrPath;
|
||||
|
||||
servers[QString::number(ac.process->processId())] = server;
|
||||
}
|
||||
|
||||
status["servers"] = servers;
|
||||
|
||||
QJsonDocument document { status };
|
||||
|
||||
connection->respond(HTTPConnection::StatusCode200, document.toJson());
|
||||
} else {
|
||||
connection->respond(HTTPConnection::StatusCode404);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -16,28 +16,39 @@
|
|||
#include <QtCore/qpointer.h>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QDir>
|
||||
|
||||
#include <Assignment.h>
|
||||
|
||||
#include "AssignmentClientChildData.h"
|
||||
#include <HTTPManager.h>
|
||||
#include <HTTPConnection.h>
|
||||
|
||||
extern const char* NUM_FORKS_PARAMETER;
|
||||
|
||||
class AssignmentClientMonitor : public QObject {
|
||||
struct ACProcess {
|
||||
QProcess* process; // looks like a dangling pointer, but is parented by the AssignmentClientMonitor
|
||||
QString logStdoutPath;
|
||||
QString logStderrPath;
|
||||
};
|
||||
|
||||
class AssignmentClientMonitor : public QObject, public HTTPRequestHandler {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks,
|
||||
const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType,
|
||||
QString assignmentPool, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname,
|
||||
quint16 assignmentServerPort);
|
||||
quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory);
|
||||
~AssignmentClientMonitor();
|
||||
|
||||
void stopChildProcesses();
|
||||
private slots:
|
||||
void checkSpares();
|
||||
void childProcessFinished();
|
||||
void childProcessFinished(qint64 pid);
|
||||
void handleChildStatusPacket(QSharedPointer<ReceivedMessage> message);
|
||||
|
||||
|
||||
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override;
|
||||
|
||||
public slots:
|
||||
void aboutToQuit();
|
||||
|
||||
|
@ -47,6 +58,10 @@ private:
|
|||
|
||||
QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children
|
||||
|
||||
QDir _logDirectory;
|
||||
|
||||
HTTPManager _httpManager;
|
||||
|
||||
const unsigned int _numAssignmentClientForks;
|
||||
const unsigned int _minAssignmentClientForks;
|
||||
const unsigned int _maxAssignmentClientForks;
|
||||
|
@ -57,7 +72,7 @@ private:
|
|||
QString _assignmentServerHostname;
|
||||
quint16 _assignmentServerPort;
|
||||
|
||||
QMap<qint64, QProcess*> _childProcesses;
|
||||
QMap<qint64, ACProcess> _childProcesses;
|
||||
};
|
||||
|
||||
#endif // hifi_AssignmentClientMonitor_h
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "NodeType.h"
|
||||
#include "SendAssetTask.h"
|
||||
#include "UploadAssetTask.h"
|
||||
#include <ServerPathUtils.h>
|
||||
|
||||
const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server";
|
||||
|
||||
|
@ -49,8 +50,27 @@ void AssetServer::run() {
|
|||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
|
||||
|
||||
_resourcesDirectory = QDir(QCoreApplication::applicationDirPath()).filePath("resources/assets");
|
||||
const QString RESOURCES_PATH = "assets";
|
||||
|
||||
_resourcesDirectory = QDir(ServerPathUtils::getDataDirectory()).filePath(RESOURCES_PATH);
|
||||
if (!_resourcesDirectory.exists()) {
|
||||
qDebug() << "Asset resources directory not found, searching for existing asset resources";
|
||||
QString oldDataDirectory = QCoreApplication::applicationDirPath();
|
||||
auto oldResourcesDirectory = QDir(oldDataDirectory).filePath(RESOURCES_PATH);
|
||||
|
||||
if (QDir(oldResourcesDirectory).exists()) {
|
||||
qDebug() << "Existing assets found in " << oldResourcesDirectory << ", copying to " << _resourcesDirectory;
|
||||
|
||||
|
||||
QDir resourcesParentDirectory = _resourcesDirectory.filePath("..");
|
||||
if (!resourcesParentDirectory.exists()) {
|
||||
qDebug() << "Creating data directory " << resourcesParentDirectory.absolutePath();
|
||||
resourcesParentDirectory.mkpath(".");
|
||||
}
|
||||
|
||||
QFile::copy(oldResourcesDirectory, _resourcesDirectory.absolutePath());
|
||||
}
|
||||
|
||||
qDebug() << "Creating resources directory";
|
||||
_resourcesDirectory.mkpath(".");
|
||||
}
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
|
||||
#include "OctreeQueryNode.h"
|
||||
#include "OctreeServerConsts.h"
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <ServerPathUtils.h>
|
||||
#include <QtCore/QDir>
|
||||
|
||||
int OctreeServer::_clientCount = 0;
|
||||
const int MOVING_AVERAGE_SAMPLE_COUNTS = 1000000;
|
||||
|
@ -280,10 +283,10 @@ OctreeServer::~OctreeServer() {
|
|||
void OctreeServer::initHTTPManager(int port) {
|
||||
// setup the embedded web server
|
||||
|
||||
QString documentRoot = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath());
|
||||
QString documentRoot = QString("%1/web").arg(ServerPathUtils::getDataDirectory());
|
||||
|
||||
// setup an httpManager with us as the request handler and the parent
|
||||
_httpManager = new HTTPManager(port, documentRoot, this, this);
|
||||
_httpManager = new HTTPManager(QHostAddress::AnyIPv4, port, documentRoot, this, this);
|
||||
}
|
||||
|
||||
bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) {
|
||||
|
@ -1031,6 +1034,7 @@ void OctreeServer::readConfiguration() {
|
|||
if (!readOptionString(QString("persistFilename"), settingsSectionObject, persistFilename)) {
|
||||
persistFilename = getMyDefaultPersistFilename();
|
||||
}
|
||||
|
||||
strcpy(_persistFilename, qPrintable(persistFilename));
|
||||
qDebug("persistFilename=%s", _persistFilename);
|
||||
|
||||
|
@ -1096,7 +1100,7 @@ void OctreeServer::run() {
|
|||
_tree->setIsServer(true);
|
||||
|
||||
qDebug() << "Waiting for connection to domain to request settings from domain-server.";
|
||||
|
||||
|
||||
// wait until we have the domain-server settings, otherwise we bail
|
||||
DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||
connect(&domainHandler, &DomainHandler::settingsReceived, this, &OctreeServer::domainSettingsRequestComplete);
|
||||
|
@ -1139,9 +1143,30 @@ void OctreeServer::domainSettingsRequestComplete() {
|
|||
|
||||
// if we want Persistence, set up the local file and persist thread
|
||||
if (_wantPersist) {
|
||||
// If persist filename does not exist, let's see if there is one beside the application binary
|
||||
// If there is, let's copy it over to our target persist directory
|
||||
QString oldResourcesDirectory = QCoreApplication::applicationDirPath();
|
||||
auto oldPersistPath = QDir(oldResourcesDirectory).absoluteFilePath(_persistFilename);
|
||||
auto persistPath = ServerPathUtils::getDataFilePath("entities/" + QString(_persistFilename));
|
||||
if (oldPersistPath != persistPath && !QFile::exists(persistPath)) {
|
||||
qDebug() << "Persist file does not exist, checking for existence of persist file next to application";
|
||||
if (QFile::exists(oldPersistPath)) {
|
||||
qDebug() << "Old persist file found, copying from " << oldPersistPath << " to " << persistPath;
|
||||
|
||||
QDir persistFileDirectory = QDir(persistPath).filePath("..");
|
||||
|
||||
if (!persistFileDirectory.exists()) {
|
||||
qDebug() << "Creating data directory " << persistFileDirectory.path();
|
||||
persistFileDirectory.mkpath(".");
|
||||
}
|
||||
QFile::copy(oldPersistPath, persistPath);
|
||||
} else {
|
||||
qDebug() << "No existing persist file found";
|
||||
}
|
||||
}
|
||||
|
||||
// now set up PersistThread
|
||||
_persistThread = new OctreePersistThread(_tree, _persistFilename, _persistInterval,
|
||||
_persistThread = new OctreePersistThread(_tree, persistPath, _persistInterval,
|
||||
_wantBackup, _settings, _debugTimestampNow, _persistAsFileType);
|
||||
_persistThread->initialize(true);
|
||||
}
|
||||
|
|
21
cmake/externals/faceshift/CMakeLists.txt
vendored
|
@ -21,10 +21,23 @@ ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
|||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE FILEPATH "Path to Faceshift include directory")
|
||||
|
||||
set(LIBRARY_DEBUG_PATH "lib/Debug")
|
||||
set(LIBRARY_RELEASE_PATH "lib/Release")
|
||||
|
||||
if (WIN32)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/Debug/faceshift.lib CACHE FILEPATH "Faceshift libraries")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/Release/faceshift.lib CACHE FILEPATH "Faceshift libraries")
|
||||
set(LIBRARY_PREFIX "")
|
||||
set(LIBRARY_EXT "lib")
|
||||
elseif (APPLE)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/Debug/libfaceshift.a CACHE FILEPATH "Faceshift libraries")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/Release/libfaceshift.a CACHE FILEPATH "Faceshift libraries")
|
||||
set(LIBRARY_EXT "a")
|
||||
set(LIBRARY_PREFIX "lib")
|
||||
|
||||
if (CMAKE_GENERATOR STREQUAL "Unix Makefiles")
|
||||
set(LIBRARY_DEBUG_PATH "build")
|
||||
set(LIBRARY_RELEASE_PATH "build")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG
|
||||
${INSTALL_DIR}/${LIBRARY_DEBUG_PATH}/${LIBRARY_PREFIX}faceshift.${LIBRARY_EXT} CACHE FILEPATH "Faceshift libraries")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE
|
||||
${INSTALL_DIR}/${LIBRARY_RELEASE_PATH}/${LIBRARY_PREFIX}faceshift.${LIBRARY_EXT} CACHE FILEPATH "Faceshift libraries")
|
||||
|
|
52
cmake/externals/quazip/CMakeLists.txt
vendored
|
@ -1,52 +0,0 @@
|
|||
set(EXTERNAL_NAME quazip)
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
cmake_policy(SET CMP0046 OLD)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
if (WIN32)
|
||||
# windows shell does not like backslashes expanded on the command line,
|
||||
# so convert all backslashes in the QT path to forward slashes
|
||||
string(REPLACE \\ / QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH})
|
||||
elseif ($ENV{QT_CMAKE_PREFIX_PATH})
|
||||
set(QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH})
|
||||
endif ()
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://s3-us-west-1.amazonaws.com/hifi-production/dependencies/quazip-0.6.2.zip
|
||||
URL_MD5 514851970f1a14d815bdc3ad6267af4d
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_PREFIX_PATH=${QT_CMAKE_PREFIX_PATH} -DCMAKE_INSTALL_NAME_DIR:PATH=<INSTALL_DIR>/lib -DZLIB_ROOT=${ZLIB_ROOT}
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
add_dependencies(quazip zlib)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES
|
||||
FOLDER "hidden/externals"
|
||||
INSTALL_NAME_DIR ${INSTALL_DIR}/lib
|
||||
BUILD_WITH_INSTALL_RPATH True)
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${INSTALL_DIR}/include CACHE PATH "List of QuaZip include directories")
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${${EXTERNAL_NAME_UPPER}_INCLUDE_DIR} CACHE PATH "List of QuaZip include directories")
|
||||
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${INSTALL_DIR}/lib CACHE FILEPATH "Location of QuaZip DLL")
|
||||
|
||||
if (APPLE)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libquazip.1.0.0.dylib CACHE FILEPATH "Location of QuaZip release library")
|
||||
elseif (WIN32)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/quazip.lib CACHE FILEPATH "Location of QuaZip release library")
|
||||
else ()
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libquazip.so CACHE FILEPATH "Location of QuaZip release library")
|
||||
endif ()
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(${EXTERNAL_NAME_UPPER})
|
||||
|
||||
# Force selected libraries into the cache
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY ${${EXTERNAL_NAME_UPPER}_LIBRARY} CACHE FILEPATH "Location of QuaZip libraries")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Location of QuaZip libraries")
|
1634
cmake/installer/install-folder.rsrc
Normal file
BIN
cmake/installer/installer-header.bmp
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
cmake/installer/installer.ico
Normal file
After Width: | Height: | Size: 153 KiB |
BIN
cmake/installer/uninstaller-header.bmp
Normal file
After Width: | Height: | Size: 100 KiB |
|
@ -1,28 +0,0 @@
|
|||
macro(CONSOLIDATE_STACK_COMPONENTS)
|
||||
|
||||
if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE)
|
||||
if (WIN32)
|
||||
# Copy all the output for this target into the common deployment location
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory $<TARGET_FILE_DIR:${TARGET_NAME}> ${CMAKE_BINARY_DIR}/full-stack-deployment
|
||||
)
|
||||
|
||||
# Copy icon files for interface and stack manager
|
||||
if (TARGET_NAME STREQUAL "interface" OR TARGET_NAME STREQUAL "stack-manager")
|
||||
if (TARGET_NAME STREQUAL "interface")
|
||||
set (ICON_FILE_PATH "${PROJECT_SOURCE_DIR}/icon/interface.ico")
|
||||
set (ICON_DESTINATION_NAME "interface.ico")
|
||||
elseif (TARGET_NAME STREQUAL "stack-manager")
|
||||
set (ICON_FILE_PATH "${PROJECT_SOURCE_DIR}/assets/icon.ico")
|
||||
set (ICON_DESTINATION_NAME "stack-manager.ico")
|
||||
endif ()
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy ${ICON_FILE_PATH} ${CMAKE_BINARY_DIR}/full-stack-deployment/${ICON_DESTINATION_NAME}
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
endmacro()
|
16
cmake/macros/FixPathForNSIS.cmake
Normal file
|
@ -0,0 +1,16 @@
|
|||
#
|
||||
# FixPathForNSIS.cmake
|
||||
#
|
||||
# Created by Sam Gateau on 1/14/16.
|
||||
# Copyright 2016 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(fix_path_for_nsis INITIAL_PATH RESULTING_PATH)
|
||||
# replace forward slash with backslash
|
||||
string(REPLACE "/" "\\\\" _BACKSLASHED_PATH ${INITIAL_PATH})
|
||||
# set the resulting path variable
|
||||
set(${RESULTING_PATH} ${_BACKSLASHED_PATH})
|
||||
endmacro()
|
58
cmake/macros/FixupInterface.cmake
Normal file
|
@ -0,0 +1,58 @@
|
|||
#
|
||||
# FixupInterface.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2016 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on January 6th, 2016
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(fixup_interface)
|
||||
if (APPLE)
|
||||
|
||||
string(REPLACE " " "\\ " ESCAPED_BUNDLE_NAME ${INTERFACE_BUNDLE_NAME})
|
||||
string(REPLACE " " "\\ " ESCAPED_INSTALL_PATH ${INTERFACE_INSTALL_DIR})
|
||||
set(_INTERFACE_INSTALL_PATH "${ESCAPED_INSTALL_PATH}/${ESCAPED_BUNDLE_NAME}.app")
|
||||
|
||||
# install QtWebProcess from Qt to the application bundle
|
||||
# since it is missed by macdeployqt
|
||||
# https://bugreports.qt.io/browse/QTBUG-35211
|
||||
set(LIBEXEC_PATH "${_INTERFACE_INSTALL_PATH}/Contents/libexec")
|
||||
install(
|
||||
PROGRAMS "${QT_DIR}/libexec/QtWebProcess"
|
||||
DESTINATION ${LIBEXEC_PATH}
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
|
||||
set(QTWEBPROCESS_PATH "\${CMAKE_INSTALL_PREFIX}/${LIBEXEC_PATH}")
|
||||
|
||||
# we also need a qt.conf in the directory of QtWebProcess
|
||||
install(CODE "
|
||||
file(WRITE ${QTWEBPROCESS_PATH}/qt.conf
|
||||
\"[Paths]\nPlugins = ../PlugIns\nImports = ../Resources/qml\nQml2Imports = ../Resources/qml\"
|
||||
)"
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
|
||||
find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS "${QT_DIR}/bin" NO_DEFAULT_PATH)
|
||||
|
||||
if (NOT MACDEPLOYQT_COMMAND AND (PRODUCTION_BUILD OR PR_BUILD))
|
||||
message(FATAL_ERROR "Could not find macdeployqt at ${QT_DIR}/bin.\
|
||||
It is required to produce an relocatable interface application.\
|
||||
Check that the environment variable QT_DIR points to your Qt installation.\
|
||||
")
|
||||
endif ()
|
||||
|
||||
install(CODE "
|
||||
execute_process(COMMAND ${MACDEPLOYQT_COMMAND}\
|
||||
\${CMAKE_INSTALL_PREFIX}/${_INTERFACE_INSTALL_PATH}/\
|
||||
-verbose=2 -qmldir=${CMAKE_SOURCE_DIR}/interface/resources/qml/\
|
||||
-executable=\${CMAKE_INSTALL_PREFIX}/${_INTERFACE_INSTALL_PATH}/Contents/libexec/QtWebProcess\
|
||||
)"
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
|
||||
endif ()
|
||||
endmacro()
|
|
@ -1,30 +1,78 @@
|
|||
#
|
||||
# GenerateInstallers.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Created by Leonardo Murillo on 12/16/2015.
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(GENERATE_INSTALLERS)
|
||||
if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE AND WIN32)
|
||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/full-stack-deployment")
|
||||
find_program(MAKENSIS_COMMAND makensis PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS])
|
||||
if (NOT MAKENSIS_COMMAND)
|
||||
message(FATAL_ERROR "The Nullsoft Scriptable Install Systems is required for generating packaged installers on Windows (http://nsis.sourceforge.net/)")
|
||||
endif ()
|
||||
add_custom_target(
|
||||
build-package ALL
|
||||
DEPENDS interface assignment-client domain-server stack-manager
|
||||
COMMAND set INSTALLER_SOURCE_DIR=${CMAKE_BINARY_DIR}/full-stack-deployment
|
||||
COMMAND set INSTALLER_NAME=${CMAKE_BINARY_DIR}/${INSTALLER_NAME}
|
||||
COMMAND set INSTALLER_SCRIPTS_DIR=${CMAKE_SOURCE_DIR}/examples
|
||||
COMMAND set INSTALLER_COMPANY=${INSTALLER_COMPANY}
|
||||
COMMAND set INSTALLER_DIRECTORY=${INSTALLER_DIRECTORY}
|
||||
COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi"
|
||||
)
|
||||
endif ()
|
||||
endmacro()
|
||||
#
|
||||
# GenerateInstallers.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Created by Leonardo Murillo on 12/16/2015.
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(GENERATE_INSTALLERS)
|
||||
include(CPackComponent)
|
||||
|
||||
set(CPACK_MODULE_PATH ${CPACK_MODULE_PATH} "${HF_CMAKE_DIR}/templates")
|
||||
|
||||
set(_DISPLAY_NAME ${BUILD_ORGANIZATION})
|
||||
|
||||
set(CPACK_PACKAGE_NAME ${_DISPLAY_NAME})
|
||||
set(CPACK_PACKAGE_VENDOR "High Fidelity")
|
||||
set(CPACK_PACKAGE_VERSION ${BUILD_VERSION})
|
||||
set(CPACK_PACKAGE_FILE_NAME "HighFidelity-Alpha-${BUILD_VERSION}")
|
||||
set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME})
|
||||
set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME})
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME})
|
||||
|
||||
if (WIN32)
|
||||
set(CPACK_NSIS_MUI_ICON "${HF_CMAKE_DIR}/installer/installer.ico")
|
||||
|
||||
# install and reference the Add/Remove icon
|
||||
set(ADD_REMOVE_ICON_NAME "installer.ico")
|
||||
set(ADD_REMOVE_ICON_BAD_PATH "${HF_CMAKE_DIR}/installer/${ADD_REMOVE_ICON_NAME}")
|
||||
fix_path_for_nsis(${ADD_REMOVE_ICON_BAD_PATH} ADD_REMOVE_ICON_PATH)
|
||||
set(CPACK_NSIS_INSTALLED_ICON_NAME ${ADD_REMOVE_ICON_NAME})
|
||||
|
||||
# use macro to put backslashes in header image path since nsis requires them
|
||||
set(_INSTALLER_HEADER_BAD_PATH "${HF_CMAKE_DIR}/installer/installer-header.bmp")
|
||||
set(INSTALLER_HEADER_IMAGE "")
|
||||
fix_path_for_nsis(${_INSTALLER_HEADER_BAD_PATH} INSTALLER_HEADER_IMAGE)
|
||||
|
||||
set(_UNINSTALLER_HEADER_BAD_PATH "${HF_CMAKE_DIR}/installer/uninstaller-header.bmp")
|
||||
set(UNINSTALLER_HEADER_IMAGE "")
|
||||
fix_path_for_nsis(${_UNINSTALLER_HEADER_BAD_PATH} UNINSTALLER_HEADER_IMAGE)
|
||||
elseif (APPLE)
|
||||
# produce a drag and drop DMG on OS X
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "/")
|
||||
set(CPACK_PACKAGING_INSTALL_PREFIX /)
|
||||
set(CPACK_OSX_PACKAGE_VERSION ${CMAKE_OSX_DEPLOYMENT_TARGET})
|
||||
|
||||
# make sure a High Fidelity directory exists, in case this hits prior to other installs
|
||||
install(CODE "file(MAKE_DIRECTORY \"\${CMAKE_INSTALL_PREFIX}/${DMG_SUBFOLDER_NAME}\")")
|
||||
|
||||
# add the resource file to the Icon file inside the folder
|
||||
install(CODE
|
||||
"execute_process(COMMAND Rez -append ${DMG_SUBFOLDER_ICON} -o \${CMAKE_INSTALL_PREFIX}/${ESCAPED_DMG_SUBFOLDER_NAME}/Icon\\r)"
|
||||
)
|
||||
|
||||
# modify the folder to use that custom icon
|
||||
install(CODE "execute_process(COMMAND SetFile -a C \${CMAKE_INSTALL_PREFIX}/${ESCAPED_DMG_SUBFOLDER_NAME})")
|
||||
|
||||
# hide the special Icon? file
|
||||
install(CODE "execute_process(COMMAND SetFile -a V \${CMAKE_INSTALL_PREFIX}/${ESCAPED_DMG_SUBFOLDER_NAME}/Icon\\r)")
|
||||
endif ()
|
||||
|
||||
# configure a cpack properties file for custom variables in template
|
||||
set(CPACK_CONFIGURED_PROP_FILE "${CMAKE_CURRENT_BINARY_DIR}/CPackCustomProperties.cmake")
|
||||
configure_file("${HF_CMAKE_DIR}/templates/CPackProperties.cmake.in" ${CPACK_CONFIGURED_PROP_FILE})
|
||||
set(CPACK_PROPERTIES_FILE ${CPACK_CONFIGURED_PROP_FILE})
|
||||
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
|
||||
|
||||
cpack_add_component(${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Client")
|
||||
cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Server")
|
||||
|
||||
include(CPack)
|
||||
endmacro()
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
#
|
||||
# IncludeApplicationVersion.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Created by Leonardo Murillo on 07/14/2015.
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(INCLUDE_APPLICATION_VERSION)
|
||||
#
|
||||
# We are relying on Jenkins defined environment variables to determine the origin of this build
|
||||
# and will only package if this is a PR or Release build
|
||||
if (DEFINED ENV{JOB_ID})
|
||||
set(DEPLOY_PACKAGE 1)
|
||||
set(BUILD_SEQ $ENV{JOB_ID})
|
||||
set(INSTALLER_COMPANY "High Fidelity")
|
||||
set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}")
|
||||
set(INSTALLER_NAME "interface-win64-${BUILD_SEQ}.exe")
|
||||
elseif (DEFINED ENV{ghprbPullId})
|
||||
set(DEPLOY_PACKAGE 1)
|
||||
set(BUILD_SEQ "PR-$ENV{ghprbPullId}")
|
||||
set(INSTALLER_COMPANY "High Fidelity - PR")
|
||||
set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}\\${BUILD_SEQ}")
|
||||
set(INSTALLER_NAME "pr-interface-win64-${BUILD_SEQ}.exe")
|
||||
else ()
|
||||
set(BUILD_SEQ "dev")
|
||||
set(INSTALLER_COMPANY "High Fidelity - Dev")
|
||||
set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}")
|
||||
set(INSTALLER_NAME "dev-interface-win64.exe")
|
||||
endif ()
|
||||
configure_file("${MACRO_DIR}/ApplicationVersion.h.in" "${PROJECT_BINARY_DIR}/includes/ApplicationVersion.h")
|
||||
include_directories("${PROJECT_BINARY_DIR}/includes")
|
||||
endmacro(INCLUDE_APPLICATION_VERSION)
|
72
cmake/macros/InstallBesideConsole.cmake
Normal file
|
@ -0,0 +1,72 @@
|
|||
#
|
||||
# InstallBesideConsole.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2016 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on January 5th, 2016
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(install_beside_console)
|
||||
if (WIN32 OR APPLE)
|
||||
# install this component beside the installed server-console executable
|
||||
if (APPLE)
|
||||
set(CONSOLE_APP_CONTENTS "${CONSOLE_INSTALL_APP_PATH}/Contents")
|
||||
set(COMPONENT_DESTINATION "${CONSOLE_APP_CONTENTS}/MacOS/Components.app/Contents/MacOS")
|
||||
else ()
|
||||
set(COMPONENT_DESTINATION ${CONSOLE_INSTALL_DIR})
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
install(
|
||||
TARGETS ${TARGET_NAME}
|
||||
RUNTIME DESTINATION ${COMPONENT_DESTINATION}
|
||||
COMPONENT ${SERVER_COMPONENT}
|
||||
)
|
||||
else ()
|
||||
# setup install of executable and things copied by fixup/windeployqt
|
||||
install(
|
||||
FILES "$<TARGET_FILE_DIR:${TARGET_NAME}>/"
|
||||
DESTINATION ${COMPONENT_DESTINATION}
|
||||
COMPONENT ${SERVER_COMPONENT}
|
||||
)
|
||||
|
||||
# on windows for PR and production builds, sign the executable
|
||||
set(EXECUTABLE_COMPONENT ${SERVER_COMPONENT})
|
||||
optional_win_executable_signing()
|
||||
endif ()
|
||||
|
||||
if (TARGET_NAME STREQUAL domain-server)
|
||||
if (APPLE)
|
||||
set(RESOURCES_DESTINATION ${COMPONENT_DESTINATION})
|
||||
else ()
|
||||
set(RESOURCES_DESTINATION ${CONSOLE_INSTALL_DIR})
|
||||
endif ()
|
||||
|
||||
# install the resources folder for the domain-server where its executable will be
|
||||
install(
|
||||
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/resources
|
||||
DESTINATION ${RESOURCES_DESTINATION}
|
||||
USE_SOURCE_PERMISSIONS
|
||||
COMPONENT ${SERVER_COMPONENT}
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
# during the install phase, call fixup to drop the shared libraries for these components in the right place
|
||||
set(EXECUTABLE_NEEDING_FIXUP "\${CMAKE_INSTALL_PREFIX}/${COMPONENT_DESTINATION}/${TARGET_NAME}")
|
||||
install(CODE "
|
||||
include(BundleUtilities)
|
||||
fixup_bundle(\"${EXECUTABLE_NEEDING_FIXUP}\" \"\" \"${FIXUP_LIBS}\")
|
||||
" COMPONENT ${SERVER_COMPONENT})
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# set variables used by manual ssleay library copy
|
||||
set(TARGET_INSTALL_DIR ${COMPONENT_DESTINATION})
|
||||
set(TARGET_INSTALL_COMPONENT ${SERVER_COMPONENT})
|
||||
manually_install_ssl_eay()
|
||||
|
||||
endmacro()
|
28
cmake/macros/ManuallyInstallSSLEay.cmake
Normal file
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
# ManuallyInstallSSLEay.cmake
|
||||
#
|
||||
# Created by Stephen Birarda on 1/15/16.
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(manually_install_ssl_eay)
|
||||
|
||||
# on windows we have had issues with targets missing ssleay library
|
||||
# not convinced we actually need it (I assume it would show up in the dependency tree)
|
||||
# but to be safe we install it manually beside the current target
|
||||
if (WIN32)
|
||||
# we need to find SSL_EAY_LIBRARY_* so we can install it beside this target
|
||||
# so we have to call find_package(OpenSSL) here even though this target may not specifically need it
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
install(
|
||||
FILES "${OPENSSL_DLL_PATH}/ssleay32.dll"
|
||||
DESTINATION ${TARGET_INSTALL_DIR}
|
||||
COMPONENT ${TARGET_INSTALL_COMPONENT}
|
||||
)
|
||||
endif()
|
||||
|
||||
endmacro()
|
34
cmake/macros/OptionalWinExecutableSigning.cmake
Normal file
|
@ -0,0 +1,34 @@
|
|||
#
|
||||
# OptionalWinExecutableSigning.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2016 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on January 12, 2016
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(optional_win_executable_signing)
|
||||
if (WIN32 AND PRODUCTION_BUILD)
|
||||
if (DEFINED ENV{HF_PFX_FILE})
|
||||
if (DEFINED ENV{HF_PFX_PASSPHRASE})
|
||||
message(STATUS "Executable for ${TARGET_NAME} will be signed with SignTool.")
|
||||
|
||||
if (NOT EXECUTABLE_PATH)
|
||||
set(EXECUTABLE_PATH "$<TARGET_FILE:${TARGET_NAME}>")
|
||||
endif ()
|
||||
|
||||
# setup a post build command to sign the executable
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND ${SIGNTOOL_EXECUTABLE} sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 ${EXECUTABLE_PATH}
|
||||
)
|
||||
else ()
|
||||
message(FATAL_ERROR "HF_PFX_PASSPHRASE must be set for executables to be signed.")
|
||||
endif ()
|
||||
else ()
|
||||
message(WARNING "Creating a production build but not code signing since HF_PFX_FILE is not set.")
|
||||
endif ()
|
||||
endif ()
|
||||
endmacro()
|
|
@ -1,25 +1,24 @@
|
|||
#
|
||||
#
|
||||
# PackageLibrariesForDeployment.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on February 17, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
#
|
||||
|
||||
macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT)
|
||||
|
||||
if (WIN32)
|
||||
configure_file(
|
||||
${HIFI_CMAKE_DIR}/templates/FixupBundlePostBuild.cmake.in
|
||||
${HF_CMAKE_DIR}/templates/FixupBundlePostBuild.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/FixupBundlePostBuild.cmake
|
||||
@ONLY
|
||||
)
|
||||
|
||||
|
||||
set(PLUGIN_PATH "plugins")
|
||||
|
||||
|
||||
# add a post-build command to copy DLLs beside the executable
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME}
|
||||
|
@ -29,31 +28,18 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT)
|
|||
-DBUNDLE_PLUGIN_DIR=$<TARGET_FILE_DIR:${TARGET_NAME}>/${PLUGIN_PATH}
|
||||
-P ${CMAKE_CURRENT_BINARY_DIR}/FixupBundlePostBuild.cmake
|
||||
)
|
||||
|
||||
|
||||
find_program(WINDEPLOYQT_COMMAND windeployqt PATHS ${QT_DIR}/bin NO_DEFAULT_PATH)
|
||||
|
||||
|
||||
if (NOT WINDEPLOYQT_COMMAND)
|
||||
message(FATAL_ERROR "Could not find windeployqt at ${QT_DIR}/bin. windeployqt is required.")
|
||||
endif ()
|
||||
|
||||
|
||||
# add a post-build command to call windeployqt to copy Qt plugins
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME}
|
||||
POST_BUILD
|
||||
COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} ${EXTRA_DEPLOY_OPTIONS} $<$<OR:$<CONFIG:Release>,$<CONFIG:MinSizeRel>,$<CONFIG:RelWithDebInfo>>:--release> $<TARGET_FILE:${TARGET_NAME}>"
|
||||
)
|
||||
elseif (DEFINED BUILD_BUNDLE AND BUILD_BUNDLE AND APPLE)
|
||||
find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS ${QT_DIR}/bin NO_DEFAULT_PATH)
|
||||
|
||||
if (NOT MACDEPLOYQT_COMMAND)
|
||||
message(FATAL_ERROR "Could not find macdeployqt at ${QT_DIR}/bin. macdeployqt is required.")
|
||||
endif ()
|
||||
|
||||
# add a post-build command to call macdeployqt to copy Qt plugins
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME}
|
||||
POST_BUILD
|
||||
COMMAND ${MACDEPLOYQT_COMMAND} ${CMAKE_CURRENT_BINARY_DIR}/\${CONFIGURATION}/${TARGET_NAME}.app -verbose 0
|
||||
)
|
||||
endif ()
|
||||
endmacro()
|
||||
|
|
109
cmake/macros/SetPackagingParameters.cmake
Normal file
|
@ -0,0 +1,109 @@
|
|||
#
|
||||
# SetPackagingParameters.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Created by Leonardo Murillo on 07/14/2015.
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
# This macro checks some Jenkins defined environment variables to determine the origin of this build
|
||||
# and decides how targets should be packaged.
|
||||
|
||||
macro(SET_PACKAGING_PARAMETERS)
|
||||
set(PR_BUILD 0)
|
||||
set(PRODUCTION_BUILD 0)
|
||||
set(DEV_BUILD 0)
|
||||
|
||||
set(RELEASE_TYPE $ENV{RELEASE_TYPE})
|
||||
set(RELEASE_NUMBER $ENV{RELEASE_NUMBER})
|
||||
|
||||
if (RELEASE_TYPE STREQUAL "PRODUCTION")
|
||||
set(DEPLOY_PACKAGE TRUE)
|
||||
set(PRODUCTION_BUILD 1)
|
||||
set(BUILD_VERSION ${RELEASE_NUMBER})
|
||||
set(BUILD_ORGANIZATION "High Fidelity")
|
||||
set(HIGH_FIDELITY_PROTOCOL "hifi")
|
||||
set(INTERFACE_BUNDLE_NAME "High Fidelity")
|
||||
set(INTERFACE_ICON_PREFIX "interface")
|
||||
elseif (RELEASE_TYPE STREQUAL "PR")
|
||||
set(DEPLOY_PACKAGE TRUE)
|
||||
set(PR_BUILD 1)
|
||||
set(BUILD_VERSION "PR${RELEASE_NUMBER}")
|
||||
set(BUILD_ORGANIZATION "High Fidelity - ${BUILD_VERSION}")
|
||||
set(INTERFACE_BUNDLE_NAME "High Fidelity")
|
||||
set(INTERFACE_ICON_PREFIX "interface-beta")
|
||||
else ()
|
||||
set(DEV_BUILD 1)
|
||||
set(BUILD_VERSION "dev")
|
||||
set(BUILD_ORGANIZATION "High Fidelity - ${BUILD_VERSION}")
|
||||
set(INTERFACE_BUNDLE_NAME "Interface")
|
||||
set(INTERFACE_ICON_PREFIX "interface-beta")
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
set(DMG_SUBFOLDER_NAME "${BUILD_ORGANIZATION}")
|
||||
|
||||
set(ESCAPED_DMG_SUBFOLDER_NAME "")
|
||||
string(REPLACE " " "\\ " ESCAPED_DMG_SUBFOLDER_NAME ${DMG_SUBFOLDER_NAME})
|
||||
|
||||
set(DMG_SUBFOLDER_ICON "${HF_CMAKE_DIR}/installer/install-folder.rsrc")
|
||||
|
||||
set(CONSOLE_INSTALL_DIR ${DMG_SUBFOLDER_NAME})
|
||||
set(INTERFACE_INSTALL_DIR ${DMG_SUBFOLDER_NAME})
|
||||
else ()
|
||||
set(CONSOLE_INSTALL_DIR ".")
|
||||
set(INTERFACE_INSTALL_DIR ".")
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
set(INTERFACE_EXEC_PREFIX "interface")
|
||||
set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.ico")
|
||||
|
||||
set(CONSOLE_EXEC_NAME "server-console.exe")
|
||||
|
||||
set(DS_EXEC_NAME "domain-server.exe")
|
||||
set(AC_EXEC_NAME "assignment-client.exe")
|
||||
|
||||
# start menu shortcuts
|
||||
set(INTERFACE_SM_SHORTCUT_NAME "High Fidelity")
|
||||
set(CONSOLE_SM_SHORTCUT_NAME "Server Console")
|
||||
|
||||
# check if we need to find signtool
|
||||
if (PRODUCTION_BUILD OR PR_BUILD)
|
||||
find_program(SIGNTOOL_EXECUTABLE signtool PATHS "C:/Program Files (x86)/Windows Kits/8.1" PATH_SUFFIXES "bin/x64")
|
||||
|
||||
if (NOT SIGNTOOL_EXECUTABLE)
|
||||
message(FATAL_ERROR "Code signing of executables was requested but signtool.exe could not be found.")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
set(GENERATED_UNINSTALLER_EXEC_NAME "Uninstall.exe")
|
||||
set(REGISTRY_HKLM_INSTALL_ROOT "Software")
|
||||
set(POST_INSTALL_OPTIONS_REG_GROUP "PostInstallOptions")
|
||||
set(CLIENT_DESKTOP_SHORTCUT_REG_KEY "ClientDesktopShortcut")
|
||||
set(CONSOLE_DESKTOP_SHORTCUT_REG_KEY "ConsoleDesktopShortcut")
|
||||
set(CONSOLE_STARTUP_REG_KEY "ConsoleStartupShortcut")
|
||||
set(LAUNCH_NOW_REG_KEY "LaunchAfterInstall")
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
|
||||
set(CONSOLE_EXEC_NAME "Server Console.app")
|
||||
set(CONSOLE_INSTALL_APP_PATH "${CONSOLE_INSTALL_DIR}/${CONSOLE_EXEC_NAME}")
|
||||
|
||||
set(INTERFACE_INSTALL_APP_PATH "${CONSOLE_INSTALL_DIR}/${INTERFACE_BUNDLE_NAME}.app")
|
||||
set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.icns")
|
||||
endif()
|
||||
|
||||
# setup component categories for installer
|
||||
set(DDE_COMPONENT dde)
|
||||
set(CLIENT_COMPONENT client)
|
||||
set(SERVER_COMPONENT server)
|
||||
|
||||
# create a header file our targets can use to find out the application version
|
||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/includes")
|
||||
configure_file("${HF_CMAKE_DIR}/templates/BuildInfo.h.in" "${CMAKE_BINARY_DIR}/includes/BuildInfo.h")
|
||||
|
||||
endmacro(SET_PACKAGING_PARAMETERS)
|
|
@ -12,12 +12,12 @@ macro(SETUP_HIFI_PLUGIN)
|
|||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Plugins")
|
||||
|
||||
if (APPLE)
|
||||
set(PLUGIN_PATH "interface.app/Contents/MacOS/plugins")
|
||||
set(PLUGIN_PATH "${INTERFACE_BUNDLE_NAME}.app/Contents/PlugIns")
|
||||
else()
|
||||
set(PLUGIN_PATH "plugins")
|
||||
endif()
|
||||
|
||||
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_GENERATOR STREQUAL "Unix Makefiles")
|
||||
set(PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/${PLUGIN_PATH}/")
|
||||
else()
|
||||
set(PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/$<CONFIGURATION>/${PLUGIN_PATH}/")
|
||||
|
@ -35,5 +35,4 @@ macro(SETUP_HIFI_PLUGIN)
|
|||
"$<TARGET_FILE:${TARGET_NAME}>"
|
||||
${PLUGIN_FULL_PATH}
|
||||
)
|
||||
|
||||
endmacro()
|
||||
|
|
|
@ -1,36 +1,35 @@
|
|||
#
|
||||
#
|
||||
# SetupHifiProject.cmake
|
||||
#
|
||||
#
|
||||
# Copyright 2013 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
#
|
||||
|
||||
macro(SETUP_HIFI_PROJECT)
|
||||
project(${TARGET_NAME})
|
||||
|
||||
|
||||
# grab the implemenation and header files
|
||||
file(GLOB TARGET_SRCS src/*)
|
||||
|
||||
|
||||
file(GLOB SRC_SUBDIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/src/*)
|
||||
|
||||
|
||||
foreach(DIR ${SRC_SUBDIRS})
|
||||
if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/${DIR}")
|
||||
file(GLOB DIR_CONTENTS "src/${DIR}/*")
|
||||
set(TARGET_SRCS ${TARGET_SRCS} "${DIR_CONTENTS}")
|
||||
endif ()
|
||||
endforeach()
|
||||
|
||||
if (DEFINED BUILD_BUNDLE AND BUILD_BUNDLE AND APPLE)
|
||||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${TARGET_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC})
|
||||
else ()
|
||||
add_executable(${TARGET_NAME} ${TARGET_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC})
|
||||
endif()
|
||||
|
||||
add_executable(${TARGET_NAME} ${TARGET_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC})
|
||||
|
||||
# include the generated application version header
|
||||
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes")
|
||||
|
||||
set(${TARGET_NAME}_DEPENDENCY_QT_MODULES ${ARGN})
|
||||
list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core)
|
||||
|
||||
|
||||
# find these Qt modules and link them to our own target
|
||||
find_package(Qt5 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED)
|
||||
|
||||
|
@ -44,7 +43,7 @@ macro(SETUP_HIFI_PROJECT)
|
|||
foreach(QT_MODULE ${${TARGET_NAME}_DEPENDENCY_QT_MODULES})
|
||||
target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE})
|
||||
endforeach()
|
||||
|
||||
|
||||
target_glm()
|
||||
|
||||
|
||||
endmacro()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# CopyDirectoryBesideTarget.cmake
|
||||
# CopyDirectoryBesideTarget.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Created by Stephen Birarda on 04/30/15.
|
||||
|
@ -10,22 +10,22 @@
|
|||
#
|
||||
|
||||
macro(SYMLINK_OR_COPY_DIRECTORY_BESIDE_TARGET _SHOULD_SYMLINK _DIRECTORY _DESTINATION)
|
||||
|
||||
|
||||
# remove the current directory
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E remove_directory $<TARGET_FILE_DIR:${TARGET_NAME}>/${_DESTINATION}
|
||||
)
|
||||
|
||||
|
||||
if (${_SHOULD_SYMLINK})
|
||||
|
||||
|
||||
# first create the destination
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E make_directory
|
||||
$<TARGET_FILE_DIR:${TARGET_NAME}>/${_DESTINATION}
|
||||
)
|
||||
|
||||
|
||||
# the caller wants a symlink, so just add a command to symlink all contents of _DIRECTORY
|
||||
# in the destination - we can't simply create a symlink for _DESTINATION
|
||||
# because the remove_directory call above would delete the original files
|
||||
|
@ -35,20 +35,20 @@ macro(SYMLINK_OR_COPY_DIRECTORY_BESIDE_TARGET _SHOULD_SYMLINK _DIRECTORY _DESTIN
|
|||
foreach(_ITEM ${_DIR_ITEMS})
|
||||
# get the filename for this item
|
||||
get_filename_component(_ITEM_FILENAME ${_ITEM} NAME)
|
||||
|
||||
|
||||
# add the command to symlink this item
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E create_symlink
|
||||
${_ITEM}
|
||||
$<TARGET_FILE_DIR:${TARGET_NAME}>/${_DESTINATION}/${_ITEM_FILENAME}
|
||||
)
|
||||
endforeach()
|
||||
)
|
||||
endforeach()
|
||||
else ()
|
||||
# copy the directory
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${_DIRECTORY}
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${_DIRECTORY}
|
||||
$<TARGET_FILE_DIR:${TARGET_NAME}>/${_DESTINATION}
|
||||
)
|
||||
endif ()
|
||||
|
|
|
@ -1,20 +1,28 @@
|
|||
#
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Bradley Austin Davis on 2015/10/10
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
#
|
||||
macro(TARGET_NSIGHT)
|
||||
if (WIN32)
|
||||
if (USE_NSIGHT)
|
||||
if (WIN32 AND USE_NSIGHT)
|
||||
|
||||
# grab the global CHECKED_FOR_NSIGHT_ONCE property
|
||||
get_property(NSIGHT_CHECKED GLOBAL PROPERTY CHECKED_FOR_NSIGHT_ONCE)
|
||||
|
||||
if (NOT NSIGHT_CHECKED)
|
||||
# try to find the Nsight package and add it to the build if we find it
|
||||
find_package(NSIGHT)
|
||||
if (NSIGHT_FOUND)
|
||||
include_directories(${NSIGHT_INCLUDE_DIRS})
|
||||
add_definitions(-DNSIGHT_FOUND)
|
||||
target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}")
|
||||
endif ()
|
||||
endif()
|
||||
endif (WIN32)
|
||||
endmacro()
|
||||
|
||||
# set the global CHECKED_FOR_NSIGHT_ONCE property so that we only debug that we couldn't find it once
|
||||
set_property(GLOBAL PROPERTY CHECKED_FOR_NSIGHT_ONCE TRUE)
|
||||
endif ()
|
||||
|
||||
if (NSIGHT_FOUND)
|
||||
include_directories(${NSIGHT_INCLUDE_DIRS})
|
||||
add_definitions(-DNSIGHT_FOUND)
|
||||
target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}")
|
||||
endif ()
|
||||
endif ()
|
||||
endmacro()
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Leonardo Murillo on 2015/11/20
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_QUAZIP)
|
||||
add_dependency_external_projects(quazip)
|
||||
find_package(QuaZip REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${QUAZIP_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${QUAZIP_LIBRARIES})
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${QUAZIP_DLL_PATH})
|
||||
endif ()
|
||||
endmacro()
|
|
@ -1,14 +1,14 @@
|
|||
#
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Bradley Austin Davis on 2015/10/10
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
#
|
||||
macro(TARGET_SIXENSE)
|
||||
add_dependency_external_projects(sixense)
|
||||
find_package(Sixense REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES})
|
||||
add_definitions(-DHAVE_SIXENSE)
|
||||
endmacro()
|
||||
endmacro()
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
# OPENSSL_INCLUDE_DIR - the OpenSSL include directory
|
||||
# OPENSSL_LIBRARIES - The libraries needed to use OpenSSL
|
||||
# OPENSSL_VERSION - This is set to $major.$minor.$revision$path (eg. 0.9.8s)
|
||||
#
|
||||
#
|
||||
# Modified on 7/16/2014 by Stephen Birarda
|
||||
# This is an adapted version of the FindOpenSSL.cmake module distributed with Cmake 2.8.12.2
|
||||
# The original license for that file is displayed below.
|
||||
#
|
||||
#
|
||||
#=============================================================================
|
||||
# Copyright 2006-2009 Kitware, Inc.
|
||||
# Copyright 2006 Alexander Neundorf <neundorf@kde.org>
|
||||
|
@ -50,18 +50,18 @@ if (WIN32)
|
|||
)
|
||||
set(_OPENSSL_ROOT_PATHS "${_programfiles}/OpenSSL" "${_programfiles}/OpenSSL-Win32" "C:/OpenSSL/" "C:/OpenSSL-Win32/")
|
||||
endif()
|
||||
|
||||
|
||||
unset(_programfiles)
|
||||
set(_OPENSSL_ROOT_HINTS_AND_PATHS HINTS ${_OPENSSL_ROOT_HINTS} PATHS ${_OPENSSL_ROOT_PATHS})
|
||||
|
||||
|
||||
else ()
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("openssl")
|
||||
|
||||
|
||||
set(_OPENSSL_ROOT_HINTS_AND_PATHS ${OPENSSL_SEARCH_DIRS})
|
||||
endif ()
|
||||
|
||||
find_path(OPENSSL_INCLUDE_DIR NAMES openssl/ssl.h HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_INCLUDEDIR}
|
||||
find_path(OPENSSL_INCLUDE_DIR NAMES openssl/ssl.h HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_INCLUDEDIR}
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
|
@ -81,15 +81,15 @@ if (WIN32 AND NOT CYGWIN)
|
|||
# We are using the libraries located in the VC subdir instead of the parent directory eventhough :
|
||||
# libeay32MD.lib is identical to ../libeay32.lib, and
|
||||
# ssleay32MD.lib is identical to ../ssleay32.lib
|
||||
find_library(LIB_EAY_DEBUG NAMES libeay32MDd libeay32d
|
||||
find_library(LIB_EAY_DEBUG NAMES libeay32MDd libeay32d
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC"
|
||||
)
|
||||
|
||||
find_library(LIB_EAY_RELEASE NAMES libeay32MD libeay32
|
||||
find_library(LIB_EAY_RELEASE NAMES libeay32MD libeay32
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC"
|
||||
)
|
||||
|
||||
find_library(SSL_EAY_DEBUG NAMES ssleay32MDd ssleay32d
|
||||
find_library(SSL_EAY_DEBUG NAMES ssleay32MDd ssleay32d
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC"
|
||||
)
|
||||
|
||||
|
@ -109,22 +109,22 @@ if (WIN32 AND NOT CYGWIN)
|
|||
set(OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY})
|
||||
|
||||
find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" ${_OPENSSL_ROOT_HINTS_AND_PATHS})
|
||||
|
||||
|
||||
elseif (MINGW)
|
||||
# same player, for MinGW
|
||||
set(LIB_EAY_NAMES libeay32)
|
||||
set(SSL_EAY_NAMES ssleay32)
|
||||
|
||||
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
list(APPEND LIB_EAY_NAMES crypto)
|
||||
list(APPEND SSL_EAY_NAMES ssl)
|
||||
endif ()
|
||||
|
||||
|
||||
find_library(LIB_EAY NAMES ${LIB_EAY_NAMES}
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "lib/MinGW"
|
||||
)
|
||||
|
||||
find_library(SSL_EAY NAMES ${SSL_EAY_NAMES}
|
||||
find_library(SSL_EAY NAMES ${SSL_EAY_NAMES}
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "lib/MinGW"
|
||||
)
|
||||
|
||||
|
@ -147,7 +147,7 @@ else()
|
|||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
find_library(OPENSSL_CRYPTO_LIBRARY NAMES crypto HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_LIBDIR}
|
||||
find_library(OPENSSL_CRYPTO_LIBRARY NAMES crypto HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_LIBDIR}
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
|
@ -196,7 +196,7 @@ if (OPENSSL_INCLUDE_DIR)
|
|||
if(OPENSSL_INCLUDE_DIR AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h")
|
||||
file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str
|
||||
REGEX "^#[ ]?define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])+.*")
|
||||
|
||||
|
||||
# The version number is encoded as 0xMNNFFPPS: major minor fix patch status
|
||||
# The status gives if this is a developer or prerelease and is ignored here.
|
||||
# Major, minor, and fix directly translate into the version numbers shown in
|
||||
|
@ -252,15 +252,6 @@ endif ()
|
|||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${OPENSSL_DLL_PATH})
|
||||
#
|
||||
# For some reason fixup misses the following DLL and only copies libeay32. There's gotta be a better way to handle this
|
||||
# but for now resorting to the following interm solution
|
||||
if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE)
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy ${OPENSSL_DLL_PATH}/ssleay32.dll ${CMAKE_BINARY_DIR}/full-stack-deployment/
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES OPENSSL_SEARCH_DIRS)
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
#
|
||||
# FindQuaZip.h
|
||||
# StackManagerQt/cmake/modules
|
||||
#
|
||||
# Created by Mohammed Nafees.
|
||||
# Copyright (c) 2014 High Fidelity. All rights reserved.
|
||||
#
|
||||
|
||||
# QUAZIP_FOUND - QuaZip library was found
|
||||
# QUAZIP_INCLUDE_DIR - Path to QuaZip include dir
|
||||
# QUAZIP_INCLUDE_DIRS - Path to QuaZip and zlib include dir (combined from QUAZIP_INCLUDE_DIR + ZLIB_INCLUDE_DIR)
|
||||
# QUAZIP_LIBRARIES - List of QuaZip libraries
|
||||
# QUAZIP_ZLIB_INCLUDE_DIR - The include dir of zlib headers
|
||||
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("quazip")
|
||||
|
||||
if (WIN32)
|
||||
find_path(QUAZIP_INCLUDE_DIRS quazip.h PATH_SUFFIXES include/quazip HINTS ${QUAZIP_SEARCH_DIRS})
|
||||
elseif (APPLE)
|
||||
find_path(QUAZIP_INCLUDE_DIRS quazip.h PATH_SUFFIXES include/quazip HINTS ${QUAZIP_SEARCH_DIRS})
|
||||
else ()
|
||||
find_path(QUAZIP_INCLUDE_DIRS quazip.h PATH_SUFFIXES quazip HINTS ${QUAZIP_SEARCH_DIRS})
|
||||
endif ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(QUAZIP DEFAULT_MSG QUAZIP_INCLUDE_DIRS)
|
||||
|
||||
mark_as_advanced(QUAZIP_INCLUDE_DIRS QUAZIP_SEARCH_DIRS)
|
|
@ -1,12 +1,15 @@
|
|||
//
|
||||
// ApplicationVersion.h.in
|
||||
// BuildInfo.h.in
|
||||
// cmake/macros
|
||||
//
|
||||
// Created by Leonardo Murillo on 8/13/15.
|
||||
// Created by Stephen Birarda on 1/14/16.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
const QString BUILD_VERSION = "@BUILD_SEQ@";
|
||||
namespace BuildInfo {
|
||||
const QString MODIFIED_ORGANIZATION = "@BUILD_ORGANIZATION@";
|
||||
const QString VERSION = "@BUILD_VERSION@";
|
||||
}
|
35
cmake/templates/CPackProperties.cmake.in
Normal file
|
@ -0,0 +1,35 @@
|
|||
#
|
||||
# CPackProperties.cmake.in
|
||||
# cmake/templates
|
||||
#
|
||||
# Copyright 2016 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on January 11, 2016
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
set(INTERFACE_SHORTCUT_NAME "@INTERFACE_SM_SHORTCUT_NAME@")
|
||||
set(INTERFACE_WIN_EXEC_NAME "@INTERFACE_EXEC_PREFIX@.exe")
|
||||
set(CONSOLE_SHORTCUT_NAME "@CONSOLE_SM_SHORTCUT_NAME@")
|
||||
set(CONSOLE_WIN_EXEC_NAME "@CONSOLE_EXEC_NAME@")
|
||||
set(DS_EXEC_NAME "@DS_EXEC_NAME@")
|
||||
set(AC_EXEC_NAME "@AC_EXEC_NAME@")
|
||||
set(HIGH_FIDELITY_PROTOCOL "@HIGH_FIDELITY_PROTOCOL@")
|
||||
set(PRODUCTION_BUILD "@PRODUCTION_BUILD@")
|
||||
set(PR_BUILD "@PR_BUILD@")
|
||||
set(BUILD_ORGANIZATION "@BUILD_ORGANIZATION@")
|
||||
set(POST_INSTALL_OPTIONS_PATH "@POST_INSTALL_OPTIONS_PATH@")
|
||||
set(CLIENT_COMPONENT_NAME "@CLIENT_COMPONENT@")
|
||||
set(SERVER_COMPONENT_NAME "@SERVER_COMPONENT@")
|
||||
set(SIGNTOOL_EXECUTABLE "@SIGNTOOL_EXECUTABLE@")
|
||||
set(UNINSTALLER_NAME "@GENERATED_UNINSTALLER_EXEC_NAME@")
|
||||
set(REGISTRY_HKLM_INSTALL_ROOT "@REGISTRY_HKLM_INSTALL_ROOT@")
|
||||
set(POST_INSTALL_OPTIONS_REG_GROUP "@POST_INSTALL_OPTIONS_REG_GROUP@")
|
||||
set(CLIENT_DESKTOP_SHORTCUT_REG_KEY "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@")
|
||||
set(CONSOLE_DESKTOP_SHORTCUT_REG_KEY "@CONSOLE_DESKTOP_SHORTCUT_REG_KEY@")
|
||||
set(CONSOLE_STARTUP_REG_KEY "@CONSOLE_STARTUP_REG_KEY@")
|
||||
set(LAUNCH_NOW_REG_KEY "@LAUNCH_NOW_REG_KEY@")
|
||||
set(INSTALLER_HEADER_IMAGE "@INSTALLER_HEADER_IMAGE@")
|
||||
set(UNINSTALLER_HEADER_IMAGE "@UNINSTALLER_HEADER_IMAGE@")
|
||||
set(ADD_REMOVE_ICON_PATH "@ADD_REMOVE_ICON_PATH@")
|
|
@ -1,56 +1,54 @@
|
|||
#
|
||||
#
|
||||
# FixupBundlePostBuild.cmake.in
|
||||
# cmake/templates
|
||||
#
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on February 13, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
#
|
||||
|
||||
include(BundleUtilities)
|
||||
|
||||
|
||||
# replace copy_resolved_item_into_bundle
|
||||
# replace copy_resolved_item_into_bundle
|
||||
#
|
||||
# The official version of copy_resolved_item_into_bundle will print out a "warning:" when
|
||||
# the resolved item matches the resolved embedded item. This not not really an issue that
|
||||
# should rise to the level of a "warning" so we replace this message with a "status:"
|
||||
#
|
||||
function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item)
|
||||
if(WIN32)
|
||||
# ignore case on Windows
|
||||
string(TOLOWER "${resolved_item}" resolved_item_compare)
|
||||
string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
|
||||
else()
|
||||
set(resolved_item_compare "${resolved_item}")
|
||||
set(resolved_embedded_item_compare "${resolved_embedded_item}")
|
||||
endif()
|
||||
if (WIN32)
|
||||
# ignore case on Windows
|
||||
string(TOLOWER "${resolved_item}" resolved_item_compare)
|
||||
string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
|
||||
else()
|
||||
set(resolved_item_compare "${resolved_item}")
|
||||
set(resolved_embedded_item_compare "${resolved_embedded_item}")
|
||||
endif()
|
||||
|
||||
if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
|
||||
# this is our only change from the original version
|
||||
message(STATUS "status: resolved_item == resolved_embedded_item - not copying...")
|
||||
else()
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
|
||||
if(UNIX AND NOT APPLE)
|
||||
file(RPATH_REMOVE FILE "${resolved_embedded_item}")
|
||||
endif()
|
||||
if ("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
|
||||
# this is our only change from the original version
|
||||
message(STATUS "status: resolved_item == resolved_embedded_item - not copying...")
|
||||
else()
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
|
||||
if(UNIX AND NOT APPLE)
|
||||
file(RPATH_REMOVE FILE "${resolved_embedded_item}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
message(STATUS "FIXUP_LIBS for fixup_bundle called for bundle ${BUNDLE_EXECUTABLE} are @FIXUP_LIBS@")
|
||||
|
||||
message(STATUS "Scanning for plugins from ${BUNDLE_PLUGIN_DIR}")
|
||||
|
||||
if (APPLE)
|
||||
set(PLUGIN_EXTENSION "dylib")
|
||||
elseif (WIN32)
|
||||
set(PLUGIN_EXTENSION "dll")
|
||||
else()
|
||||
set(PLUGIN_EXTENSION "so")
|
||||
set(PLUGIN_EXTENSION "dylib")
|
||||
elseif (WIN32)
|
||||
set(PLUGIN_EXTENSION "dll")
|
||||
else()
|
||||
set(PLUGIN_EXTENSION "so")
|
||||
endif()
|
||||
|
||||
file(GLOB RUNTIME_PLUGINS "${BUNDLE_PLUGIN_DIR}/*.${PLUGIN_EXTENSION}")
|
||||
fixup_bundle("${BUNDLE_EXECUTABLE}" "${RUNTIME_PLUGINS}" "@FIXUP_LIBS@")
|
||||
file(GLOB EXTRA_PLUGINS "${BUNDLE_PLUGIN_DIR}/*.${PLUGIN_EXTENSION}")
|
||||
fixup_bundle("${BUNDLE_EXECUTABLE}" "${EXTRA_PLUGINS}" "@FIXUP_LIBS@")
|
||||
|
|
1
cmake/templates/Icon.rc.in
Normal file
|
@ -0,0 +1 @@
|
|||
IDI_ICON1 ICON DISCARDABLE "@CONFIGURE_ICON_PATH@"
|
1364
cmake/templates/NSIS.template.in
Normal file
4
cmake/templates/console-build-info.json.in
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"releaseType": "@RELEASE_TYPE@",
|
||||
"buildIdentifier": "@BUILD_VERSION@"
|
||||
}
|
|
@ -34,8 +34,10 @@ target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES})
|
|||
# libcrypto uses dlopen in libdl
|
||||
if (UNIX)
|
||||
target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS})
|
||||
endif (UNIX)
|
||||
endif ()
|
||||
|
||||
include_application_version()
|
||||
package_libraries_for_deployment()
|
||||
consolidate_stack_components()
|
||||
if (WIN32)
|
||||
package_libraries_for_deployment()
|
||||
endif ()
|
||||
|
||||
install_beside_console()
|
||||
|
|
|
@ -386,8 +386,8 @@
|
|||
"name": "persistFilename",
|
||||
"label": "Entities Filename",
|
||||
"help": "the path to the file entities are stored in. Make sure the path exists.",
|
||||
"placeholder": "resources/models.json.gz",
|
||||
"default": "resources/models.json.gz",
|
||||
"placeholder": "models.json.gz",
|
||||
"default": "models.json.gz",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
|
|
|
@ -126,6 +126,20 @@ var viewHelpers = {
|
|||
}
|
||||
}
|
||||
|
||||
var qs = (function(a) {
|
||||
if (a == "") return {};
|
||||
var b = {};
|
||||
for (var i = 0; i < a.length; ++i)
|
||||
{
|
||||
var p=a[i].split('=', 2);
|
||||
if (p.length == 1)
|
||||
b[p[0]] = "";
|
||||
else
|
||||
b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
|
||||
}
|
||||
return b;
|
||||
})(window.location.search.substr(1).split('&'));
|
||||
|
||||
$(document).ready(function(){
|
||||
/*
|
||||
* Clamped-width.
|
||||
|
@ -272,9 +286,80 @@ $(document).ready(function(){
|
|||
|
||||
// $('body').scrollspy({ target: '#setup-sidebar'})
|
||||
|
||||
reloadSettings();
|
||||
reloadSettings(function(success){
|
||||
if (success) {
|
||||
handleAction();
|
||||
} else {
|
||||
swal({
|
||||
title: '',
|
||||
type: 'error',
|
||||
text: "There was a problem loading the domain settings.\nPlease refresh the page to try again.",
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function handleAction() {
|
||||
// check if we were passed an action to handle
|
||||
var action = qs["action"];
|
||||
|
||||
if (action == "share") {
|
||||
// figure out if we already have a stored domain ID
|
||||
if (Settings.data.values.metaverse.id.length > 0) {
|
||||
// we need to ask the API what a shareable name for this domain is
|
||||
getDomainFromAPI(function(data){
|
||||
// check if we have owner_places (for a real domain) or a name (for a temporary domain)
|
||||
if (data && data.status == "success") {
|
||||
var shareName;
|
||||
if (data.domain.owner_places) {
|
||||
shareName = data.domain.owner_places[0].name
|
||||
} else if (data.domain.name) {
|
||||
shareName = data.domain.name;
|
||||
}
|
||||
|
||||
var shareLink = "hifi://" + shareName;
|
||||
|
||||
console.log(shareLink);
|
||||
|
||||
// show a dialog with a copiable share URL
|
||||
swal({
|
||||
title: "Share",
|
||||
type: "input",
|
||||
inputPlaceholder: shareLink,
|
||||
inputValue: shareLink,
|
||||
text: "Copy this URL to invite friends to your domain.",
|
||||
closeOnConfirm: true
|
||||
});
|
||||
|
||||
$('.sweet-alert input').select();
|
||||
|
||||
} else {
|
||||
// show an error alert
|
||||
swal({
|
||||
title: '',
|
||||
type: 'error',
|
||||
text: "There was a problem retreiving domain information from High Fidelity API.",
|
||||
confirmButtonText: 'Try again',
|
||||
showCancelButton: true,
|
||||
closeOnConfirm: false
|
||||
}, function(isConfirm){
|
||||
if (isConfirm) {
|
||||
// they want to try getting domain share info again
|
||||
showSpinnerAlert("Requesting domain information...")
|
||||
handleAction();
|
||||
} else {
|
||||
swal.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// no domain ID present, just show the share dialog
|
||||
createTemporaryDomain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function dynamicButton(button_id, text) {
|
||||
return $("<button type='button' id='" + button_id + "' class='btn btn-primary'>" + text + "</button>");
|
||||
}
|
||||
|
@ -577,29 +662,33 @@ function placeTableRowForPlaceObject(place) {
|
|||
return placeTableRow(place.name, placePathOrIndex, false);
|
||||
}
|
||||
|
||||
function reloadPlacesOrTemporaryName() {
|
||||
function getDomainFromAPI(callback) {
|
||||
// we only need to do this if we have a current domain ID
|
||||
var domainID = Settings.data.values.metaverse.id;
|
||||
if (domainID.length > 0) {
|
||||
var domainURL = Settings.METAVERSE_URL + "/api/v1/domains/" + domainID;
|
||||
|
||||
$.getJSON(domainURL, function(data){
|
||||
// check if we have owner_places (for a real domain) or a name (for a temporary domain)
|
||||
if (data.status == "success") {
|
||||
if (data.domain.owner_places) {
|
||||
// add a table row for each of these names
|
||||
_.each(data.domain.owner_places, function(place){
|
||||
$('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRowForPlaceObject(place));
|
||||
});
|
||||
} else if (data.domain.name) {
|
||||
// add a table row for this temporary domain name
|
||||
$('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRow(data.domain.name, '/', true));
|
||||
}
|
||||
}
|
||||
});
|
||||
$.getJSON(domainURL, callback).fail(callback);
|
||||
}
|
||||
}
|
||||
|
||||
function reloadPlacesOrTemporaryName() {
|
||||
getDomainFromAPI(function(data){
|
||||
// check if we have owner_places (for a real domain) or a name (for a temporary domain)
|
||||
if (data.status == "success") {
|
||||
if (data.domain.owner_places) {
|
||||
// add a table row for each of these names
|
||||
_.each(data.domain.owner_places, function(place){
|
||||
$('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRowForPlaceObject(place));
|
||||
});
|
||||
} else if (data.domain.name) {
|
||||
// add a table row for this temporary domain name
|
||||
$('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRow(data.domain.name, '/', true));
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function appendDomainIDButtons() {
|
||||
var domainIDInput = $(Settings.DOMAIN_ID_SELECTOR);
|
||||
|
||||
|
@ -728,7 +817,7 @@ function createTemporaryDomain() {
|
|||
});
|
||||
}
|
||||
|
||||
function reloadSettings() {
|
||||
function reloadSettings(callback) {
|
||||
$.getJSON('/settings.json', function(data){
|
||||
_.extend(data, viewHelpers)
|
||||
|
||||
|
@ -757,6 +846,12 @@ function reloadSettings() {
|
|||
placement: 'right',
|
||||
title: 'This setting is in the master config file and cannot be changed'
|
||||
});
|
||||
|
||||
// call the callback now that settings are loaded
|
||||
callback(true);
|
||||
}).fail(function() {
|
||||
// call the failure object since settings load faild
|
||||
callback(false)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <QUrlQuery>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <ApplicationVersion.h>
|
||||
#include <BuildInfo.h>
|
||||
#include <HifiConfigVariantMap.h>
|
||||
#include <HTTPConnection.h>
|
||||
#include <LogUtils.h>
|
||||
|
@ -35,6 +35,7 @@
|
|||
#include <ShutdownEventListener.h>
|
||||
#include <UUID.h>
|
||||
#include <LogHandler.h>
|
||||
#include <ServerPathUtils.h>
|
||||
|
||||
#include "DomainServerNodeData.h"
|
||||
#include "NodeConnectionData.h"
|
||||
|
@ -46,7 +47,7 @@ const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.io";
|
|||
DomainServer::DomainServer(int argc, char* argv[]) :
|
||||
QCoreApplication(argc, argv),
|
||||
_gatekeeper(this),
|
||||
_httpManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this),
|
||||
_httpManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this),
|
||||
_httpsManager(NULL),
|
||||
_allAssignments(),
|
||||
_unfulfilledAssignments(),
|
||||
|
@ -71,17 +72,19 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
|
||||
connect(this, &QCoreApplication::aboutToQuit, this, &DomainServer::aboutToQuit);
|
||||
|
||||
setOrganizationName("High Fidelity");
|
||||
setOrganizationName(BuildInfo::MODIFIED_ORGANIZATION);
|
||||
setOrganizationDomain("highfidelity.io");
|
||||
setApplicationName("domain-server");
|
||||
setApplicationVersion(BUILD_VERSION);
|
||||
setApplicationVersion(BuildInfo::VERSION);
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
|
||||
// make sure we have a fresh AccountManager instance
|
||||
// (need this since domain-server can restart itself and maintain static variables)
|
||||
AccountManager::getInstance(true);
|
||||
|
||||
_settingsManager.setupConfigMap(arguments());
|
||||
auto args = arguments();
|
||||
|
||||
_settingsManager.setupConfigMap(args);
|
||||
|
||||
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
||||
#ifdef _WIN32
|
||||
|
@ -110,6 +113,8 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
|
||||
// preload some user public keys so they can connect on first request
|
||||
_gatekeeper.preloadAllowedUserPublicKeys();
|
||||
|
||||
optionallyGetTemporaryName(args);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,7 +162,7 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() {
|
|||
QSslCertificate sslCertificate(&certFile);
|
||||
QSslKey privateKey(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, keyPassphraseString.toUtf8());
|
||||
|
||||
_httpsManager = new HTTPSManager(DOMAIN_SERVER_HTTPS_PORT, sslCertificate, privateKey, QString(), this, this);
|
||||
_httpsManager = new HTTPSManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTPS_PORT, sslCertificate, privateKey, QString(), this, this);
|
||||
|
||||
qDebug() << "TCP server listening for HTTPS connections on" << DOMAIN_SERVER_HTTPS_PORT;
|
||||
|
||||
|
@ -209,6 +214,80 @@ bool DomainServer::optionallySetupOAuth() {
|
|||
return true;
|
||||
}
|
||||
|
||||
static const QString METAVERSE_DOMAIN_ID_KEY_PATH = "metaverse.id";
|
||||
|
||||
void DomainServer::optionallyGetTemporaryName(const QStringList& arguments) {
|
||||
// check for the temporary name parameter
|
||||
const QString GET_TEMPORARY_NAME_SWITCH = "--get-temp-name";
|
||||
|
||||
if (arguments.contains(GET_TEMPORARY_NAME_SWITCH)) {
|
||||
|
||||
// make sure we don't already have a domain ID
|
||||
const QVariant* idValueVariant = valueForKeyPath(_settingsManager.getSettingsMap(), METAVERSE_DOMAIN_ID_KEY_PATH);
|
||||
if (idValueVariant) {
|
||||
qWarning() << "Temporary domain name requested but a domain ID is already present in domain-server settings."
|
||||
<< "Will not request temporary name.";
|
||||
return;
|
||||
}
|
||||
|
||||
// we've been asked to grab a temporary name from the API
|
||||
// so fire off that request now
|
||||
auto& accountManager = AccountManager::getInstance();
|
||||
|
||||
// ask our auth endpoint for our balance
|
||||
JSONCallbackParameters callbackParameters;
|
||||
callbackParameters.jsonCallbackReceiver = this;
|
||||
callbackParameters.jsonCallbackMethod = "handleTempDomainSuccess";
|
||||
callbackParameters.errorCallbackReceiver = this;
|
||||
callbackParameters.errorCallbackMethod = "handleTempDomainError";
|
||||
|
||||
accountManager.sendRequest("/api/v1/domains/temporary", AccountManagerAuth::None,
|
||||
QNetworkAccessManager::PostOperation, callbackParameters);
|
||||
}
|
||||
}
|
||||
|
||||
void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) {
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object();
|
||||
|
||||
// grab the information for the new domain
|
||||
static const QString DATA_KEY = "data";
|
||||
static const QString DOMAIN_KEY = "domain";
|
||||
static const QString ID_KEY = "id";
|
||||
static const QString NAME_KEY = "name";
|
||||
|
||||
auto domainObject = jsonObject[DATA_KEY].toObject()[DOMAIN_KEY].toObject();
|
||||
if (!domainObject.isEmpty()) {
|
||||
auto id = domainObject[ID_KEY].toString();
|
||||
auto name = domainObject[NAME_KEY].toString();
|
||||
|
||||
qInfo() << "Received new temporary domain name" << name;
|
||||
qDebug() << "The temporary domain ID is" << id;
|
||||
|
||||
// store the new domain ID and auto network setting immediately
|
||||
QString newSettingsJSON = QString("{\"metaverse\": { \"id\": \"%1\", \"automatic_networking\": \"full\"}}").arg(id);
|
||||
auto settingsDocument = QJsonDocument::fromJson(newSettingsJSON.toUtf8());
|
||||
_settingsManager.recurseJSONObjectAndOverwriteSettings(settingsDocument.object());
|
||||
|
||||
// store the new ID and auto networking setting on disk
|
||||
_settingsManager.persistToFile();
|
||||
|
||||
// change our domain ID immediately
|
||||
DependencyManager::get<LimitedNodeList>()->setSessionUUID(QUuid { id });
|
||||
|
||||
// change our automatic networking settings so that we're communicating with the ICE server
|
||||
setupICEHeartbeatForFullNetworking();
|
||||
|
||||
} else {
|
||||
qWarning() << "There were problems parsing the API response containing a temporary domain name. Please try again"
|
||||
<< "via domain-server relaunch or from the domain-server settings.";
|
||||
}
|
||||
}
|
||||
|
||||
void DomainServer::handleTempDomainError(QNetworkReply& requestReply) {
|
||||
qWarning() << "A temporary name was requested but there was an error creating one. Please try again via domain-server relaunch"
|
||||
<< "or from the domain-server settings.";
|
||||
}
|
||||
|
||||
const QString DOMAIN_CONFIG_ID_KEY = "id";
|
||||
|
||||
const QString METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH = "metaverse.automatic_networking";
|
||||
|
@ -259,7 +338,6 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
|||
|
||||
// set our LimitedNodeList UUID to match the UUID from our config
|
||||
// nodes will currently use this to add resources to data-web that relate to our domain
|
||||
const QString METAVERSE_DOMAIN_ID_KEY_PATH = "metaverse.id";
|
||||
const QVariant* idValueVariant = valueForKeyPath(settingsMap, METAVERSE_DOMAIN_ID_KEY_PATH);
|
||||
if (idValueVariant) {
|
||||
nodeList->setSessionUUID(idValueVariant->toString());
|
||||
|
@ -372,19 +450,7 @@ void DomainServer::setupAutomaticNetworking() {
|
|||
_settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH).toString();
|
||||
|
||||
if (_automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) {
|
||||
// call our sendHeartbeatToIceServer immediately anytime a local or public socket changes
|
||||
connect(nodeList.data(), &LimitedNodeList::localSockAddrChanged,
|
||||
this, &DomainServer::sendHeartbeatToIceServer);
|
||||
connect(nodeList.data(), &LimitedNodeList::publicSockAddrChanged,
|
||||
this, &DomainServer::sendHeartbeatToIceServer);
|
||||
|
||||
// we need this DS to know what our public IP is - start trying to figure that out now
|
||||
nodeList->startSTUNPublicSocketUpdate();
|
||||
|
||||
// setup a timer to heartbeat with the ice-server every so often
|
||||
QTimer* iceHeartbeatTimer = new QTimer(this);
|
||||
connect(iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::sendHeartbeatToIceServer);
|
||||
iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS);
|
||||
setupICEHeartbeatForFullNetworking();
|
||||
}
|
||||
|
||||
if (!didSetupAccountManagerWithAccessToken()) {
|
||||
|
@ -434,6 +500,26 @@ void DomainServer::setupAutomaticNetworking() {
|
|||
dataHeartbeatTimer->start(DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS);
|
||||
}
|
||||
|
||||
void DomainServer::setupICEHeartbeatForFullNetworking() {
|
||||
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
||||
|
||||
// call our sendHeartbeatToIceServer immediately anytime a local or public socket changes
|
||||
connect(limitedNodeList.data(), &LimitedNodeList::localSockAddrChanged,
|
||||
this, &DomainServer::sendHeartbeatToIceServer);
|
||||
connect(limitedNodeList.data(), &LimitedNodeList::publicSockAddrChanged,
|
||||
this, &DomainServer::sendHeartbeatToIceServer);
|
||||
|
||||
// we need this DS to know what our public IP is - start trying to figure that out now
|
||||
limitedNodeList->startSTUNPublicSocketUpdate();
|
||||
|
||||
if (!_iceHeartbeatTimer) {
|
||||
// setup a timer to heartbeat with the ice-server every so often
|
||||
_iceHeartbeatTimer = new QTimer { this };
|
||||
connect(_iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::sendHeartbeatToIceServer);
|
||||
_iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS);
|
||||
}
|
||||
}
|
||||
|
||||
void DomainServer::loginFailed() {
|
||||
qDebug() << "Login to data server has failed. domain-server will now quit";
|
||||
QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection);
|
||||
|
@ -1068,7 +1154,7 @@ QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) {
|
|||
|
||||
const char ASSIGNMENT_SCRIPT_HOST_LOCATION[] = "resources/web/assignment";
|
||||
QString pathForAssignmentScript(const QUuid& assignmentUUID) {
|
||||
QString newPath(ASSIGNMENT_SCRIPT_HOST_LOCATION);
|
||||
QString newPath { ServerPathUtils::getDataDirectory() + "/" + QString(ASSIGNMENT_SCRIPT_HOST_LOCATION) };
|
||||
newPath += "/scripts/";
|
||||
// append the UUID for this script as the new filename, remove the curly braces
|
||||
newPath += uuidStringWithoutCurlyBraces(assignmentUUID);
|
||||
|
|
|
@ -74,6 +74,9 @@ private slots:
|
|||
void sendHeartbeatToIceServer();
|
||||
|
||||
void handleConnectedNode(SharedNodePointer newNode);
|
||||
|
||||
void handleTempDomainSuccess(QNetworkReply& requestReply);
|
||||
void handleTempDomainError(QNetworkReply& requestReply);
|
||||
|
||||
private:
|
||||
void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid());
|
||||
|
@ -81,10 +84,13 @@ private:
|
|||
bool optionallyReadX509KeyAndCertificate();
|
||||
bool optionallySetupAssignmentPayment();
|
||||
|
||||
void optionallyGetTemporaryName(const QStringList& arguments);
|
||||
|
||||
bool didSetupAccountManagerWithAccessToken();
|
||||
bool resetAccountManagerAccessToken();
|
||||
|
||||
void setupAutomaticNetworking();
|
||||
void setupICEHeartbeatForFullNetworking();
|
||||
void sendHeartbeatToDataServer(const QString& networkAddress);
|
||||
|
||||
unsigned int countConnectedUsers();
|
||||
|
@ -144,6 +150,8 @@ private:
|
|||
DomainServerSettingsManager _settingsManager;
|
||||
|
||||
HifiSockAddr _iceServerSocket;
|
||||
|
||||
QTimer* _iceHeartbeatTimer { nullptr }; // this looks like it dangles when created but it's parented to the DomainServer
|
||||
|
||||
friend class DomainGatekeeper;
|
||||
};
|
||||
|
|
|
@ -193,7 +193,7 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection
|
|||
qDebug() << "DomainServerSettingsManager postedObject -" << postedObject;
|
||||
|
||||
// we recurse one level deep below each group for the appropriate setting
|
||||
recurseJSONObjectAndOverwriteSettings(postedObject, _configMap.getUserConfig());
|
||||
recurseJSONObjectAndOverwriteSettings(postedObject);
|
||||
|
||||
// store whatever the current _settingsMap is to file
|
||||
persistToFile();
|
||||
|
@ -407,8 +407,9 @@ QJsonObject DomainServerSettingsManager::settingDescriptionFromGroup(const QJson
|
|||
return QJsonObject();
|
||||
}
|
||||
|
||||
void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject,
|
||||
QVariantMap& settingsVariant) {
|
||||
void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject) {
|
||||
auto& settingsVariant = _configMap.getUserConfig();
|
||||
|
||||
// Iterate on the setting groups
|
||||
foreach(const QString& rootKey, postedObject.keys()) {
|
||||
QJsonValue rootValue = postedObject[rootKey];
|
||||
|
@ -481,6 +482,9 @@ void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
|||
settingsVariant.remove(rootKey);
|
||||
}
|
||||
}
|
||||
|
||||
// re-merge the user and master configs after a settings change
|
||||
_configMap.mergeMasterAndUserConfigs();
|
||||
}
|
||||
|
||||
void DomainServerSettingsManager::persistToFile() {
|
||||
|
|
|
@ -46,7 +46,7 @@ private slots:
|
|||
|
||||
private:
|
||||
QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false);
|
||||
void recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, QVariantMap& settingsVariant);
|
||||
void recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject);
|
||||
|
||||
void updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap,
|
||||
const QJsonObject& settingDescription);
|
||||
|
@ -56,6 +56,8 @@ private:
|
|||
double _descriptionVersion;
|
||||
QJsonArray _descriptionArray;
|
||||
HifiConfigVariantMap _configMap;
|
||||
|
||||
friend class DomainServer;
|
||||
};
|
||||
|
||||
#endif // hifi_DomainServerSettingsManager_h
|
||||
|
|
|
@ -27,7 +27,7 @@ IceServer::IceServer(int argc, char* argv[]) :
|
|||
_id(QUuid::createUuid()),
|
||||
_serverSocket(),
|
||||
_activePeers(),
|
||||
_httpManager(ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this)
|
||||
_httpManager(QHostAddress::AnyIPv4, ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this)
|
||||
{
|
||||
// start the ice-server socket
|
||||
qDebug() << "ice-server socket is listening on" << ICE_SERVER_DEFAULT_PORT;
|
||||
|
|
|
@ -20,12 +20,10 @@ find_package(Qt5LinguistTools REQUIRED)
|
|||
find_package(Qt5LinguistToolsMacros)
|
||||
|
||||
if (WIN32)
|
||||
add_definitions(-D_USE_MATH_DEFINES) # apparently needed to get M_PI and other defines from cmath/math.h
|
||||
add_definitions(-DWINDOWS_LEAN_AND_MEAN) # needed to make sure windows doesn't go to crazy with its defines
|
||||
add_definitions(-D_USE_MATH_DEFINES) # apparently needed to get M_PI and other defines from cmath/math.h
|
||||
add_definitions(-DWINDOWS_LEAN_AND_MEAN) # needed to make sure windows doesn't go to crazy with its defines
|
||||
endif()
|
||||
|
||||
include_application_version()
|
||||
|
||||
# grab the implementation and header files from src dirs
|
||||
file(GLOB_RECURSE INTERFACE_SRCS "src/*.cpp" "src/*.h")
|
||||
GroupSources("src")
|
||||
|
@ -45,8 +43,8 @@ else ()
|
|||
list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP})
|
||||
endif ()
|
||||
|
||||
find_package(Qt5 COMPONENTS
|
||||
Gui Multimedia Network OpenGL Qml Quick Script Svg
|
||||
find_package(Qt5 COMPONENTS
|
||||
Gui Multimedia Network OpenGL Qml Quick Script Svg
|
||||
WebChannel WebEngine WebEngineWidgets WebKitWidgets WebSockets)
|
||||
|
||||
# grab the ui files in resources/ui
|
||||
|
@ -65,23 +63,24 @@ set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}")
|
|||
|
||||
if (APPLE)
|
||||
# configure CMake to use a custom Info.plist
|
||||
SET_TARGET_PROPERTIES( ${this_target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in )
|
||||
set_target_properties(${this_target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in)
|
||||
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME Interface)
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER io.highfidelity.Interface)
|
||||
|
||||
if (UPPER_CMAKE_BUILD_TYPE MATCHES RELEASE OR UPPER_CMAKE_BUILD_TYPE MATCHES RELWITHDEBINFO)
|
||||
set(ICON_FILENAME "interface.icns")
|
||||
if (PRODUCTION_BUILD)
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface)
|
||||
else ()
|
||||
set(ICON_FILENAME "interface-beta.icns")
|
||||
if (DEV_BUILD)
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface-dev)
|
||||
elseif (PR_BUILD)
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface-pr)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
||||
# set how the icon shows up in the Info.plist file
|
||||
SET(MACOSX_BUNDLE_ICON_FILE "${ICON_FILENAME}")
|
||||
set(MACOSX_BUNDLE_ICON_FILE "${INTERFACE_ICON_FILENAME}")
|
||||
|
||||
# set where in the bundle to put the resources file
|
||||
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/icon/${ICON_FILENAME} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
|
||||
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
|
||||
set(DISCOVERED_RESOURCES "")
|
||||
|
||||
# use the add_resources_to_os_x_bundle macro to recurse into resources
|
||||
|
@ -89,28 +88,37 @@ if (APPLE)
|
|||
|
||||
# append the discovered resources to our list of interface sources
|
||||
list(APPEND INTERFACE_SRCS ${DISCOVERED_RESOURCES})
|
||||
|
||||
set(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/icon/${ICON_FILENAME}")
|
||||
|
||||
set(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME}")
|
||||
endif()
|
||||
|
||||
# create the executable, make it a bundle on OS X
|
||||
if (APPLE)
|
||||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})
|
||||
|
||||
# make sure the output name for the .app bundle is correct
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${INTERFACE_BUNDLE_NAME})
|
||||
elseif(WIN32)
|
||||
add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM})
|
||||
# configure an rc file for the chosen icon
|
||||
set(CONFIGURE_ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME}")
|
||||
set(CONFIGURE_ICON_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Icon.rc")
|
||||
configure_file("${HF_CMAKE_DIR}/templates/Icon.rc.in" ${CONFIGURE_ICON_RC_OUTPUT})
|
||||
|
||||
# add an executable that also has the icon itself and the configured rc file as resources
|
||||
add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT})
|
||||
else()
|
||||
add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
|
||||
endif()
|
||||
|
||||
# These are external plugins, but we need to do the 'add dependency' here so that their
|
||||
# binary directories get added to the fixup path
|
||||
add_dependency_external_projects(sixense)
|
||||
add_dependency_external_projects(sdl2)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes")
|
||||
|
||||
if (WIN32)
|
||||
add_dependency_external_projects(OpenVR)
|
||||
endif()
|
||||
if(WIN32 OR APPLE)
|
||||
add_dependency_external_projects(neuron)
|
||||
# These are external plugins, but we need to do the 'add dependency' here so that their
|
||||
# binary directories get added to the fixup path
|
||||
add_dependency_external_projects(sixense)
|
||||
add_dependency_external_projects(sdl2)
|
||||
add_dependency_external_projects(OpenVR)
|
||||
add_dependency_external_projects(neuron)
|
||||
endif()
|
||||
|
||||
# disable /OPT:REF and /OPT:ICF for the Debug builds
|
||||
|
@ -121,11 +129,14 @@ if (WIN32)
|
|||
endif()
|
||||
|
||||
# link required hifi libraries
|
||||
link_hifi_libraries(shared octree environment gpu gl procedural model render
|
||||
recording fbx networking model-networking entities avatars
|
||||
audio audio-client animation script-engine physics
|
||||
link_hifi_libraries(shared octree environment gpu gl procedural model render
|
||||
recording fbx networking model-networking entities avatars
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer ui auto-updater
|
||||
controllers plugins display-plugins input-plugins )
|
||||
controllers plugins display-plugins input-plugins)
|
||||
|
||||
# include the binary directory of render-utils for shader includes
|
||||
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries/render-utils")
|
||||
|
||||
#fixme find a way to express faceshift as a plugin
|
||||
target_bullet()
|
||||
|
@ -133,39 +144,39 @@ target_glew()
|
|||
target_opengl()
|
||||
|
||||
if (WIN32 OR APPLE)
|
||||
target_faceshift()
|
||||
target_faceshift()
|
||||
endif()
|
||||
|
||||
# perform standard include and linking for found externals
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
|
||||
|
||||
if (${${EXTERNAL}_UPPERCASE}_REQUIRED)
|
||||
find_package(${EXTERNAL} REQUIRED)
|
||||
else ()
|
||||
find_package(${EXTERNAL})
|
||||
endif ()
|
||||
|
||||
|
||||
if (${${EXTERNAL}_UPPERCASE}_FOUND AND NOT DISABLE_${${EXTERNAL}_UPPERCASE})
|
||||
add_definitions(-DHAVE_${${EXTERNAL}_UPPERCASE})
|
||||
|
||||
|
||||
# include the library directories (ignoring warnings)
|
||||
if (NOT ${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS)
|
||||
set(${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIR})
|
||||
endif ()
|
||||
|
||||
|
||||
include_directories(SYSTEM ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS})
|
||||
|
||||
|
||||
# perform the system include hack for OS X to ignore warnings
|
||||
if (APPLE)
|
||||
foreach(EXTERNAL_INCLUDE_DIR ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS})
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${EXTERNAL_INCLUDE_DIR}")
|
||||
endforeach()
|
||||
endif ()
|
||||
|
||||
|
||||
if (NOT ${${EXTERNAL}_UPPERCASE}_LIBRARIES)
|
||||
set(${${EXTERNAL}_UPPERCASE}_LIBRARIES ${${${EXTERNAL}_UPPERCASE}_LIBRARY})
|
||||
endif ()
|
||||
|
||||
|
||||
if (NOT APPLE OR NOT ${${EXTERNAL}_UPPERCASE} MATCHES "SIXENSE")
|
||||
target_link_libraries(${TARGET_NAME} ${${${EXTERNAL}_UPPERCASE}_LIBRARIES})
|
||||
elseif (APPLE AND NOT INSTALLER_BUILD)
|
||||
|
@ -179,15 +190,15 @@ include_directories("${PROJECT_SOURCE_DIR}/src")
|
|||
|
||||
target_link_libraries(
|
||||
${TARGET_NAME}
|
||||
Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL
|
||||
Qt5::Qml Qt5::Quick Qt5::Script Qt5::Svg
|
||||
Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL
|
||||
Qt5::Qml Qt5::Quick Qt5::Script Qt5::Svg
|
||||
Qt5::WebChannel Qt5::WebEngine Qt5::WebEngineWidgets Qt5::WebKitWidgets
|
||||
)
|
||||
|
||||
# Issue causes build failure unless we add this directory.
|
||||
# See https://bugreports.qt.io/browse/QTBUG-43351
|
||||
# Issue causes build failure unless we add this directory.
|
||||
# See https://bugreports.qt.io/browse/QTBUG-43351
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${Qt5_DIR}/../../../plugins/qtwebengine)
|
||||
add_paths_to_fixup_libs(${Qt5_DIR}/../../../plugins/qtwebengine)
|
||||
endif()
|
||||
|
||||
# assume we are using a Qt build without bearer management
|
||||
|
@ -199,31 +210,63 @@ if (APPLE)
|
|||
find_library(AppKit AppKit)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} ${OpenGL} ${AppKit})
|
||||
|
||||
# install command for OS X bundle
|
||||
INSTALL(TARGETS ${TARGET_NAME}
|
||||
BUNDLE DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/install" COMPONENT Runtime
|
||||
RUNTIME DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/install" COMPONENT Runtime
|
||||
|
||||
# setup install of OS X interface bundle
|
||||
install(TARGETS ${TARGET_NAME}
|
||||
BUNDLE DESTINATION ${INTERFACE_INSTALL_DIR}
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
|
||||
set(SCRIPTS_INSTALL_DIR "${INTERFACE_INSTALL_APP_PATH}/Contents/Resources")
|
||||
|
||||
# call the fixup_interface macro to add required bundling commands for installation
|
||||
fixup_interface()
|
||||
|
||||
else (APPLE)
|
||||
# copy the resources files beside the executable
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${PROJECT_SOURCE_DIR}/resources"
|
||||
$<TARGET_FILE_DIR:${TARGET_NAME}>/resources
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/examples"
|
||||
$<TARGET_FILE_DIR:${TARGET_NAME}>/scripts
|
||||
)
|
||||
|
||||
# link target to external libraries
|
||||
if (WIN32)
|
||||
target_link_libraries(${TARGET_NAME} wsock32.lib Winmm.lib)
|
||||
else (WIN32)
|
||||
# Nothing else required on linux apparently
|
||||
|
||||
# setup install of executable and things copied by fixup/windeployqt
|
||||
install(
|
||||
FILES "$<TARGET_FILE_DIR:${TARGET_NAME}>/"
|
||||
DESTINATION ${INTERFACE_INSTALL_DIR}
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
|
||||
set(SCRIPTS_INSTALL_DIR "${INTERFACE_INSTALL_DIR}")
|
||||
|
||||
set(EXECUTABLE_COMPONENT ${CLIENT_COMPONENT})
|
||||
|
||||
optional_win_executable_signing()
|
||||
endif()
|
||||
endif (APPLE)
|
||||
|
||||
if (WIN32)
|
||||
set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/resources/qml")
|
||||
if (SCRIPTS_INSTALL_DIR)
|
||||
# setup install of scripts beside interface executable
|
||||
install(
|
||||
DIRECTORY "${CMAKE_SOURCE_DIR}/examples/"
|
||||
DESTINATION ${SCRIPTS_INSTALL_DIR}/scripts
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
endif()
|
||||
|
||||
package_libraries_for_deployment()
|
||||
consolidate_stack_components()
|
||||
if (WIN32)
|
||||
set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/resources/qml")
|
||||
|
||||
set(TARGET_INSTALL_DIR ${INTERFACE_INSTALL_DIR})
|
||||
set(TARGET_INSTALL_COMPONENT ${CLIENT_COMPONENT})
|
||||
manually_install_ssl_eay()
|
||||
|
||||
package_libraries_for_deployment()
|
||||
endif()
|
||||
|
|
|
@ -36,6 +36,9 @@
|
|||
#include <QtGui/QMouseEvent>
|
||||
#include <QtGui/QDesktopServices>
|
||||
|
||||
#include <QtNetwork/QLocalSocket>
|
||||
#include <QtNetwork/QLocalServer>
|
||||
|
||||
#include <QtQml/QQmlContext>
|
||||
#include <QtQml/QQmlEngine>
|
||||
#include <QtQuick/QQuickWindow>
|
||||
|
@ -57,7 +60,7 @@
|
|||
#include <ResourceScriptingInterface.h>
|
||||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
#include <ApplicationVersion.h>
|
||||
#include <BuildInfo.h>
|
||||
#include <AssetClient.h>
|
||||
#include <AssetUpload.h>
|
||||
#include <AutoUpdater.h>
|
||||
|
@ -302,7 +305,7 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
listenPort = atoi(portStr);
|
||||
}
|
||||
// Set build version
|
||||
QCoreApplication::setApplicationVersion(BUILD_VERSION);
|
||||
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
|
||||
|
||||
Setting::preInit();
|
||||
|
||||
|
@ -5175,3 +5178,30 @@ void Application::setActiveDisplayPlugin(const QString& pluginName) {
|
|||
}
|
||||
updateDisplayMode();
|
||||
}
|
||||
|
||||
void Application::handleLocalServerConnection() {
|
||||
auto server = qobject_cast<QLocalServer*>(sender());
|
||||
|
||||
qDebug() << "Got connection on local server from additional instance - waiting for parameters";
|
||||
|
||||
auto socket = server->nextPendingConnection();
|
||||
|
||||
connect(socket, &QLocalSocket::readyRead, this, &Application::readArgumentsFromLocalSocket);
|
||||
|
||||
qApp->getWindow()->raise();
|
||||
qApp->getWindow()->activateWindow();
|
||||
}
|
||||
|
||||
void Application::readArgumentsFromLocalSocket() {
|
||||
auto socket = qobject_cast<QLocalSocket*>(sender());
|
||||
|
||||
auto message = socket->readAll();
|
||||
socket->deleteLater();
|
||||
|
||||
qDebug() << "Read from connection: " << message;
|
||||
|
||||
// If we received a message, try to open it as a URL
|
||||
if (message.length() > 0) {
|
||||
qApp->openUrl(QString::fromUtf8(message));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ class Application;
|
|||
|
||||
class Application : public QApplication, public AbstractViewStateInterface, public AbstractScriptingServicesInterface, public AbstractUriHandler {
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
// TODO? Get rid of those
|
||||
friend class OctreePacketProcessor;
|
||||
friend class PluginContainerProxy;
|
||||
|
@ -102,15 +102,15 @@ public:
|
|||
Application(int& argc, char** argv, QElapsedTimer& startup_time);
|
||||
~Application();
|
||||
|
||||
void postLambdaEvent(std::function<void()> f);
|
||||
void postLambdaEvent(std::function<void()> f) override;
|
||||
|
||||
void initializeGL();
|
||||
void initializeUi();
|
||||
void paintGL();
|
||||
void resizeGL();
|
||||
|
||||
bool event(QEvent* event);
|
||||
bool eventFilter(QObject* object, QEvent* event);
|
||||
bool event(QEvent* event) override;
|
||||
bool eventFilter(QObject* object, QEvent* event) override;
|
||||
|
||||
glm::uvec2 getCanvasSize() const;
|
||||
glm::uvec2 getUiSize() const;
|
||||
|
@ -129,7 +129,7 @@ public:
|
|||
// passes, mirror window passes, etc
|
||||
ViewFrustum* getDisplayViewFrustum();
|
||||
const ViewFrustum* getDisplayViewFrustum() const;
|
||||
ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; }
|
||||
ViewFrustum* getShadowViewFrustum() override { return &_shadowViewFrustum; }
|
||||
const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; }
|
||||
EntityTreeRenderer* getEntities() { return DependencyManager::get<EntityTreeRenderer>().data(); }
|
||||
QUndoStack* getUndoStack() { return &_undoStack; }
|
||||
|
@ -151,7 +151,7 @@ public:
|
|||
Overlays& getOverlays() { return _overlays; }
|
||||
|
||||
bool isForeground() const { return _isForeground; }
|
||||
|
||||
|
||||
uint32_t getFrameCount() { return _frameCount; }
|
||||
float getFps() const { return _fps; }
|
||||
float getTargetFrameRate(); // frames/second
|
||||
|
@ -164,7 +164,7 @@ public:
|
|||
NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; }
|
||||
|
||||
virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; }
|
||||
virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine);
|
||||
virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) override;
|
||||
|
||||
QImage renderAvatarBillboard(RenderArgs* renderArgs);
|
||||
|
||||
|
@ -208,9 +208,9 @@ public:
|
|||
void setMaxOctreePacketsPerSecond(int maxOctreePPS);
|
||||
int getMaxOctreePacketsPerSecond();
|
||||
|
||||
render::ScenePointer getMain3DScene() { return _main3DScene; }
|
||||
render::ScenePointer getMain3DScene() override { return _main3DScene; }
|
||||
render::ScenePointer getMain3DScene() const { return _main3DScene; }
|
||||
render::EnginePointer getRenderEngine() { return _renderEngine; }
|
||||
render::EnginePointer getRenderEngine() override { return _renderEngine; }
|
||||
gpu::ContextPointer getGPUContext() const { return _gpuContext; }
|
||||
|
||||
const QRect& getMirrorViewRect() const { return _mirrorViewRect; }
|
||||
|
@ -245,6 +245,9 @@ public slots:
|
|||
void toggleLogDialog();
|
||||
void toggleRunningScriptsWidget();
|
||||
|
||||
void handleLocalServerConnection();
|
||||
void readArgumentsFromLocalSocket();
|
||||
|
||||
void showFriendsWindow();
|
||||
|
||||
void packageModel();
|
||||
|
@ -258,7 +261,7 @@ public slots:
|
|||
|
||||
void resetSensors(bool andReload = false);
|
||||
void setActiveFaceTracker();
|
||||
|
||||
|
||||
#ifdef HAVE_IVIEWHMD
|
||||
void setActiveEyeTracker();
|
||||
void calibrateEyeTracker1Point();
|
||||
|
@ -275,11 +278,11 @@ public slots:
|
|||
void reloadResourceCaches();
|
||||
|
||||
void crashApplication();
|
||||
|
||||
|
||||
void rotationModeChanged();
|
||||
|
||||
|
||||
void runTests();
|
||||
|
||||
|
||||
private slots:
|
||||
void clearDomainOctreeDetails();
|
||||
void idle(uint64_t now);
|
||||
|
@ -291,12 +294,12 @@ private slots:
|
|||
void faceTrackerMuteToggled();
|
||||
|
||||
void activeChanged(Qt::ApplicationState state);
|
||||
|
||||
|
||||
void domainSettingsReceived(const QJsonObject& domainSettingsObject);
|
||||
void handleDomainConnectionDeniedPacket(QSharedPointer<ReceivedMessage> message);
|
||||
|
||||
|
||||
void notifyPacketVersionMismatch();
|
||||
|
||||
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
|
||||
|
@ -318,13 +321,13 @@ private slots:
|
|||
void packetSent(quint64 length);
|
||||
void updateDisplayMode();
|
||||
void updateInputModes();
|
||||
|
||||
|
||||
private:
|
||||
void initDisplay();
|
||||
void init();
|
||||
|
||||
void cleanupBeforeQuit();
|
||||
|
||||
|
||||
void emptyLocalCache();
|
||||
|
||||
void update(float deltaTime);
|
||||
|
@ -344,45 +347,45 @@ private:
|
|||
void renderRearViewMirror(RenderArgs* renderArgs, const QRect& region, bool billboard = false);
|
||||
|
||||
int sendNackPackets();
|
||||
|
||||
|
||||
void takeSnapshot();
|
||||
|
||||
|
||||
MyAvatar* getMyAvatar() const;
|
||||
|
||||
|
||||
void checkSkeleton();
|
||||
|
||||
|
||||
void initializeAcceptedFiles();
|
||||
int getRenderAmbientLight() const;
|
||||
|
||||
|
||||
void displaySide(RenderArgs* renderArgs, Camera& whichCamera, bool selfAvatarOnly = false, bool billboard = false);
|
||||
|
||||
|
||||
bool importSVOFromURL(const QString& urlString);
|
||||
|
||||
|
||||
bool nearbyEntitiesAreReadyForPhysics();
|
||||
int processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode);
|
||||
void trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket);
|
||||
|
||||
|
||||
void resizeEvent(QResizeEvent* size);
|
||||
|
||||
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
void keyReleaseEvent(QKeyEvent* event);
|
||||
|
||||
|
||||
void focusOutEvent(QFocusEvent* event);
|
||||
void focusInEvent(QFocusEvent* event);
|
||||
|
||||
|
||||
void mouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0);
|
||||
void mousePressEvent(QMouseEvent* event, unsigned int deviceID = 0);
|
||||
void mouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID = 0);
|
||||
void mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0);
|
||||
|
||||
|
||||
void touchBeginEvent(QTouchEvent* event);
|
||||
void touchEndEvent(QTouchEvent* event);
|
||||
void touchUpdateEvent(QTouchEvent* event);
|
||||
|
||||
|
||||
void wheelEvent(QWheelEvent* event);
|
||||
void dropEvent(QDropEvent* event);
|
||||
void dragEnterEvent(QDragEnterEvent* event);
|
||||
|
||||
|
||||
|
||||
bool _dependencyManagerIsSetup;
|
||||
|
||||
|
@ -461,7 +464,7 @@ private:
|
|||
|
||||
quint64 _lastNackTime;
|
||||
quint64 _lastSendDownstreamAudioStats;
|
||||
|
||||
|
||||
bool _aboutToQuit;
|
||||
|
||||
Bookmarks* _bookmarks;
|
||||
|
@ -470,9 +473,9 @@ private:
|
|||
|
||||
QThread _settingsThread;
|
||||
QTimer _settingsTimer;
|
||||
|
||||
|
||||
GLCanvas* _glWidget{ nullptr };
|
||||
|
||||
|
||||
typedef bool (Application::* AcceptURLMethod)(const QString &);
|
||||
static const QHash<QString, AcceptURLMethod> _acceptedExtensions;
|
||||
|
||||
|
|
|
@ -22,11 +22,11 @@
|
|||
#include <RenderArgs.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
#include "../../libraries/render-utils/stars_vert.h"
|
||||
#include "../../libraries/render-utils/stars_frag.h"
|
||||
#include <stars_vert.h>
|
||||
#include <stars_frag.h>
|
||||
|
||||
#include "../../libraries/render-utils/standardTransformPNTC_vert.h"
|
||||
#include "../../libraries/render-utils/starsGrid_frag.h"
|
||||
#include <standardTransformPNTC_vert.h>
|
||||
#include <starsGrid_frag.h>
|
||||
|
||||
//static const float TILT = 0.23f;
|
||||
static const float TILT = 0.0f;
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
|
||||
virtual void updateActionWorker(float deltaTimeStep) override;
|
||||
|
||||
QByteArray serialize() const;
|
||||
QByteArray serialize() const override;
|
||||
virtual void deserialize(QByteArray serializedArguments) override;
|
||||
|
||||
virtual bool shouldSuppressLocationEdits() override { return _active && !_ownerEntity.expired(); }
|
||||
|
|
|
@ -11,7 +11,10 @@
|
|||
#include <QCommandLineParser>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QLocalSocket>
|
||||
#include <QLocalServer>
|
||||
#include <QSettings>
|
||||
#include <QSharedMemory>
|
||||
#include <QTranslator>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
@ -19,71 +22,71 @@
|
|||
#include "AddressManager.h"
|
||||
#include "Application.h"
|
||||
#include "InterfaceLogging.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) {
|
||||
const UINT TIMEOUT = 200; // ms
|
||||
DWORD_PTR response;
|
||||
LRESULT result = SendMessageTimeout(hWnd, UWM_IDENTIFY_INSTANCES, 0, 0, SMTO_BLOCK | SMTO_ABORTIFHUNG, TIMEOUT, &response);
|
||||
if (result == 0) { // Timeout; continue search.
|
||||
return TRUE;
|
||||
}
|
||||
if (response == UWM_IDENTIFY_INSTANCES) {
|
||||
HWND* target = (HWND*)lParam;
|
||||
*target = hWnd;
|
||||
return FALSE; // Found; terminate search.
|
||||
}
|
||||
return TRUE; // Not found; continue search.
|
||||
}
|
||||
#endif
|
||||
#include "MainWindow.h"
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
QString applicationName = "High Fidelity Interface - " + qgetenv("USERNAME");
|
||||
|
||||
bool instanceMightBeRunning = true;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
// Run only one instance of Interface at a time.
|
||||
HANDLE mutex = CreateMutex(NULL, FALSE, "High Fidelity Interface - " + qgetenv("USERNAME"));
|
||||
DWORD result = GetLastError();
|
||||
if (result == ERROR_ALREADY_EXISTS || result == ERROR_ACCESS_DENIED) {
|
||||
// Interface is already running.
|
||||
HWND otherInstance = NULL;
|
||||
EnumWindows(enumWindowsCallback, (LPARAM)&otherInstance);
|
||||
if (otherInstance) {
|
||||
// Show other instance.
|
||||
SendMessage(otherInstance, UWM_SHOW_APPLICATION, 0, 0);
|
||||
// Try to create a shared memory block - if it can't be created, there is an instance of
|
||||
// interface already running. We only do this on Windows for now because of the potential
|
||||
// for crashed instances to leave behind shared memory instances on unix.
|
||||
QSharedMemory sharedMemory { applicationName };
|
||||
instanceMightBeRunning = !sharedMemory.create(1, QSharedMemory::ReadOnly);
|
||||
#endif
|
||||
|
||||
// Send command line --url value to other instance.
|
||||
if (argc >= 3) {
|
||||
QStringList arguments;
|
||||
for (int i = 0; i < argc; i += 1) {
|
||||
arguments << argv[i];
|
||||
}
|
||||
if (instanceMightBeRunning) {
|
||||
// Try to connect and send message to existing interface instance
|
||||
QLocalSocket socket;
|
||||
|
||||
QCommandLineParser parser;
|
||||
QCommandLineOption urlOption("url", "", "value");
|
||||
parser.addOption(urlOption);
|
||||
parser.process(arguments);
|
||||
socket.connectToServer(applicationName);
|
||||
|
||||
if (parser.isSet(urlOption)) {
|
||||
QUrl url = QUrl(parser.value(urlOption));
|
||||
if (url.isValid() && url.scheme() == HIFI_URL_SCHEME) {
|
||||
QByteArray urlBytes = url.toString().toLatin1();
|
||||
const char* urlChars = urlBytes.data();
|
||||
COPYDATASTRUCT cds;
|
||||
cds.cbData = urlBytes.length() + 1;
|
||||
cds.lpData = (PVOID)urlChars;
|
||||
SendMessage(otherInstance, WM_COPYDATA, 0, (LPARAM)&cds);
|
||||
static const int LOCAL_SERVER_TIMEOUT_MS = 500;
|
||||
|
||||
// Try to connect - if we can't connect, interface has probably just gone down
|
||||
if (socket.waitForConnected(LOCAL_SERVER_TIMEOUT_MS)) {
|
||||
|
||||
QStringList arguments;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
arguments << argv[i];
|
||||
}
|
||||
|
||||
QCommandLineParser parser;
|
||||
QCommandLineOption urlOption("url", "", "value");
|
||||
parser.addOption(urlOption);
|
||||
parser.process(arguments);
|
||||
|
||||
if (parser.isSet(urlOption)) {
|
||||
QUrl url = QUrl(parser.value(urlOption));
|
||||
if (url.isValid() && url.scheme() == HIFI_URL_SCHEME) {
|
||||
qDebug() << "Writing URL to local socket";
|
||||
socket.write(url.toString().toUtf8());
|
||||
if (!socket.waitForBytesWritten(5000)) {
|
||||
qDebug() << "Error writing URL to local socket";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
socket.close();
|
||||
|
||||
qDebug() << "Interface instance appears to be running, exiting";
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
return EXIT_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
QElapsedTimer startupTime;
|
||||
startupTime.start();
|
||||
|
||||
// Debug option to demonstrate that the client's local time does not
|
||||
// need to be in sync with any other network node. This forces clock
|
||||
|
||||
// Debug option to demonstrate that the client's local time does not
|
||||
// need to be in sync with any other network node. This forces clock
|
||||
// skew for the individual client
|
||||
const char* CLOCK_SKEW = "--clockSkew";
|
||||
const char* clockSkewOption = getCmdOption(argc, argv, CLOCK_SKEW);
|
||||
|
@ -102,19 +105,26 @@ int main(int argc, const char* argv[]) {
|
|||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
Application app(argc, const_cast<char**>(argv), startupTime);
|
||||
|
||||
// Setup local server
|
||||
QLocalServer server { &app };
|
||||
|
||||
// We failed to connect to a local server, so we remove any existing servers.
|
||||
server.removeServer(applicationName);
|
||||
server.listen(applicationName);
|
||||
|
||||
QObject::connect(&server, &QLocalServer::newConnection, &app, &Application::handleLocalServerConnection);
|
||||
|
||||
QTranslator translator;
|
||||
translator.load("i18n/interface_en");
|
||||
app.installTranslator(&translator);
|
||||
|
||||
|
||||
qCDebug(interfaceapp, "Created QT Application.");
|
||||
exitCode = app.exec();
|
||||
server.close();
|
||||
}
|
||||
|
||||
Application::shutdownPlugins();
|
||||
#ifdef Q_OS_WIN
|
||||
ReleaseMutex(mutex);
|
||||
#endif
|
||||
|
||||
qCDebug(interfaceapp, "Normal exit.");
|
||||
return exitCode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,9 @@
|
|||
const int SOCKET_ERROR_EXIT_CODE = 2;
|
||||
const int SOCKET_CHECK_INTERVAL_IN_MS = 30000;
|
||||
|
||||
HTTPManager::HTTPManager(quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler, QObject* parent) :
|
||||
HTTPManager::HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler, QObject* parent) :
|
||||
QTcpServer(parent),
|
||||
_listenAddress(listenAddress),
|
||||
_documentRoot(documentRoot),
|
||||
_requestHandler(requestHandler),
|
||||
_port(port)
|
||||
|
@ -178,7 +179,7 @@ void HTTPManager::isTcpServerListening() {
|
|||
bool HTTPManager::bindSocket() {
|
||||
qCDebug(embeddedwebserver) << "Attempting to bind TCP socket on port " << QString::number(_port);
|
||||
|
||||
if (listen(QHostAddress::AnyIPv4, _port)) {
|
||||
if (listen(_listenAddress, _port)) {
|
||||
qCDebug(embeddedwebserver) << "TCP socket is listening on" << serverAddress() << "and port" << serverPort();
|
||||
|
||||
return true;
|
||||
|
|
|
@ -33,7 +33,7 @@ class HTTPManager : public QTcpServer, public HTTPRequestHandler {
|
|||
Q_OBJECT
|
||||
public:
|
||||
/// Initializes the manager.
|
||||
HTTPManager(quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler = NULL, QObject* parent = 0);
|
||||
HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler = NULL, QObject* parent = 0);
|
||||
|
||||
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false);
|
||||
|
||||
|
@ -49,6 +49,7 @@ protected:
|
|||
virtual void incomingConnection(qintptr socketDescriptor);
|
||||
virtual bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url);
|
||||
|
||||
QHostAddress _listenAddress;
|
||||
QString _documentRoot;
|
||||
HTTPRequestHandler* _requestHandler;
|
||||
QTimer* _isListeningTimer;
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
|
||||
#include "HTTPSManager.h"
|
||||
|
||||
HTTPSManager::HTTPSManager(quint16 port, const QSslCertificate& certificate, const QSslKey& privateKey,
|
||||
HTTPSManager::HTTPSManager(QHostAddress listenAddress, quint16 port, const QSslCertificate& certificate, const QSslKey& privateKey,
|
||||
const QString& documentRoot, HTTPSRequestHandler* requestHandler, QObject* parent) :
|
||||
HTTPManager(port, documentRoot, requestHandler, parent),
|
||||
HTTPManager(listenAddress, port, documentRoot, requestHandler, parent),
|
||||
_certificate(certificate),
|
||||
_privateKey(privateKey),
|
||||
_sslRequestHandler(requestHandler)
|
||||
|
|
|
@ -26,7 +26,8 @@ public:
|
|||
class HTTPSManager : public HTTPManager, public HTTPSRequestHandler {
|
||||
Q_OBJECT
|
||||
public:
|
||||
HTTPSManager(quint16 port,
|
||||
HTTPSManager(QHostAddress listenAddress,
|
||||
quint16 port,
|
||||
const QSslCertificate& certificate,
|
||||
const QSslKey& privateKey,
|
||||
const QString& documentRoot,
|
||||
|
@ -35,12 +36,12 @@ public:
|
|||
void setCertificate(const QSslCertificate& certificate) { _certificate = certificate; }
|
||||
void setPrivateKey(const QSslKey& privateKey) { _privateKey = privateKey; }
|
||||
|
||||
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false);
|
||||
bool handleHTTPSRequest(HTTPSConnection* connection, const QUrl& url, bool skipSubHandler = false);
|
||||
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override;
|
||||
bool handleHTTPSRequest(HTTPSConnection* connection, const QUrl& url, bool skipSubHandler = false) override;
|
||||
|
||||
protected:
|
||||
void incomingConnection(qintptr socketDescriptor);
|
||||
bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url);
|
||||
void incomingConnection(qintptr socketDescriptor) override;
|
||||
bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url) override;
|
||||
private:
|
||||
QSslCertificate _certificate;
|
||||
QSslKey _privateKey;
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const RenderableEntityItemProxy::Pointer& payload);
|
||||
template <> const ItemKey payloadGetKey(const RenderableEntityItemProxy::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const RenderableEntityItemProxy::Pointer& payload);
|
||||
template <> void payloadRender(const RenderableEntityItemProxy::Pointer& payload, RenderArgs* args);
|
||||
}
|
||||
|
@ -73,8 +73,8 @@ private:
|
|||
|
||||
#define SIMPLE_RENDERABLE() \
|
||||
public: \
|
||||
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) { return _renderHelper.addToScene(self, scene, pendingChanges); } \
|
||||
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) { _renderHelper.removeFromScene(self, scene, pendingChanges); } \
|
||||
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override { return _renderHelper.addToScene(self, scene, pendingChanges); } \
|
||||
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override { _renderHelper.removeFromScene(self, scene, pendingChanges); } \
|
||||
private: \
|
||||
SimpleRenderableEntityItem _renderHelper;
|
||||
|
||||
|
|
|
@ -27,19 +27,19 @@ public:
|
|||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
static void createPipeline();
|
||||
RenderablePolyLineEntityItem(const EntityItemID& entityItemID);
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
|
||||
virtual void render(RenderArgs* args) override;
|
||||
virtual void update(const quint64& now) override;
|
||||
virtual bool needsToCallUpdate() const { return true; };
|
||||
|
||||
virtual bool needsToCallUpdate() const override { return true; };
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
|
||||
|
||||
NetworkTexturePointer _texture;
|
||||
|
||||
static gpu::PipelinePointer _pipeline;
|
||||
static gpu::Stream::FormatPointer _format;
|
||||
static int32_t PAINTSTROKE_GPU_SLOT;
|
||||
|
||||
|
||||
protected:
|
||||
void updateGeometry();
|
||||
void updateVertices();
|
||||
|
|
|
@ -2,6 +2,8 @@ set(TARGET_NAME networking)
|
|||
setup_hifi_library(Network)
|
||||
link_hifi_libraries(shared)
|
||||
|
||||
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes")
|
||||
|
||||
if (WIN32)
|
||||
# we need ws2_32.lib on windows, but it's static so we don't bubble it up
|
||||
target_link_libraries(${TARGET_NAME} ws2_32.lib)
|
||||
|
@ -31,4 +33,3 @@ endif (UNIX)
|
|||
|
||||
# append tbb includes to our list of includes to bubble
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${TBB_INCLUDE_DIRS})
|
||||
include_application_version()
|
||||
|
|
|
@ -12,11 +12,13 @@
|
|||
#include "udt/PacketHeaders.h"
|
||||
#include "SharedUtil.h"
|
||||
#include "UUID.h"
|
||||
#include "ServerPathUtils.h"
|
||||
|
||||
#include <QtCore/QDataStream>
|
||||
|
||||
#include <ApplicationVersion.h>
|
||||
#include <BuildInfo.h>
|
||||
#include "Assignment.h"
|
||||
#include <QtCore/QStandardPaths>
|
||||
|
||||
Assignment::Type Assignment::typeForNodeType(NodeType_t nodeType) {
|
||||
switch (nodeType) {
|
||||
|
@ -64,7 +66,7 @@ Assignment::Assignment(Assignment::Command command, Assignment::Type type, const
|
|||
// this is a newly created assignment, generate a random UUID
|
||||
_uuid = QUuid::createUuid();
|
||||
} else if (_command == Assignment::RequestCommand) {
|
||||
_nodeVersion = BUILD_VERSION;
|
||||
_nodeVersion = BuildInfo::VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -95,16 +95,16 @@ void HifiSockAddr::handleLookupResult(const QHostInfo& hostInfo) {
|
|||
if (hostInfo.error() != QHostInfo::NoError) {
|
||||
qCDebug(networking) << "Lookup failed for" << hostInfo.lookupId() << ":" << hostInfo.errorString();
|
||||
emit lookupFailed();
|
||||
}
|
||||
|
||||
foreach(const QHostAddress& address, hostInfo.addresses()) {
|
||||
// just take the first IPv4 address
|
||||
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
_address = address;
|
||||
qCDebug(networking) << "QHostInfo lookup result for"
|
||||
<< hostInfo.hostName() << "with lookup ID" << hostInfo.lookupId() << "is" << address.toString();
|
||||
emit lookupCompleted();
|
||||
break;
|
||||
} else {
|
||||
foreach(const QHostAddress& address, hostInfo.addresses()) {
|
||||
// just take the first IPv4 address
|
||||
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
_address = address;
|
||||
qCDebug(networking) << "QHostInfo lookup result for"
|
||||
<< hostInfo.hostName() << "with lookup ID" << hostInfo.lookupId() << "is" << address.toString();
|
||||
emit lookupCompleted();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
|
|||
|
||||
firstCall = false;
|
||||
}
|
||||
|
||||
|
||||
qRegisterMetaType<ConnectionStep>("ConnectionStep");
|
||||
|
||||
_nodeSocket.bind(QHostAddress::AnyIPv4, socketListenPort);
|
||||
|
@ -87,7 +87,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
|
|||
|
||||
// check the local socket right now
|
||||
updateLocalSockAddr();
|
||||
|
||||
|
||||
// set &PacketReceiver::handleVerifiedPacket as the verified packet callback for the udt::Socket
|
||||
_nodeSocket.setPacketHandler(
|
||||
[this](std::unique_ptr<udt::Packet> packet) {
|
||||
|
@ -108,8 +108,16 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
|
|||
// set our isPacketVerified method as the verify operator for the udt::Socket
|
||||
using std::placeholders::_1;
|
||||
_nodeSocket.setPacketFilterOperator(std::bind(&LimitedNodeList::isPacketVerified, this, _1));
|
||||
|
||||
|
||||
_packetStatTimer.start();
|
||||
|
||||
if (_stunSockAddr.getAddress().isNull()) {
|
||||
// we don't know the stun server socket yet, add it to unfiltered once known
|
||||
connect(&_stunSockAddr, &HifiSockAddr::lookupCompleted, this, &LimitedNodeList::addSTUNHandlerToUnfiltered);
|
||||
} else {
|
||||
// we know the stun server socket, add it to unfiltered now
|
||||
addSTUNHandlerToUnfiltered();
|
||||
}
|
||||
}
|
||||
|
||||
void LimitedNodeList::setSessionUUID(const QUuid& sessionUUID) {
|
||||
|
@ -161,42 +169,42 @@ bool LimitedNodeList::isPacketVerified(const udt::Packet& packet) {
|
|||
bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) {
|
||||
PacketType headerType = NLPacket::typeInHeader(packet);
|
||||
PacketVersion headerVersion = NLPacket::versionInHeader(packet);
|
||||
|
||||
|
||||
if (headerVersion != versionForPacketType(headerType)) {
|
||||
|
||||
|
||||
static QMultiHash<QUuid, PacketType> sourcedVersionDebugSuppressMap;
|
||||
static QMultiHash<HifiSockAddr, PacketType> versionDebugSuppressMap;
|
||||
|
||||
|
||||
bool hasBeenOutput = false;
|
||||
QString senderString;
|
||||
|
||||
|
||||
if (NON_SOURCED_PACKETS.contains(headerType)) {
|
||||
const HifiSockAddr& senderSockAddr = packet.getSenderSockAddr();
|
||||
hasBeenOutput = versionDebugSuppressMap.contains(senderSockAddr, headerType);
|
||||
|
||||
|
||||
if (!hasBeenOutput) {
|
||||
versionDebugSuppressMap.insert(senderSockAddr, headerType);
|
||||
senderString = QString("%1:%2").arg(senderSockAddr.getAddress().toString()).arg(senderSockAddr.getPort());
|
||||
}
|
||||
} else {
|
||||
QUuid sourceID = NLPacket::sourceIDInHeader(packet);
|
||||
|
||||
|
||||
hasBeenOutput = sourcedVersionDebugSuppressMap.contains(sourceID, headerType);
|
||||
|
||||
|
||||
if (!hasBeenOutput) {
|
||||
sourcedVersionDebugSuppressMap.insert(sourceID, headerType);
|
||||
senderString = uuidStringWithoutCurlyBraces(sourceID.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!hasBeenOutput) {
|
||||
qCDebug(networking) << "Packet version mismatch on" << headerType << "- Sender"
|
||||
<< senderString << "sent" << qPrintable(QString::number(headerVersion)) << "but"
|
||||
<< qPrintable(QString::number(versionForPacketType(headerType))) << "expected.";
|
||||
|
||||
|
||||
emit packetVersionMismatch(headerType);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
|
@ -204,27 +212,27 @@ bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) {
|
|||
}
|
||||
|
||||
bool LimitedNodeList::packetSourceAndHashMatch(const udt::Packet& packet) {
|
||||
|
||||
|
||||
PacketType headerType = NLPacket::typeInHeader(packet);
|
||||
|
||||
|
||||
if (NON_SOURCED_PACKETS.contains(headerType)) {
|
||||
return true;
|
||||
} else {
|
||||
QUuid sourceID = NLPacket::sourceIDInHeader(packet);
|
||||
|
||||
|
||||
// figure out which node this is from
|
||||
SharedNodePointer matchingNode = nodeWithUUID(sourceID);
|
||||
|
||||
|
||||
if (matchingNode) {
|
||||
if (!NON_VERIFIED_PACKETS.contains(headerType)) {
|
||||
|
||||
|
||||
QByteArray packetHeaderHash = NLPacket::verificationHashInHeader(packet);
|
||||
QByteArray expectedHash = NLPacket::hashForPacketAndSecret(packet, matchingNode->getConnectionSecret());
|
||||
|
||||
|
||||
// check if the md5 hash in the header matches the hash we would expect
|
||||
if (packetHeaderHash != expectedHash) {
|
||||
static QMultiMap<QUuid, PacketType> hashDebugSuppressMap;
|
||||
|
||||
|
||||
if (!hashDebugSuppressMap.contains(sourceID, headerType)) {
|
||||
qCDebug(networking) << "Packet hash mismatch on" << headerType << "- Sender" << sourceID;
|
||||
|
||||
|
@ -238,15 +246,15 @@ bool LimitedNodeList::packetSourceAndHashMatch(const udt::Packet& packet) {
|
|||
// No matter if this packet is handled or not, we update the timestamp for the last time we heard
|
||||
// from this sending node
|
||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
|
||||
} else {
|
||||
static const QString UNKNOWN_REGEX = "Packet of type \\d+ \\([\\sa-zA-Z:]+\\) received from unknown node with UUID";
|
||||
static QString repeatedMessage
|
||||
= LogHandler::getInstance().addRepeatedMessageRegex(UNKNOWN_REGEX);
|
||||
|
||||
qCDebug(networking) << "Packet of type" << headerType
|
||||
qCDebug(networking) << "Packet of type" << headerType
|
||||
<< "received from unknown node with UUID" << qPrintable(uuidStringWithoutCurlyBraces(sourceID));
|
||||
}
|
||||
}
|
||||
|
@ -264,7 +272,7 @@ void LimitedNodeList::fillPacketHeader(const NLPacket& packet, const QUuid& conn
|
|||
if (!NON_SOURCED_PACKETS.contains(packet.getType())) {
|
||||
packet.writeSourceID(getSessionUUID());
|
||||
}
|
||||
|
||||
|
||||
if (!connectionSecret.isNull()
|
||||
&& !NON_SOURCED_PACKETS.contains(packet.getType())
|
||||
&& !NON_VERIFIED_PACKETS.contains(packet.getType())) {
|
||||
|
@ -274,14 +282,14 @@ void LimitedNodeList::fillPacketHeader(const NLPacket& packet, const QUuid& conn
|
|||
|
||||
qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const Node& destinationNode) {
|
||||
Q_ASSERT(!packet.isPartOfMessage());
|
||||
|
||||
|
||||
if (!destinationNode.getActiveSocket()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
emit dataSent(destinationNode.getType(), packet.getDataSize());
|
||||
destinationNode.recordBytesSent(packet.getDataSize());
|
||||
|
||||
|
||||
return sendUnreliablePacket(packet, *destinationNode.getActiveSocket(), destinationNode.getConnectionSecret());
|
||||
}
|
||||
|
||||
|
@ -290,21 +298,21 @@ qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const HifiS
|
|||
Q_ASSERT(!packet.isPartOfMessage());
|
||||
Q_ASSERT_X(!packet.isReliable(), "LimitedNodeList::sendUnreliablePacket",
|
||||
"Trying to send a reliable packet unreliably.");
|
||||
|
||||
|
||||
collectPacketStats(packet);
|
||||
fillPacketHeader(packet, connectionSecret);
|
||||
|
||||
|
||||
return _nodeSocket.writePacket(packet, sockAddr);
|
||||
}
|
||||
|
||||
qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const Node& destinationNode) {
|
||||
Q_ASSERT(!packet->isPartOfMessage());
|
||||
auto activeSocket = destinationNode.getActiveSocket();
|
||||
|
||||
|
||||
if (activeSocket) {
|
||||
emit dataSent(destinationNode.getType(), packet->getDataSize());
|
||||
destinationNode.recordBytesSent(packet->getDataSize());
|
||||
|
||||
|
||||
return sendPacket(std::move(packet), *activeSocket, destinationNode.getConnectionSecret());
|
||||
} else {
|
||||
qDebug() << "LimitedNodeList::sendPacket called without active socket for node" << destinationNode << "- not sending";
|
||||
|
@ -318,10 +326,10 @@ qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const HifiS
|
|||
if (packet->isReliable()) {
|
||||
collectPacketStats(*packet);
|
||||
fillPacketHeader(*packet, connectionSecret);
|
||||
|
||||
|
||||
auto size = packet->getDataSize();
|
||||
_nodeSocket.writePacket(std::move(packet), sockAddr);
|
||||
|
||||
|
||||
return size;
|
||||
} else {
|
||||
return sendUnreliablePacket(*packet, sockAddr, connectionSecret);
|
||||
|
@ -330,18 +338,18 @@ qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const HifiS
|
|||
|
||||
qint64 LimitedNodeList::sendPacketList(NLPacketList& packetList, const Node& destinationNode) {
|
||||
auto activeSocket = destinationNode.getActiveSocket();
|
||||
|
||||
|
||||
if (activeSocket) {
|
||||
qint64 bytesSent = 0;
|
||||
auto connectionSecret = destinationNode.getConnectionSecret();
|
||||
|
||||
|
||||
// close the last packet in the list
|
||||
packetList.closeCurrentPacket();
|
||||
|
||||
|
||||
while (!packetList._packets.empty()) {
|
||||
bytesSent += sendPacket(packetList.takeFront<NLPacket>(), *activeSocket, connectionSecret);
|
||||
}
|
||||
|
||||
|
||||
emit dataSent(destinationNode.getType(), bytesSent);
|
||||
return bytesSent;
|
||||
} else {
|
||||
|
@ -354,21 +362,21 @@ qint64 LimitedNodeList::sendPacketList(NLPacketList& packetList, const Node& des
|
|||
qint64 LimitedNodeList::sendPacketList(NLPacketList& packetList, const HifiSockAddr& sockAddr,
|
||||
const QUuid& connectionSecret) {
|
||||
qint64 bytesSent = 0;
|
||||
|
||||
|
||||
// close the last packet in the list
|
||||
packetList.closeCurrentPacket();
|
||||
|
||||
|
||||
while (!packetList._packets.empty()) {
|
||||
bytesSent += sendPacket(packetList.takeFront<NLPacket>(), sockAddr, connectionSecret);
|
||||
}
|
||||
|
||||
|
||||
return bytesSent;
|
||||
}
|
||||
|
||||
qint64 LimitedNodeList::sendPacketList(std::unique_ptr<NLPacketList> packetList, const HifiSockAddr& sockAddr) {
|
||||
// close the last packet in the list
|
||||
packetList->closeCurrentPacket();
|
||||
|
||||
|
||||
for (std::unique_ptr<udt::Packet>& packet : packetList->_packets) {
|
||||
NLPacket* nlPacket = static_cast<NLPacket*>(packet.get());
|
||||
collectPacketStats(*nlPacket);
|
||||
|
@ -383,13 +391,13 @@ qint64 LimitedNodeList::sendPacketList(std::unique_ptr<NLPacketList> packetList,
|
|||
if (activeSocket) {
|
||||
// close the last packet in the list
|
||||
packetList->closeCurrentPacket();
|
||||
|
||||
|
||||
for (std::unique_ptr<udt::Packet>& packet : packetList->_packets) {
|
||||
NLPacket* nlPacket = static_cast<NLPacket*>(packet.get());
|
||||
collectPacketStats(*nlPacket);
|
||||
fillPacketHeader(*nlPacket, destinationNode.getConnectionSecret());
|
||||
}
|
||||
|
||||
|
||||
return _nodeSocket.writePacketList(std::move(packetList), *activeSocket);
|
||||
} else {
|
||||
qCDebug(networking) << "LimitedNodeList::sendPacketList called without active socket for node. Not sending.";
|
||||
|
@ -403,11 +411,11 @@ qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const Node&
|
|||
qCDebug(networking) << "LimitedNodeList::sendPacket called without active socket for node. Not sending.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// use the node's active socket as the destination socket if there is no overriden socket address
|
||||
auto& destinationSockAddr = (overridenSockAddr.isNull()) ? *destinationNode.getActiveSocket()
|
||||
: overridenSockAddr;
|
||||
|
||||
|
||||
return sendPacket(std::move(packet), destinationSockAddr, destinationNode.getConnectionSecret());
|
||||
}
|
||||
|
||||
|
@ -423,7 +431,7 @@ int LimitedNodeList::updateNodeWithDataFromPacket(QSharedPointer<ReceivedMessage
|
|||
QMutexLocker linkedDataLocker(&linkedData->getMutex());
|
||||
return linkedData->parseData(*message);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -453,7 +461,7 @@ void LimitedNodeList::eraseAllNodes() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach(const SharedNodePointer& killedNode, killedNodes) {
|
||||
handleNodeKill(killedNode);
|
||||
}
|
||||
|
@ -461,7 +469,7 @@ void LimitedNodeList::eraseAllNodes() {
|
|||
|
||||
void LimitedNodeList::reset() {
|
||||
eraseAllNodes();
|
||||
|
||||
|
||||
// we need to make sure any socket connections are gone so wait on that here
|
||||
_nodeSocket.clearConnections();
|
||||
}
|
||||
|
@ -474,16 +482,16 @@ bool LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) {
|
|||
SharedNodePointer matchingNode = it->second;
|
||||
|
||||
readLocker.unlock();
|
||||
|
||||
|
||||
{
|
||||
QWriteLocker writeLocker(&_nodeMutex);
|
||||
_nodeHash.unsafe_erase(it);
|
||||
}
|
||||
|
||||
|
||||
handleNodeKill(matchingNode);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -499,7 +507,7 @@ void LimitedNodeList::handleNodeKill(const SharedNodePointer& node) {
|
|||
qCDebug(networking) << "Killed" << *node;
|
||||
node->stopPingTimer();
|
||||
emit nodeKilled(node);
|
||||
|
||||
|
||||
if (auto activeSocket = node->getActiveSocket()) {
|
||||
_nodeSocket.cleanupConnection(*activeSocket);
|
||||
}
|
||||
|
@ -553,9 +561,9 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
|
|||
|
||||
std::unique_ptr<NLPacket> LimitedNodeList::constructPingPacket(PingType_t pingType) {
|
||||
int packetSize = sizeof(PingType_t) + sizeof(quint64);
|
||||
|
||||
|
||||
auto pingPacket = NLPacket::create(PacketType::Ping, packetSize);
|
||||
|
||||
|
||||
pingPacket->writePrimitive(pingType);
|
||||
pingPacket->writePrimitive(usecTimestampNow());
|
||||
|
||||
|
@ -605,14 +613,14 @@ std::unique_ptr<NLPacket> LimitedNodeList::constructICEPingReplyPacket(ReceivedM
|
|||
|
||||
unsigned int LimitedNodeList::broadcastToNodes(std::unique_ptr<NLPacket> packet, const NodeSet& destinationNodeTypes) {
|
||||
unsigned int n = 0;
|
||||
|
||||
|
||||
eachNode([&](const SharedNodePointer& node){
|
||||
if (node && destinationNodeTypes.contains(node->getType())) {
|
||||
sendUnreliablePacket(*packet, *node);
|
||||
++n;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -664,46 +672,48 @@ const int NUM_BYTES_STUN_HEADER = 20;
|
|||
|
||||
void LimitedNodeList::sendSTUNRequest() {
|
||||
|
||||
const int NUM_INITIAL_STUN_REQUESTS_BEFORE_FAIL = 10;
|
||||
if (!_stunSockAddr.isNull()) {
|
||||
const int NUM_INITIAL_STUN_REQUESTS_BEFORE_FAIL = 10;
|
||||
|
||||
if (!_hasCompletedInitialSTUN) {
|
||||
qCDebug(networking) << "Sending intial stun request to" << STUN_SERVER_HOSTNAME;
|
||||
if (!_hasCompletedInitialSTUN) {
|
||||
qCDebug(networking) << "Sending intial stun request to" << STUN_SERVER_HOSTNAME;
|
||||
|
||||
if (_numInitialSTUNRequests > NUM_INITIAL_STUN_REQUESTS_BEFORE_FAIL) {
|
||||
// we're still trying to do our initial STUN we're over the fail threshold
|
||||
stopInitialSTUNUpdate(false);
|
||||
if (_numInitialSTUNRequests > NUM_INITIAL_STUN_REQUESTS_BEFORE_FAIL) {
|
||||
// we're still trying to do our initial STUN we're over the fail threshold
|
||||
stopInitialSTUNUpdate(false);
|
||||
}
|
||||
|
||||
++_numInitialSTUNRequests;
|
||||
}
|
||||
|
||||
++_numInitialSTUNRequests;
|
||||
char stunRequestPacket[NUM_BYTES_STUN_HEADER];
|
||||
|
||||
int packetIndex = 0;
|
||||
|
||||
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
|
||||
|
||||
// leading zeros + message type
|
||||
const uint16_t REQUEST_MESSAGE_TYPE = htons(0x0001);
|
||||
memcpy(stunRequestPacket + packetIndex, &REQUEST_MESSAGE_TYPE, sizeof(REQUEST_MESSAGE_TYPE));
|
||||
packetIndex += sizeof(REQUEST_MESSAGE_TYPE);
|
||||
|
||||
// message length (no additional attributes are included)
|
||||
uint16_t messageLength = 0;
|
||||
memcpy(stunRequestPacket + packetIndex, &messageLength, sizeof(messageLength));
|
||||
packetIndex += sizeof(messageLength);
|
||||
|
||||
memcpy(stunRequestPacket + packetIndex, &RFC_5389_MAGIC_COOKIE_NETWORK_ORDER, sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER));
|
||||
packetIndex += sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
||||
|
||||
// transaction ID (random 12-byte unsigned integer)
|
||||
const uint NUM_TRANSACTION_ID_BYTES = 12;
|
||||
QUuid randomUUID = QUuid::createUuid();
|
||||
memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES);
|
||||
|
||||
flagTimeForConnectionStep(ConnectionStep::SendSTUNRequest);
|
||||
|
||||
_nodeSocket.writeDatagram(stunRequestPacket, sizeof(stunRequestPacket), _stunSockAddr);
|
||||
}
|
||||
|
||||
char stunRequestPacket[NUM_BYTES_STUN_HEADER];
|
||||
|
||||
int packetIndex = 0;
|
||||
|
||||
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
|
||||
|
||||
// leading zeros + message type
|
||||
const uint16_t REQUEST_MESSAGE_TYPE = htons(0x0001);
|
||||
memcpy(stunRequestPacket + packetIndex, &REQUEST_MESSAGE_TYPE, sizeof(REQUEST_MESSAGE_TYPE));
|
||||
packetIndex += sizeof(REQUEST_MESSAGE_TYPE);
|
||||
|
||||
// message length (no additional attributes are included)
|
||||
uint16_t messageLength = 0;
|
||||
memcpy(stunRequestPacket + packetIndex, &messageLength, sizeof(messageLength));
|
||||
packetIndex += sizeof(messageLength);
|
||||
|
||||
memcpy(stunRequestPacket + packetIndex, &RFC_5389_MAGIC_COOKIE_NETWORK_ORDER, sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER));
|
||||
packetIndex += sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
||||
|
||||
// transaction ID (random 12-byte unsigned integer)
|
||||
const uint NUM_TRANSACTION_ID_BYTES = 12;
|
||||
QUuid randomUUID = QUuid::createUuid();
|
||||
memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES);
|
||||
|
||||
flagTimeForConnectionStep(ConnectionStep::SendSTUNRequest);
|
||||
|
||||
_nodeSocket.writeDatagram(stunRequestPacket, sizeof(stunRequestPacket), _stunSockAddr);
|
||||
}
|
||||
|
||||
void LimitedNodeList::processSTUNResponse(std::unique_ptr<udt::BasePacket> packet) {
|
||||
|
@ -722,7 +732,7 @@ void LimitedNodeList::processSTUNResponse(std::unique_ptr<udt::BasePacket> packe
|
|||
|
||||
// enumerate the attributes to find XOR_MAPPED_ADDRESS_TYPE
|
||||
while (attributeStartIndex < packet->getDataSize()) {
|
||||
|
||||
|
||||
if (memcmp(packet->getData() + attributeStartIndex, &XOR_MAPPED_ADDRESS_TYPE, sizeof(XOR_MAPPED_ADDRESS_TYPE)) == 0) {
|
||||
const int NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH = 4;
|
||||
const int NUM_BYTES_FAMILY_ALIGN = 1;
|
||||
|
@ -751,7 +761,7 @@ void LimitedNodeList::processSTUNResponse(std::unique_ptr<udt::BasePacket> packe
|
|||
uint32_t stunAddress = ntohl(xorMappedAddress) ^ ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
||||
|
||||
QHostAddress newPublicAddress(stunAddress);
|
||||
|
||||
|
||||
if (newPublicAddress != _publicSockAddr.getAddress() || newPublicPort != _publicSockAddr.getPort()) {
|
||||
_publicSockAddr = HifiSockAddr(newPublicAddress, newPublicPort);
|
||||
|
||||
|
@ -768,7 +778,7 @@ void LimitedNodeList::processSTUNResponse(std::unique_ptr<udt::BasePacket> packe
|
|||
|
||||
flagTimeForConnectionStep(ConnectionStep::SetPublicSocketFromSTUN);
|
||||
}
|
||||
|
||||
|
||||
// we're done reading the packet so we can return now
|
||||
return;
|
||||
}
|
||||
|
@ -788,38 +798,50 @@ void LimitedNodeList::processSTUNResponse(std::unique_ptr<udt::BasePacket> packe
|
|||
}
|
||||
|
||||
void LimitedNodeList::startSTUNPublicSocketUpdate() {
|
||||
assert(!_initialSTUNTimer);
|
||||
if (!_initialSTUNTimer ) {
|
||||
// setup our initial STUN timer here so we can quickly find out our public IP address
|
||||
_initialSTUNTimer = new QTimer { this };
|
||||
|
||||
if (!_initialSTUNTimer) {
|
||||
// if we don't know the STUN IP yet we need to have ourselves be called once it is known
|
||||
connect(_initialSTUNTimer.data(), &QTimer::timeout, this, &LimitedNodeList::sendSTUNRequest);
|
||||
|
||||
const int STUN_INITIAL_UPDATE_INTERVAL_MSECS = 250;
|
||||
_initialSTUNTimer->setInterval(STUN_INITIAL_UPDATE_INTERVAL_MSECS);
|
||||
|
||||
// if we don't know the STUN IP yet we need to wait until it is known to start STUN requests
|
||||
if (_stunSockAddr.getAddress().isNull()) {
|
||||
connect(&_stunSockAddr, &HifiSockAddr::lookupCompleted, this, &LimitedNodeList::startSTUNPublicSocketUpdate);
|
||||
connect(&_stunSockAddr, &HifiSockAddr::lookupCompleted, this, &LimitedNodeList::addSTUNHandlerToUnfiltered);
|
||||
|
||||
// in case we just completely fail to lookup the stun socket - add a 10s timeout that will trigger the fail case
|
||||
// if we fail to lookup the socket then timeout the STUN address lookup
|
||||
connect(&_stunSockAddr, &HifiSockAddr::lookupFailed, this, &LimitedNodeList::possiblyTimeoutSTUNAddressLookup);
|
||||
|
||||
// immediately send a STUN request once we know the socket
|
||||
connect(&_stunSockAddr, &HifiSockAddr::lookupCompleted, this, &LimitedNodeList::sendSTUNRequest);
|
||||
|
||||
// start the initial STUN timer once we know the socket
|
||||
connect(&_stunSockAddr, SIGNAL(lookupCompleted()), _initialSTUNTimer, SLOT(start()));
|
||||
|
||||
// in case we just completely fail to lookup the stun socket - add a 10s single shot that will trigger the fail case
|
||||
const quint64 STUN_DNS_LOOKUP_TIMEOUT_MSECS = 10 * 1000;
|
||||
|
||||
QTimer* stunLookupFailTimer = new QTimer(this);
|
||||
connect(stunLookupFailTimer, &QTimer::timeout, this, &LimitedNodeList::possiblyTimeoutSTUNAddressLookup);
|
||||
stunLookupFailTimer->start(STUN_DNS_LOOKUP_TIMEOUT_MSECS);
|
||||
QTimer* lookupTimeoutTimer = new QTimer { this };
|
||||
lookupTimeoutTimer->setSingleShot(true);
|
||||
|
||||
connect(lookupTimeoutTimer, &QTimer::timeout, this, &LimitedNodeList::possiblyTimeoutSTUNAddressLookup);
|
||||
|
||||
// delete the lookup timeout timer once it has fired
|
||||
connect(lookupTimeoutTimer, &QTimer::timeout, lookupTimeoutTimer, &QTimer::deleteLater);
|
||||
|
||||
lookupTimeoutTimer->start(STUN_DNS_LOOKUP_TIMEOUT_MSECS);
|
||||
} else {
|
||||
// setup our initial STUN timer here so we can quickly find out our public IP address
|
||||
_initialSTUNTimer = new QTimer(this);
|
||||
_initialSTUNTimer->start();
|
||||
|
||||
connect(_initialSTUNTimer.data(), &QTimer::timeout, this, &LimitedNodeList::sendSTUNRequest);
|
||||
|
||||
const int STUN_INITIAL_UPDATE_INTERVAL_MSECS = 250;
|
||||
_initialSTUNTimer->start(STUN_INITIAL_UPDATE_INTERVAL_MSECS);
|
||||
|
||||
// send an initial STUN request right away
|
||||
sendSTUNRequest();
|
||||
// send an initial STUN request right away
|
||||
sendSTUNRequest();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LimitedNodeList::possiblyTimeoutSTUNAddressLookup() {
|
||||
if (_stunSockAddr.getAddress().isNull()) {
|
||||
if (_stunSockAddr.isNull()) {
|
||||
// our stun address is still NULL, but we've been waiting for long enough - time to force a fail
|
||||
stopInitialSTUNUpdate(false);
|
||||
}
|
||||
|
@ -859,7 +881,7 @@ void LimitedNodeList::stopInitialSTUNUpdate(bool success) {
|
|||
// Or, if we failed - if will check if we can eventually get a public socket
|
||||
const int STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS = 30 * 1000;
|
||||
|
||||
QTimer* stunOccasionalTimer = new QTimer(this);
|
||||
QTimer* stunOccasionalTimer = new QTimer { this };
|
||||
connect(stunOccasionalTimer, &QTimer::timeout, this, &LimitedNodeList::sendSTUNRequest);
|
||||
|
||||
stunOccasionalTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS);
|
||||
|
@ -904,7 +926,7 @@ void LimitedNodeList::sendPacketToIceServer(PacketType packetType, const HifiSoc
|
|||
|
||||
QDataStream iceDataStream(icePacket.get());
|
||||
iceDataStream << clientID << _publicSockAddr << _localSockAddr;
|
||||
|
||||
|
||||
if (packetType == PacketType::ICEServerQuery) {
|
||||
assert(!peerID.isNull());
|
||||
|
||||
|
|
|
@ -293,6 +293,7 @@ protected:
|
|||
bool _thisNodeCanRez;
|
||||
|
||||
QPointer<QTimer> _initialSTUNTimer;
|
||||
|
||||
int _numInitialSTUNRequests = 0;
|
||||
bool _hasCompletedInitialSTUN = false;
|
||||
quint64 _firstSTUNTime = 0;
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <QtCore/QThread>
|
||||
#include <QtNetwork/QHostInfo>
|
||||
|
||||
#include <ApplicationVersion.h>
|
||||
#include <LogHandler.h>
|
||||
#include <UUID.h>
|
||||
|
||||
|
|
|
@ -40,8 +40,8 @@ public:
|
|||
virtual void updateActionWorker(float deltaTimeStep) = 0;
|
||||
|
||||
// these are from btActionInterface
|
||||
virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep);
|
||||
virtual void debugDraw(btIDebugDraw* debugDrawer);
|
||||
virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) override;
|
||||
virtual void debugDraw(btIDebugDraw* debugDrawer) override;
|
||||
|
||||
virtual QByteArray serialize() const override = 0;
|
||||
virtual void deserialize(QByteArray serializedArguments) override = 0;
|
||||
|
|
|
@ -9,8 +9,11 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "HifiConfigVariantMap.h"
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonArray>
|
||||
|
@ -18,8 +21,8 @@
|
|||
#include <QtCore/QStandardPaths>
|
||||
#include <QtCore/QVariant>
|
||||
|
||||
#include "ServerPathUtils.h"
|
||||
#include "SharedLogging.h"
|
||||
#include "HifiConfigVariantMap.h"
|
||||
|
||||
QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringList& argumentList) {
|
||||
|
||||
|
@ -110,18 +113,54 @@ void HifiConfigVariantMap::loadMasterAndUserConfig(const QStringList& argumentLi
|
|||
|
||||
// load the user config
|
||||
const QString USER_CONFIG_FILE_OPTION = "--user-config";
|
||||
static const QString USER_CONFIG_FILE_NAME = "config.json";
|
||||
|
||||
int userConfigIndex = argumentList.indexOf(USER_CONFIG_FILE_OPTION);
|
||||
if (userConfigIndex != -1) {
|
||||
_userConfigFilename = argumentList[userConfigIndex + 1];
|
||||
} else {
|
||||
_userConfigFilename = QString("%1/%2/%3/config.json").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation),
|
||||
QCoreApplication::organizationName(),
|
||||
QCoreApplication::applicationName());
|
||||
// we weren't passed a user config path
|
||||
_userConfigFilename = ServerPathUtils::getDataFilePath(USER_CONFIG_FILE_NAME);
|
||||
|
||||
// as of 1/19/2016 this path was moved so we attempt a migration for first run post migration here
|
||||
|
||||
// figure out what the old path was
|
||||
auto oldConfigFilename = QString("%1/%2/%3/%4").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation),
|
||||
QCoreApplication::organizationName(),
|
||||
QCoreApplication::applicationName(),
|
||||
USER_CONFIG_FILE_NAME);
|
||||
|
||||
// check if there's already a config file at the new path
|
||||
QFile newConfigFile { _userConfigFilename };
|
||||
if (!newConfigFile.exists()) {
|
||||
QFile oldConfigFile { oldConfigFilename };
|
||||
|
||||
if (oldConfigFile.exists()) {
|
||||
// we have the old file and not the new file - time to copy the file
|
||||
|
||||
// make the destination directory if it doesn't exist
|
||||
auto dataDirectory = ServerPathUtils::getDataDirectory();
|
||||
if (QDir().mkpath(dataDirectory)) {
|
||||
if (oldConfigFile.copy(_userConfigFilename)) {
|
||||
qDebug() << "Migrated config file from" << oldConfigFilename << "to" << _userConfigFilename;
|
||||
} else {
|
||||
qWarning() << "Could not copy previous config file from" << oldConfigFilename << "to" << _userConfigFilename
|
||||
<< "- please try to copy manually and restart.";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Could not create application data directory" << dataDirectory << "- unable to migrate previous config file.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
loadMapFromJSONFile(_userConfig, _userConfigFilename);
|
||||
|
||||
mergeMasterAndUserConfigs();
|
||||
}
|
||||
|
||||
void HifiConfigVariantMap::mergeMasterAndUserConfigs() {
|
||||
// the merged config is initially matched to the master config
|
||||
_mergedConfig = _masterConfig;
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_HifiConfigVariantMap_h
|
||||
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVariantMap>
|
||||
|
||||
class HifiConfigVariantMap {
|
||||
public:
|
||||
|
@ -25,6 +26,8 @@ public:
|
|||
QVariantMap& getUserConfig() { return _userConfig; }
|
||||
QVariantMap& getMergedConfig() { return _mergedConfig; }
|
||||
|
||||
void mergeMasterAndUserConfigs();
|
||||
|
||||
const QString& getUserConfigFilename() const { return _userConfigFilename; }
|
||||
private:
|
||||
QString _userConfigFilename;
|
||||
|
|
|
@ -42,6 +42,8 @@ LogHandler::LogHandler() :
|
|||
|
||||
const char* stringForLogType(LogMsgType msgType) {
|
||||
switch (msgType) {
|
||||
case LogInfo:
|
||||
return "INFO";
|
||||
case LogDebug:
|
||||
return "DEBUG";
|
||||
case LogWarning:
|
||||
|
|
|
@ -22,11 +22,12 @@
|
|||
const int VERBOSE_LOG_INTERVAL_SECONDS = 5;
|
||||
|
||||
enum LogMsgType {
|
||||
LogInfo = QtInfoMsg,
|
||||
LogDebug = QtDebugMsg,
|
||||
LogWarning = QtWarningMsg,
|
||||
LogCritical = QtCriticalMsg,
|
||||
LogFatal = QtFatalMsg,
|
||||
LogSuppressed
|
||||
LogSuppressed = 100
|
||||
};
|
||||
|
||||
/// Handles custom message handling and sending of stats/logs to Logstash instance
|
||||
|
|
37
libraries/shared/src/ServerPathUtils.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// ServerPathUtils.cpp
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Ryan Huffman on 01/12/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "ServerPathUtils.h"
|
||||
|
||||
#include <QStandardPaths>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtWidgets/qapplication.h>
|
||||
#include <QDebug>
|
||||
|
||||
QString ServerPathUtils::getDataDirectory() {
|
||||
auto dataPath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
dataPath += "/AppData/Roaming/";
|
||||
#elif defined(Q_OS_OSX)
|
||||
dataPath += "/Library/Application Support/";
|
||||
#else
|
||||
dataPath += "/.local/share/";
|
||||
#endif
|
||||
|
||||
dataPath += qApp->organizationName() + "/" + qApp->applicationName();
|
||||
|
||||
return QDir::cleanPath(dataPath);
|
||||
}
|
||||
|
||||
QString ServerPathUtils::getDataFilePath(QString filename) {
|
||||
return QDir(getDataDirectory()).absoluteFilePath(filename);
|
||||
}
|
||||
|
22
libraries/shared/src/ServerPathUtils.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// ServerPathUtils.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Ryan Huffman on 01/12/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ServerPathUtils_h
|
||||
#define hifi_ServerPathUtils_h
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace ServerPathUtils {
|
||||
QString getDataDirectory();
|
||||
QString getDataFilePath(QString filename);
|
||||
}
|
||||
|
||||
#endif // hifi_ServerPathUtils_h
|
5
server-console/.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
Server\ Console-*/
|
||||
server-console-*/
|
||||
electron-packager/
|
||||
npm-debug.log
|
||||
logs/
|
71
server-console/CMakeLists.txt
Normal file
|
@ -0,0 +1,71 @@
|
|||
set(TARGET_NAME packaged-server-console)
|
||||
|
||||
if (PRODUCTION_BUILD)
|
||||
set(PRODUCTION_OPTION "--production")
|
||||
endif()
|
||||
|
||||
# add a target that will package the console
|
||||
add_custom_target(${TARGET_NAME}-npm-install
|
||||
COMMAND npm install
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
add_custom_target(${TARGET_NAME}
|
||||
COMMAND npm run packager -- --out ${CMAKE_CURRENT_BINARY_DIR} ${PRODUCTION_OPTION}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS ${TARGET_NAME}-npm-install
|
||||
)
|
||||
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Server Console")
|
||||
set_target_properties(${TARGET_NAME}-npm-install PROPERTIES FOLDER "hidden/Server Console")
|
||||
|
||||
# add a dependency from the package target to the server components
|
||||
add_dependencies(${TARGET_NAME} assignment-client domain-server)
|
||||
|
||||
# set the packaged console folder depending on platform, so we can copy it
|
||||
if (APPLE)
|
||||
set(PACKAGED_CONSOLE_FOLDER "Server\\ Console-darwin-x64/${CONSOLE_EXEC_NAME}")
|
||||
elseif (WIN32)
|
||||
set(PACKAGED_CONSOLE_FOLDER "server-console-win32-x64")
|
||||
elseif (UNIX)
|
||||
set(PACKAGED_CONSOLE_FOLDER "server-console-linux-x64")
|
||||
endif ()
|
||||
|
||||
# install the packaged Server Console in our install directory
|
||||
if (APPLE)
|
||||
install(
|
||||
PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}"
|
||||
DESTINATION ${CONSOLE_INSTALL_DIR}
|
||||
COMPONENT ${SERVER_COMPONENT}
|
||||
)
|
||||
elseif (WIN32)
|
||||
set(CONSOLE_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}")
|
||||
|
||||
install(
|
||||
DIRECTORY "${CONSOLE_DESTINATION}/"
|
||||
DESTINATION ${CONSOLE_INSTALL_DIR}
|
||||
COMPONENT ${SERVER_COMPONENT}
|
||||
)
|
||||
|
||||
# sign the copied server console executable after install
|
||||
set(EXECUTABLE_PATH "${CONSOLE_DESTINATION}/${CONSOLE_EXEC_NAME}")
|
||||
optional_win_executable_signing()
|
||||
endif()
|
||||
|
||||
if (PR_BUILD OR PRODUCTION_BUILD)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL FALSE EXCLUDE_FROM_DEFAULT_BUILD FALSE)
|
||||
|
||||
if (APPLE)
|
||||
set(BESIDE_CONSOLE_DIR "${CONSOLE_INSTALL_APP_PATH}/Contents/Resources")
|
||||
else ()
|
||||
set(BESIDE_CONSOLE_DIR ${CONSOLE_INSTALL_DIR})
|
||||
endif ()
|
||||
|
||||
# configure our build info json file and install it beside the console
|
||||
set(CONSOLE_BUILD_INFO_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build-info.json")
|
||||
configure_file("${HF_CMAKE_DIR}/templates/console-build-info.json.in" ${CONSOLE_BUILD_INFO_OUTPUT})
|
||||
install(
|
||||
FILES ${CONSOLE_BUILD_INFO_OUTPUT}
|
||||
DESTINATION ${BESIDE_CONSOLE_DIR}
|
||||
COMPONENT ${SERVER_COMPONENT}
|
||||
)
|
||||
endif ()
|
25
server-console/README.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
### Console
|
||||
|
||||
The High Fidelity Server Console, made with [Electron](http://electron.atom.io/).
|
||||
|
||||
### Running Locally
|
||||
|
||||
Make sure you have [Node.js](https://nodejs.org/en/) installed. Use the latest stable version.
|
||||
|
||||
```
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
To run, the console needs to find a build of Interface, domain-server, and assignment-client.
|
||||
|
||||
The command `npm start` tells the console to look for builds of those binaries in a build folder beside this console folder.
|
||||
|
||||
On platforms with separate build folders for release and debug libraries `npm start` will choose the debug binaries. On those platforms if you prefer to use local release builds you'll want `npm run local-release`.
|
||||
|
||||
### Packaging
|
||||
|
||||
CMake produces a target `packaged-server-console` that will bundle up everything you need for the Server Console on your platform.
|
||||
It ensures that there are available builds for the domain-server and assignment-client. Then it produces an executable for the Server Console.
|
||||
|
||||
The install target will copy all of the produced executables to a directory, ready for testing or packaging for deployment.
|
38
server-console/package.json
Normal file
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"name": "hf-console",
|
||||
"description": "High Fidelity Console",
|
||||
"author": "High Fidelity",
|
||||
"license": "Apache-2.0",
|
||||
"version": "1.0.0",
|
||||
"keywords": [
|
||||
""
|
||||
],
|
||||
"devDependencies": {
|
||||
"electron-compilers": "^1.0.1",
|
||||
"electron-packager": "^5.2.1",
|
||||
"electron-prebuilt": "0.35.4"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/highfidelity/hifi.git"
|
||||
},
|
||||
"main": "src/main.js",
|
||||
"scripts": {
|
||||
"start": "electron . --binary-type local-debug --debug",
|
||||
"local-release": "electron . --binary-type local-release --debug",
|
||||
"local-release-no-debug": "electron . --binary-type local-release",
|
||||
"packager": "node packager.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"always-tail": "0.2.0",
|
||||
"cheerio": "^0.19.0",
|
||||
"extend": "^3.0.0",
|
||||
"fs-extra": "^0.26.4",
|
||||
"node-notifier": "^4.4.0",
|
||||
"os-homedir": "^1.0.1",
|
||||
"request": "2.67.0",
|
||||
"request-progress": "1.0.2",
|
||||
"unzip": "0.1.11",
|
||||
"yargs": "^3.30.0"
|
||||
}
|
||||
}
|
59
server-console/packager.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
var packager = require('electron-packager')
|
||||
var osType = require('os').type();
|
||||
|
||||
var platform = null;
|
||||
if (osType == "Darwin" || osType == "Linux") {
|
||||
platform = osType.toLowerCase();
|
||||
} else if (osType == "Windows_NT") {
|
||||
platform = "win32"
|
||||
}
|
||||
|
||||
var argv = require('yargs').argv;
|
||||
|
||||
// check which icon we should use, beta or regular
|
||||
var iconName = argv.production ? "console" : "console-beta";
|
||||
|
||||
// setup the common options for the packager
|
||||
var options = {
|
||||
dir: __dirname,
|
||||
name: "server-console",
|
||||
version: "0.35.4",
|
||||
overwrite: true,
|
||||
prune: true,
|
||||
arch: "x64",
|
||||
platform: platform,
|
||||
icon: "resources/" + iconName,
|
||||
ignore: "logs|(S|s)erver(\\s|-)(C|c)onsole-\\S+|electron-packager|README.md|CMakeLists.txt|packager.js|.gitignore"
|
||||
}
|
||||
|
||||
const EXEC_NAME = "server-console";
|
||||
const SHORT_NAME = "Server Console";
|
||||
const FULL_NAME = "High Fidelity Server Console";
|
||||
|
||||
// setup per OS options
|
||||
if (osType == "Darwin") {
|
||||
options["app-bundle-id"] = "com.highfidelity.server-console" + (argv.production ? "" : "-dev")
|
||||
options["name"] = SHORT_NAME
|
||||
} else if (osType == "Windows_NT") {
|
||||
options["version-string"] = {
|
||||
CompanyName: "High Fidelity, Inc.",
|
||||
FileDescription: SHORT_NAME,
|
||||
ProductName: FULL_NAME,
|
||||
OriginalFilename: EXEC_NAME + ".exe"
|
||||
}
|
||||
}
|
||||
|
||||
// check if we were passed a custom out directory, pass it along if so
|
||||
if (argv.out) {
|
||||
options.out = argv.out
|
||||
}
|
||||
|
||||
// call the packager to produce the executable
|
||||
packager(options, function(error, appPath) {
|
||||
if (error) {
|
||||
console.error("There was an error writing the packaged console: " + error.message);
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log("Wrote new app to " + appPath);
|
||||
}
|
||||
});
|
BIN
server-console/resources/console-beta.icns
Normal file
BIN
server-console/resources/console-beta.ico
Normal file
After Width: | Height: | Size: 61 KiB |
BIN
server-console/resources/console-beta.png
Normal file
After Width: | Height: | Size: 320 KiB |
BIN
server-console/resources/console-notification.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
server-console/resources/console-tray-Template.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
server-console/resources/console-tray-Template@2x.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
server-console/resources/console-tray.ico
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
server-console/resources/console-tray.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
server-console/resources/console-tray@2x.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
server-console/resources/console.icns
Normal file
BIN
server-console/resources/console.ico
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
server-console/resources/console.png
Normal file
After Width: | Height: | Size: 271 KiB |
145
server-console/src/downloader.css
Normal file
|
@ -0,0 +1,145 @@
|
|||
@font-face {
|
||||
font-family: 'Raleway';
|
||||
src: url('vendor/Raleway/Raleway-Regular.ttf');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Raleway';
|
||||
src: url('vendor/Raleway/Raleway-ExtraLight.ttf');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Raleway';
|
||||
src: url('vendor/Raleway/Raleway-SemiBold.ttf');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
||||
* {
|
||||
font-family: "Raleway", "Open Sans", Arial, Helvetica, sans-serif;
|
||||
line-height: 130%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #808785;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
font-size: 13.5pt;
|
||||
-webkit-touch-callout: none; -webkit-user-select: none;
|
||||
cursor: default;
|
||||
overflow: hidden;
|
||||
font-variant-numeric: lining-nums;
|
||||
-moz-font-feature-settings: "lnum";
|
||||
-webkit-font-feature-settings: "lnum";
|
||||
font-feature-settings: "lnum";
|
||||
}
|
||||
|
||||
#error-message {
|
||||
background-color: #F7F8F8;
|
||||
color: #EB4C5F;
|
||||
padding: 20px;
|
||||
margin: 20px 120px 0 120px;
|
||||
}
|
||||
|
||||
.selectable {
|
||||
-webkit-touch-callout: text;
|
||||
-webkit-user-select: text;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
progress {
|
||||
height: 1px;
|
||||
width: 300px;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
progress[value]::-webkit-progress-bar {
|
||||
background-color: #DADADA;
|
||||
/* border-radius: 2px; */
|
||||
}
|
||||
|
||||
progress[value]::-webkit-progress-value {
|
||||
background-color: #21B7D4;
|
||||
/* border-radius: 2px; */
|
||||
}
|
||||
|
||||
#progress-bytes {
|
||||
font-weight: lighter;
|
||||
color: #BBBBBB;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#download-summary {
|
||||
margin-top: 80px;
|
||||
}
|
||||
|
||||
.state {
|
||||
padding-top: 100px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 29pt;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
#cancel-area {
|
||||
margin-top: 100px;
|
||||
}
|
||||
|
||||
a:link,
|
||||
a:visited,
|
||||
a:hover,
|
||||
a:active {
|
||||
color: #B4B4B4;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #2D88A4;
|
||||
}
|
||||
|
||||
.one {
|
||||
opacity: 0;
|
||||
animation: dot 2.3s infinite;
|
||||
animation-delay: 0.0s;
|
||||
}
|
||||
|
||||
.two {
|
||||
opacity: 0;
|
||||
animation: dot 2.3s infinite;
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.three {
|
||||
opacity: 0;
|
||||
animation: dot 2.3s infinite;
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes dot {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dot {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
34
server-console/src/downloader.html
Normal file
|
@ -0,0 +1,34 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>High Fidelity</title>
|
||||
<script src="downloader.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="downloader.css"></link>
|
||||
</head>
|
||||
<body onload="ready()">
|
||||
<div id="state-downloading" class="state">
|
||||
<h1>Downloading<span class="one">.</span><span class="two">.</span><span class="three">.</span></h1>
|
||||
<progress max="100" value="80" id="download-progress"></progress>
|
||||
<div id="progress-bytes">10 MB / 4.0 MB</div>
|
||||
<div id="download-summary">
|
||||
Sit tight, we are downloading content for your home
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="state-installing" class="state">
|
||||
<h1>Installing<span class="one">.</span><span class="two">.</span><span class="three">.</span></h1>
|
||||
<em>Just a moment</em>
|
||||
</div>
|
||||
|
||||
<div id="state-complete" class="state">
|
||||
<h1>Success!</h1>
|
||||
<em>You're all set.</em>
|
||||
</div>
|
||||
|
||||
<div id="state-error" class="state">
|
||||
<h1>Houston...</h1>
|
||||
<em>An unfortunate error has occurred:</em>
|
||||
<div id="error-message" class="selectable">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
52
server-console/src/downloader.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
function ready() {
|
||||
console.log("Ready");
|
||||
|
||||
const electron = require('electron');
|
||||
const remote = require('remote');
|
||||
window.$ = require('./vendor/jquery/jquery-2.1.4.min.js');
|
||||
|
||||
$(".state").hide();
|
||||
|
||||
var currentState = null;
|
||||
|
||||
function updateState(state, args) {
|
||||
if (state == 'downloading') {
|
||||
function formatBytes(size) {
|
||||
return (size / 1000000).toFixed('2');
|
||||
}
|
||||
$('#download-progress').attr('value', args.percentage * 100);
|
||||
if (args.size !== null && args.size.transferred !== null && args.size.total !== null) {
|
||||
var progressString = formatBytes(args.size.transferred) + "MB / " + formatBytes(args.size.total) + "MB";
|
||||
$('#progress-bytes').html(progressString);
|
||||
} else {
|
||||
$('#progress-bytes').html("Retrieving resources...");
|
||||
}
|
||||
} else if (state == 'installing') {
|
||||
} else if (state == 'complete') {
|
||||
setTimeout(function() {
|
||||
remote.getCurrentWindow().close();
|
||||
}, 2000);
|
||||
} else if (state == 'error') {
|
||||
$('#error-message').html(args.message);
|
||||
}
|
||||
|
||||
if (currentState != state) {
|
||||
if (currentState) {
|
||||
$('#state-' + currentState).hide();
|
||||
}
|
||||
$('#state-' + state).show();
|
||||
currentState = state;
|
||||
}
|
||||
}
|
||||
|
||||
electron.ipcRenderer.on('update', function(event, message) {
|
||||
updateState(message.state, message.args);
|
||||
});
|
||||
|
||||
// updateState('error', { message: "This is an error message", progress: 0.5 });
|
||||
// updateState('complete', { progress: 0 });
|
||||
// updateState('downloading', { percentage: 0.5, size: { total: 83040400, transferred: 500308} });
|
||||
|
||||
updateState('downloading', { percentage: 0, size: null });
|
||||
electron.ipcRenderer.send('ready');
|
||||
}
|
BIN
server-console/src/images/console-hf-logo-2x.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
server-console/src/images/console-menubar-osx-2x.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
server-console/src/images/console-menubar-windows-2x.png
Normal file
After Width: | Height: | Size: 52 KiB |
87
server-console/src/log.css
Normal file
|
@ -0,0 +1,87 @@
|
|||
@font-face {
|
||||
font-family: 'Raleway';
|
||||
src: url('vendor/Raleway/Raleway-Regular.ttf');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Raleway';
|
||||
src: url('vendor/Raleway/Raleway-ExtraLight.ttf');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Raleway';
|
||||
src: url('vendor/Raleway/Raleway-SemiBold.ttf');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Raleway", "Open Sans", Arial, Helvetica, sans-serif;
|
||||
font-size: 13.5pt;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-variant-numeric: lining-nums;
|
||||
-moz-font-feature-settings: "lnum";
|
||||
-webkit-font-feature-settings: "lnum";
|
||||
font-feature-settings: "lnum";
|
||||
}
|
||||
|
||||
ul.tabs {
|
||||
margin: 0;
|
||||
padding: 0px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
ul.tabs li {
|
||||
background: none;
|
||||
color: #222;
|
||||
display: inline-block;
|
||||
padding: 10px 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
ul.tabs li.current {
|
||||
background-color: #ededed;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.tab-pane {
|
||||
display: none;
|
||||
background-color: #ededed;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.tab-pane.current {
|
||||
display: inherit;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
overflow: auto;
|
||||
padding: 10px;
|
||||
background-color: #ededed;
|
||||
}
|
||||
|
||||
.top {
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 45px;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.search {
|
||||
display: none;
|
||||
float: right;
|
||||
margin: 10px;
|
||||
}
|