Merge pull request #69 from huffman/console-post-demo

Console post demo
This commit is contained in:
Ryan Huffman 2016-01-19 16:08:21 -08:00
commit f22ee1925d
89 changed files with 4078 additions and 791 deletions

5
.gitignore vendored
View file

@ -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
@ -48,4 +48,5 @@ TAGS
*.swp
# ignore node files for the console
node_modules
node_modules
npm-debug.log

View file

@ -115,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.")
@ -178,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})

25
LICENSE
View file

@ -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.

View file

@ -9,5 +9,8 @@ link_hifi_libraries(
controllers physics
)
package_libraries_for_deployment()
consolidate_installer_components()
if (WIN32)
package_libraries_for_deployment()
endif()
install_beside_console()

View file

@ -12,7 +12,7 @@
#include <QCommandLineParser>
#include <QThread>
#include <ApplicationVersion.h>
#include <BuildInfo.h>
#include <LogHandler.h>
#include <SharedUtil.h>
#include <HifiConfigVariantMap.h>
@ -32,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
@ -44,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);
@ -65,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);
@ -94,6 +94,9 @@ 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);
@ -135,6 +138,11 @@ 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);
@ -180,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)) {
@ -212,7 +220,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks,
requestAssignmentType, assignmentPool,
listenPort, walletUUID, assignmentServerHostname,
assignmentServerPort, logDirectory);
assignmentServerPort, httpStatusPort, logDirectory);
monitor->setParent(this);
connect(this, &QCoreApplication::aboutToQuit, monitor, &AssignmentClientMonitor::aboutToQuit);
} else {

View file

@ -25,6 +25,7 @@ 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 {

View file

@ -23,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;
@ -32,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, QDir logDirectory) :
quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory) :
_logDirectory(logDirectory),
_httpManager(QHostAddress::LocalHost, httpStatusServerPort, "", this),
_numAssignmentClientForks(numAssignmentClientForks),
_minAssignmentClientForks(minAssignmentClientForks),
_maxAssignmentClientForks(maxAssignmentClientForks),
@ -40,8 +43,8 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen
_assignmentPool(assignmentPool),
_walletUUID(walletUUID),
_assignmentServerHostname(assignmentServerHostname),
_assignmentServerPort(assignmentServerPort),
_logDirectory(logDirectory)
_assignmentServerPort(assignmentServerPort)
{
qDebug() << "_requestAssignmentType =" << _requestAssignmentType;
@ -84,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();
}
}
@ -109,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();
}
}
@ -191,25 +191,29 @@ void AssignmentClientMonitor::spawnChildClient() {
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: " << stdoutPathTemp;
qDebug() << "Child stderr being written to: " << stderrPathTemp;
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() {
@ -265,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));
@ -295,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;
}

View file

@ -21,24 +21,34 @@
#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;
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, QDir logDirectory);
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();
@ -54,13 +64,14 @@ private:
const unsigned int _minAssignmentClientForks;
const unsigned int _maxAssignmentClientForks;
HTTPManager _httpManager;
Assignment::Type _requestAssignmentType;
QString _assignmentPool;
QUuid _walletUUID;
QString _assignmentServerHostname;
quint16 _assignmentServerPort;
QMap<qint64, QProcess*> _childProcesses;
QMap<qint64, ACProcess> _childProcesses;
};
#endif // hifi_AssignmentClientMonitor_h

View file

@ -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(".");
}

View file

@ -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);
}

View file

@ -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")

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

View file

@ -1,33 +0,0 @@
macro(CONSOLIDATE_INSTALLER_COMPONENTS)
if (DEPLOY_PACKAGE AND WIN32)
# Copy icon files for interface and stack manager
if (TARGET_NAME STREQUAL "interface")
set (ICON_FILE_PATH "${PROJECT_SOURCE_DIR}/icon/${INTERFACE_ICON}")
set (ICON_DESTINATION_NAME "interface.ico")
add_custom_command(
TARGET ${TARGET_NAME} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy ${ICON_FILE_PATH} ${CMAKE_BINARY_DIR}/package-bundle/${ICON_DESTINATION_NAME}
COMMAND "${CMAKE_COMMAND}" -E copy_directory $<TARGET_FILE_DIR:${TARGET_NAME}> ${CMAKE_BINARY_DIR}/package-bundle
)
elseif (TARGET_NAME STREQUAL "package-console")
set (ICON_FILE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/resources/${CONSOLE_ICON}")
set (ICON_DESTINATION_NAME "console.ico")
# add a command to copy the folder produced by electron-packager to package-bundle
add_custom_command(
TARGET ${TARGET_NAME} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy ${ICON_FILE_PATH} ${CMAKE_BINARY_DIR}/package-bundle/${ICON_DESTINATION_NAME}
COMMAND "${CMAKE_COMMAND}" -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER} ${CMAKE_BINARY_DIR}/package-bundle
)
else ()
# add a command to copy the fixed up binary and libraries to package-bundle
add_custom_command(
TARGET ${TARGET_NAME} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy_directory $<TARGET_FILE_DIR:${TARGET_NAME}> ${CMAKE_BINARY_DIR}/package-bundle
)
endif ()
endif ()
endmacro()

View 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()

View 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()

View file

@ -10,23 +10,59 @@
#
macro(GENERATE_INSTALLERS)
if (DEPLOY_PACKAGE AND WIN32)
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/package-bundle")
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}/package-bundle
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"
)
include(CPackComponent)
set_target_properties(build-package PROPERTIES EXCLUDE_FROM_ALL TRUE FOLDER "Installer")
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)
endif()
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
# configure a cpack properties file for custom variables in NSIS 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})
if (APPLE)
set(CPACK_PACKAGE_INSTALL_DIRECTORY "/")
set(CPACK_PACKAGING_INSTALL_PREFIX /)
set(CPACK_OSX_PACKAGE_VERSION ${CMAKE_OSX_DEPLOYMENT_TARGET})
endif ()
cpack_add_component(${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Client")
cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Server")
if (APPLE)
# we don't want the OS X package to install anywhere but the main volume, so disable relocation
set(CPACK_PACKAGE_RELOCATABLE FALSE)
endif ()
include(CPack)
endmacro()

View 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()

View 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()

View 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()

View file

@ -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()

View file

@ -12,37 +12,85 @@
# and decides how targets should be packaged.
macro(SET_PACKAGING_PARAMETERS)
set(PR_BUILD 0)
set(PRODUCTION_BUILD 0)
set(DEV_BUILD 0)
if (DEFINED ENV{JOB_ID})
set(DEPLOY_PACKAGE 1)
set(BUILD_SEQ $ENV{JOB_ID})
set(BUILD_TAGGED_BETA FALSE)
set(INSTALLER_COMPANY "High Fidelity")
set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}")
set(INSTALLER_NAME "interface-win64-${BUILD_SEQ}.exe")
set(INTERFACE_ICON "interface.ico")
set(CONSOLE_ICON "console.ico")
elseif (DEFINED ENV{ghprbPullId})
set(DEPLOY_PACKAGE 1)
set(BUILD_TAGGED_BETA TRUE)
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")
set(INTERFACE_ICON "interface-beta.ico")
set(CONSOLE_ICON "console-beta.ico")
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 ${BUILD_VERSION}")
set(INTERFACE_ICON_PREFIX "interface-beta")
else ()
set(BUILD_SEQ "dev")
set(BUILD_TAGGED_BETA TRUE)
set(INSTALLER_COMPANY "High Fidelity - Dev")
set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}")
set(INSTALLER_NAME "dev-interface-win64.exe")
set(INTERFACE_ICON "interface-beta.ico")
set(CONSOLE_ICON "console-beta.ico")
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 ()
set(CONSOLE_INSTALL_DIR ".")
set(INTERFACE_INSTALL_DIR ".")
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_EXEC_NAME}")
set(INTERFACE_INSTALL_APP_PATH "${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("${MACRO_DIR}/ApplicationVersion.h.in" "${CMAKE_BINARY_DIR}/includes/ApplicationVersion.h")
configure_file("${HF_CMAKE_DIR}/templates/BuildInfo.h.in" "${CMAKE_BINARY_DIR}/includes/BuildInfo.h")
endmacro(SET_PACKAGING_PARAMETERS)

View file

@ -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()

View file

@ -22,11 +22,7 @@ macro(SETUP_HIFI_PROJECT)
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")

View file

@ -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 ()

View file

@ -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()

View file

@ -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}/package-bundle/
)
endif ()
endif ()
mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES OPENSSL_SEARCH_DIRS)

View file

@ -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@";
}

View 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@")

View file

@ -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@")

View file

@ -0,0 +1 @@
IDI_ICON1 ICON DISCARDABLE "@CONFIGURE_ICON_PATH@"

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,4 @@
{
"releaseType": "@RELEASE_TYPE@",
"buildIdentifier": "@BUILD_VERSION@"
}

1
console/.gitignore vendored
View file

@ -1,4 +1,5 @@
Server\ Console-*/
server-console-*/
electron-packager/
npm-debug.log
logs/

View file

@ -1,24 +1,71 @@
set(TARGET_NAME package-console)
set(TARGET_NAME packaged-console)
if (BUILD_TAGGED_BETA)
set(BETA_OPTION "--beta")
if (PRODUCTION_BUILD)
set(PRODUCTION_OPTION "--production")
endif()
# add a target that will package the console
add_custom_target(${TARGET_NAME}
COMMAND npm run packager -- --out ${CMAKE_CURRENT_BINARY_DIR} ${BETA_OPTION}
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")
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 ()
set_target_properties(${TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL TRUE FOLDER "Installer")
# 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}")
consolidate_installer_components()
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 ()

View file

@ -9,7 +9,7 @@
],
"devDependencies": {
"electron-compilers": "^1.0.1",
"electron-packager": "^5.1.1",
"electron-packager": "^5.2.1",
"electron-prebuilt": "0.35.4"
},
"repository": {
@ -18,12 +18,20 @@
},
"main": "src/main.js",
"scripts": {
"start": "electron . --local-debug-builds --debug",
"local-release": "electron . --local-release-builds --debug",
"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",
"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"
}
}

View file

@ -11,7 +11,7 @@ if (osType == "Darwin" || osType == "Linux") {
var argv = require('yargs').argv;
// check which icon we should use, beta or regular
var iconName = argv.beta ? "console-beta" : "console"
var iconName = argv.production ? "console" : "console-beta";
// setup the common options for the packager
var options = {
@ -22,7 +22,8 @@ var options = {
prune: true,
arch: "x64",
platform: platform,
icon: "resources/" + iconName
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";
@ -31,6 +32,7 @@ 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"] = {

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

135
console/src/downloader.css Normal file
View file

@ -0,0 +1,135 @@
@font-face {
font-family: 'Proxima Nova';
src: url('vendor/ProximaNova/ProximaNova-Regular.otf');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Proxima Nova';
src: url('vendor/ProximaNova/ProximaNova-Light.otf');
font-weight: 200;
font-style: normal;
}
* {
font-family: "Proxima Nova", "Open Sans", Arial, Helvetica, sans-serif;
line-height: 130%;
}
body {
margin: 0;
padding: 0;
color: #808785;
margin: 0 auto;
text-align: center;
font-size: 14pt;
-webkit-touch-callout: none;
-webkit-user-select: none;
cursor: default;
overflow: hidden;
}
#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;
}
}

View 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
console/src/downloader.js Normal file
View 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');
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

67
console/src/log.css Normal file
View file

@ -0,0 +1,67 @@
@font-face {
font-family: 'Proxima Nova';
src: url('vendor/ProximaNova/ProximaNova-Regular.otf');
}
body {
font-family: "Proxima Nova", "Open Sans", Arial, Helvetica, sans-serif;
line-height: 1.6;
margin: 0;
padding: 0;
}
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 {
float: right;
margin: 10px;
}

23
console/src/log.html Normal file
View file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<title>Log</title>
<script src="log.js"></script>
<link rel="stylesheet" type="text/css" href="log.css"></link>
</head>
<body onload="ready()">
<div class="search">
<input id="search-input" placeholder="filter" />
</div>
<ul class="tabs top">
<li class="tab-link current" data-tab="domain-server">Domain Server</li>
<li class="tab-link" data-tab="assignment-client">Assignment Clients</li>
</ul>
<div class="tab-content bottom">
<div class="tab-pane" id="domain-server"></div>
<div class="tab-pane" id="assignment-client"><div>
</div>
</body>
</html>

205
console/src/log.js Normal file
View file

@ -0,0 +1,205 @@
var remote = require('electron').remote;
var os = require('os');
var Tail = require('always-tail');
function cleanPath(path) {
if (os.type() == "Windows_NT") {
// Fix path on Windows
while (path.indexOf('\\') >= 0) {
path = path.replace('\\', '/', 'g');
}
}
return path;
}
// a: array, b: array
// Returns: { add: [...], subtract: [...] }
// add: array of items in b but not a
// subtract: array of items in a but not b
function difference(a, b) {
var add = [];
var subtract = [];
for (var k of a) {
if (b.indexOf(k) == -1) {
// In a, but not in b
subtract.push(k);
}
}
for (k of b) {
if (a.indexOf(k) == -1) {
// In a, but not in b
add.push(k);
}
}
return {
add: add,
subtract: subtract
};
}
ready = function() {
window.$ = require('./vendor/jquery/jquery-2.1.4.min.js');
var domainServer = remote.getGlobal('domainServer');
var acMonitor = remote.getGlobal('acMonitor');
var logWatchers = {
'ds': {
},
'ac': {
}
};
function updateLogWatchers(stream, watchList, newLogFilesByPID) {
// Consolidate into a list of the log paths
var newLogFilePaths = [];
for (var pid in newLogFilesByPID) {
newLogFilePaths.push(newLogFilesByPID[pid].stdout);
newLogFilePaths.push(newLogFilesByPID[pid].stderr);
}
var oldLogFilePaths = Object.keys(watchList);
var diff = difference(oldLogFilePaths, newLogFilePaths);
console.log('diff', diff);
// For each removed file, remove it from our watch list
diff.subtract.forEach(function(removedLogFilePath) {
watchList[removedLogFilePath].unwatch();
delete watchList[removedLogFilePath];
});
diff.add.forEach(function(addedLogFilePath) {
var cleanFilePath = cleanPath(addedLogFilePath);
var logTail = new Tail(cleanFilePath, '\n', { start: 0, interval: 500 });
logTail.on('line', function(msg) {
appendLogMessage(0, msg, stream);
});
logTail.on('error', function(error) {
console.log("ERROR:", error);
});
logTail.watch();
watchList[addedLogFilePath] = logTail;
console.log("Watching", cleanFilePath);
});
}
function updateLogFiles() {
// Get ds and ac logs from main application
var dsLogs = domainServer.getLogs();
var acLogs = acMonitor.getLogs();
updateLogWatchers('ds', logWatchers.ds, dsLogs);
updateLogWatchers('ac', logWatchers.ac, acLogs);
}
window.onbeforeunload = function(e) {
domainServer.removeListener('logs-updated', updateLogFiles);
acMonitor.removeListener('logs-updated', updateLogFiles);
};
domainServer.on('logs-updated', updateLogFiles);
acMonitor.on('logs-updated', updateLogFiles);
const maxLogLines = 2500;
const ipcRenderer = require('electron').ipcRenderer;
var currentTab = 'domain-server';
var tabStates = {
'domain-server': {
atBottom: true,
size: 0
},
'assignment-client': {
atBottom: true,
size: 0
}
};
function setCurrentTab(tabId) {
if (currentTab == tabId) {
return;
}
var padding = 15;
$currentTab = $('#' + currentTab);
tabStates[currentTab].atBottom = $currentTab[0].scrollTop >= ($currentTab[0].scrollHeight - $currentTab.height() - (2 * padding));
currentTab = tabId;
$('ul.tabs li').removeClass('current');
$('.tab-pane').removeClass('current');
$('li[data-tab=' + tabId + ']').addClass('current');
var $pidLog = $("#" + tabId);
$pidLog.addClass('current');
if (tabStates[tabId].atBottom) {
$pidLog.scrollTop($pidLog[0].scrollHeight);
}
}
$('ul.tabs li').click(function(){
setCurrentTab($(this).attr('data-tab'));
});
setCurrentTab('domain-server');
setCurrentTab('assignment-client');
var filter = "";
function shouldDisplayLogMessage(message) {
return !filter || message.toLowerCase().indexOf(filter) >= 0;
}
function appendLogMessage(pid, msg, name) {
console.log(pid, msg, name);
var id = "pid-" + pid;
id = name == "ds" ? "domain-server" : "assignment-client";
var $pidLog = $('#' + id);
var size = ++tabStates[id].size;
if (size > maxLogLines) {
$pidLog.find('div.log-line:first').remove();
removed = true;
}
var wasAtBottom = false;
if (currentTab == id) {
var padding = 15;
wasAtBottom = $pidLog[0].scrollTop >= ($pidLog[0].scrollHeight - $pidLog.height() - (2 * padding));
}
var $logLine = $('<div class="log-line">').text(msg);
if (!shouldDisplayLogMessage(msg)) {
$logLine.hide();
}
$pidLog.append($logLine);
if (wasAtBottom) {
$pidLog.scrollTop($pidLog[0].scrollHeight);
}
}
// handle filtering of table rows on input change
$('#search-input').on('input', function() {
filter = $(this).val().toLowerCase();
if (filter == "") {
$('.log-line').show();
} else {
$('.log-line').each(function(){
// decide to hide or show the row if it matches the filter
if (filter && $(this).text().toLowerCase().indexOf(filter) == -1) {
$(this).hide();
} else {
$(this).show();
}
});
}
});
updateLogFiles();
};

View file

@ -1,33 +1,164 @@
'use strict'
'use strict';
var electron = require('electron');
var app = electron.app; // Module to control application life.
var BrowserWindow = electron.BrowserWindow;
const electron = require('electron');
const app = electron.app; // Module to control application life.
const BrowserWindow = electron.BrowserWindow;
var Menu = require('menu');
var Tray = require('tray');
var shell = require('shell');
var os = require('os');
var childProcess = require('child_process');
var path = require('path');
const dialog = require('electron').dialog;
const notifier = require('node-notifier');
const util = require('util');
const dialog = electron.dialog;
const Menu = require('menu');
const Tray = require('tray');
const shell = require('shell');
const os = require('os');
const childProcess = require('child_process');
const path = require('path');
const fs = require('fs');
const Tail = require('always-tail');
const http = require('http');
const unzip = require('unzip');
var hfprocess = require('./modules/hf-process.js');
var Process = hfprocess.Process;
var ProcessGroup = hfprocess.ProcessGroup;
var ProcessGroupStates = hfprocess.ProcessGroupStates;
const request = require('request');
const progress = require('request-progress');
const osHomeDir = require('os-homedir');
const ipcMain = electron.ipcMain;
const updater = require('./modules/hf-updater.js');
const Config = require('./modules/config').Config;
const hfprocess = require('./modules/hf-process.js');
const Process = hfprocess.Process;
const ACMonitorProcess = hfprocess.ACMonitorProcess;
const ProcessStates = hfprocess.ProcessStates;
const ProcessGroup = hfprocess.ProcessGroup;
const ProcessGroupStates = hfprocess.ProcessGroupStates;
const osType = os.type();
var path = require('path');
const appIcon = path.join(__dirname, '../resources/console.png');
const TRAY_FILENAME = (osType == "Darwin" ? "console-tray-Template.png" : "console-tray.png");
const TRAY_ICON = path.join(__dirname, '../resources/' + TRAY_FILENAME);
function getBuildInfo() {
var buildInfoPath = null;
if (osType == 'Windows_NT') {
buildInfoPath = path.resolve(process.execPath, 'build-info.json');
} else if (osType == 'Darwin') {
var contentPath = ".app/Contents/";
var contentEndIndex = __dirname.indexOf(contentPath);
if (contentEndIndex != -1) {
// this is an app bundle
var appPath = __dirname.substring(0, contentEndIndex) + ".app";
buildInfoPath = path.resolve(appPath, "/Contents/Resources/build-info.json");
}
}
const DEFAULT_BUILD_INFO = { releaseType: "", buildIdentifier: "dev" };
var buildInfo = DEFAULT_BUILD_INFO;
if (buildInfoPath) {
console.log('Build info path:', buildInfoPath);
try {
buildInfo = JSON.parse(fs.readFileSync(buildInfoPath));
} catch (e) {
buildInfo = DEFAULT_BUILD_INFO;
}
}
return buildInfo;
}
const buildInfo = getBuildInfo();
console.log("build info", buildInfo);
function getRootHifiDataDirectory() {
var organization = "High Fidelity";
if (buildInfo.releaseType != "PRODUCTION") {
organization += ' - ' + buildInfo.buildIdentifier;
}
if (osType == 'Windows_NT') {
return path.resolve(osHomeDir(), 'AppData/Roaming', organization);
} else if (osType == 'Darwin') {
return path.resolve(osHomeDir(), 'Library/Application Support', organization);
} else {
return path.resolve(osHomeDir(), '.local/share/', organization);
}
}
function getAssignmentClientResourcesDirectory() {
return path.join(getRootHifiDataDirectory(), '/assignment-client');
}
function getApplicationDataDirectory() {
return path.join(getRootHifiDataDirectory(), '/Server Console');
}
console.log("Root hifi directory is: ", getRootHifiDataDirectory());
const ipcMain = electron.ipcMain;
var isShuttingDown = false;
function shutdown() {
if (!isShuttingDown) {
var idx = 0;
// if the home server is running, show a prompt before quit to ask if the user is sure
if (homeServer.state == ProcessGroupStates.STARTED) {
idx = dialog.showMessageBox({
type: 'question',
buttons: ['Yes', 'No'],
title: 'Are you sure?',
message: 'Quitting will stop your Server Console and your Home domain will no longer be running.'
});
}
if (idx == 0) {
isShuttingDown = true;
userConfig.save(configPath);
if (logWindow) {
logWindow.close();
}
if (homeServer) {
homeServer.stop();
}
updateTrayMenu(null);
if (homeServer.state == ProcessGroupStates.STOPPED) {
// if the home server is already down, take down the server console now
app.quit();
} else {
// if the home server is still running, wait until we get a state change or timeout
// before quitting the app
var timeoutID = setTimeout(app.quit, 5000);
homeServer.on('state-update', function(processGroup) {
if (processGroup.state == ProcessGroupStates.STOPPED) {
clearTimeout(timeoutID);
app.quit();
}
});
}
}
}
}
var logPath = path.join(getApplicationDataDirectory(), '/logs');
console.log("Log directory:", logPath, getRootHifiDataDirectory());
const configPath = path.join(getApplicationDataDirectory(), 'config.json');
var userConfig = new Config();
userConfig.load(configPath);
// print out uncaught exceptions in the console
process.on('uncaughtException', console.log.bind(console));
process.on('uncaughtException', function(err) {
console.error(err);
console.error(err.stack);
});
var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
// Someone tried to run a second instance, focus the window (if there is one)
@ -35,6 +166,7 @@ var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory)
});
if (shouldQuit) {
console.warn("Another instance of the Server Console is already running - this instance will quit.");
app.quit();
return;
}
@ -49,11 +181,11 @@ var acPath = null;
var debug = argv.debug;
if (argv.localDebugBuilds || argv.localReleaseBuilds) {
interfacePath = pathFinder.discoveredPath("Interface", argv.localReleaseBuilds);
dsPath = pathFinder.discoveredPath("domain-server", argv.localReleaseBuilds);
acPath = pathFinder.discoveredPath("assignment-client", argv.localReleaseBuilds);
}
var binaryType = argv.binaryType;
interfacePath = pathFinder.discoveredPath("Interface", binaryType);
dsPath = pathFinder.discoveredPath("domain-server", binaryType);
acPath = pathFinder.discoveredPath("assignment-client", binaryType);
function binaryMissingMessage(displayName, executableName, required) {
var message = "The " + displayName + " executable was not found.\n";
@ -71,7 +203,7 @@ function binaryMissingMessage(displayName, executableName, required) {
var paths = pathFinder.searchPaths(executableName, argv.localReleaseBuilds);
message += paths.join("\n");
} else {
message += "It is expected to be found beside this executable.\n"
message += "It is expected to be found beside this executable.\n";
message += "You may need to re-install the Server Console.";
}
@ -86,13 +218,15 @@ if (!dsPath) {
}
if (!acPath) {
dialog.showErrorBox("Assignment Client Not Found", binaryMissingMessage("assignment-client", "assignment-client", true))
dialog.showErrorBox("Assignment Client Not Found", binaryMissingMessage("assignment-client", "assignment-client", true));
app.quit();
}
function openFileBrowser(path) {
// Add quotes around path
path = '"' + path + '"';
if (osType == "Windows_NT") {
childProcess.exec('start ' + path);
childProcess.exec('start "" ' + path);
} else if (osType == "Darwin") {
childProcess.exec('open ' + path);
} else if (osType == "Linux") {
@ -100,6 +234,12 @@ function openFileBrowser(path) {
}
}
// NOTE: this looks like it does nothing, but it's very important.
// Without it the default behaviour is to quit the app once all windows closed
// which is absolutely not what we want for a taskbar application.
app.on('window-all-closed', function() {
});
function startInterface(url) {
var argArray = [];
@ -114,67 +254,125 @@ function startInterface(url) {
}
var tray = null;
var logPath = null;
var homeServer = null;
global.homeServer = null;
global.domainServer = null;
global.acMonitor = null;
global.userConfig = userConfig;
const GO_HOME_INDEX = 0;
const SERVER_LABEL_INDEX = 2;
const RESTART_INDEX = 3;
const STOP_INDEX = 4;
const SETTINGS_INDEX = 5;
const GO_HOME_INDEX = 2;
const SERVER_LABEL_INDEX = 0;
const RESTART_INDEX = 4;
const STOP_INDEX = 5;
const SETTINGS_INDEX = 6;
var LogWindow = function(ac, ds) {
this.ac = ac;
this.ds = ds;
this.window = null;
this.acMonitor = null;
this.dsMonitor = null;
}
LogWindow.prototype = {
open: function() {
if (this.window) {
this.window.show();
this.window.restore();
return;
}
// Create the browser window.
this.window = new BrowserWindow({ width: 700, height: 500, icon: appIcon });
this.window.loadURL('file://' + __dirname + '/log.html');
if (!debug) {
this.window.setMenu(null);
}
this.window.on('closed', function() {
this.window = null;
}.bind(this));
},
close: function() {
if (this.window) {
this.window.close();
}
}
};
function goHomeClicked() {
if (interfacePath) {
startInterface('hifi://localhost');
startInterface('hifi://localhost/542.972,495.01,509.351/0,-0.385102,0,0.922874');
} else {
// show an error to say that we can't go home without an interface instance
dialog.showErrorBox("Client Not Found", binaryMissingMessage("High Fidelity Client", "Interface", false));
dialog.showErrorBox("Client Not Found", binaryMissingMessage("High Fidelity client", "Interface", false));
}
}
function buildMenuArray(serverState) {
var menuArray = [
{
label: 'Go Home',
click: goHomeClicked,
enabled: false
},
{
type: 'separator'
},
{
label: "Server - Stopped",
enabled: false
},
{
label: "Start",
click: function() { homeServer.restart(); }
},
{
label: "Stop",
visible: false,
click: function() { homeServer.stop(); }
},
{
label: "Settings",
click: function() { shell.openExternal('http://localhost:40100/settings'); },
enabled: false
},
{
label: "View Logs",
click: function() { openFileBrowser(logPath); }
},
{
type: 'separator'
},
{
label: 'Quit',
accelerator: 'Command+Q',
click: function() { app.quit(); }
}
];
var logWindow = null;
updateMenuArray(menuArray, serverState);
function buildMenuArray(serverState) {
var menuArray = null;
if (isShuttingDown) {
menuArray = [
{
label: "Shutting down...",
enabled: false
}
];
} else {
menuArray = [
{
label: 'Server - Stopped',
enabled: false
},
{
type: 'separator'
},
{
label: 'Go Home',
click: goHomeClicked,
enabled: false
},
{
type: 'separator'
},
{
label: 'Start Server',
click: function() { homeServer.restart(); }
},
{
label: 'Stop Server',
visible: false,
click: function() { homeServer.stop(); }
},
{
label: 'Settings',
click: function() { shell.openExternal('http://localhost:40100/settings'); },
enabled: false
},
{
label: 'View Logs',
click: function() { logWindow.open(); }
},
{
type: 'separator'
},
{
label: 'Share',
click: function() { shell.openExternal('http://localhost:40100/settings/?action=share') }
},
{
type: 'separator'
},
{
label: 'Quit',
accelerator: 'Command+Q',
click: function() { shutdown(); }
}
];
updateMenuArray(menuArray, serverState);
}
return menuArray;
}
@ -197,13 +395,15 @@ function updateMenuArray(menuArray, serverState) {
if (serverState == ProcessGroupStates.STARTED) {
serverLabelItem.label = "Server - Started";
restartItem.label = "Restart";
restartItem.label = "Restart Server";
} else if (serverState == ProcessGroupStates.STOPPED) {
serverLabelItem.label = "Server - Stopped";
restartItem.label = "Start";
restartItem.label = "Start Server";
} else if (serverState == ProcessGroupStates.STOPPING) {
serverLabelItem.label = "Server - Stopping";
restartItem.label = "Restart";
restartItem.label = "Restart Server";
restartItem.enabled = false;
}
}
@ -211,10 +411,147 @@ function updateTrayMenu(serverState) {
if (tray) {
var menuArray = buildMenuArray(serverState);
tray.setContextMenu(Menu.buildFromTemplate(menuArray));
if (isShuttingDown) {
tray.setToolTip('High Fidelity - Shutting Down');
}
}
}
var hiddenWindow = null;
const httpStatusPort = 60332;
function maybeInstallDefaultContentSet(onComplete) {
var hasRun = userConfig.get('hasRun', false);
if (hasRun) {
onComplete();
return;
}
// Check for existing AC data
const acResourceDirectory = getAssignmentClientResourcesDirectory();
console.log("Checking for existence of " + acResourceDirectory);
var userHasExistingServerData = true;
try {
fs.accessSync(acResourceDirectory);
} catch (e) {
console.log(e);
userHasExistingServerData = false;
}
if (userHasExistingServerData) {
console.log("User has existing data, suppressing downloader");
onComplete();
return;
}
// Show popup
var window = new BrowserWindow({
icon: appIcon,
width: 640,
height: 480,
center: true,
frame: true,
useContentSize: true,
resizable: false
});
window.loadURL('file://' + __dirname + '/downloader.html');
if (!debug) {
window.setMenu(null);
}
window.show();
window.on('closed', onComplete);
electron.ipcMain.on('ready', function() {
console.log("got ready");
function sendStateUpdate(state, args) {
// console.log(state, window, args);
window.webContents.send('update', { state: state, args: args });
}
var aborted = false;
// Start downloading content set
var req = progress(request.get({
url: "https://s3.amazonaws.com/hifi-public/homeset/demo.zip"
}, function(error, responseMessage, responseData) {
if (aborted) {
return;
} else if (error || responseMessage.statusCode != 200) {
var message = '';
if (error) {
message = "Error contacting resource server.";
} else {
message = "Error downloading resources from server.";
}
sendStateUpdate('error', {
message: message
});
} else {
sendStateUpdate('installing');
}
}), { throttle: 250 }).on('progress', function(state) {
if (!aborted) {
// Update progress popup
sendStateUpdate('downloading', state);
}
});
var unzipper = unzip.Extract({
path: acResourceDirectory,
verbose: true
});
unzipper.on('close', function() {
console.log("Done", arguments);
sendStateUpdate('complete');
});
unzipper.on('error', function (err) {
console.log("aborting");
aborted = true;
req.abort();
console.log("ERROR");
sendStateUpdate('error', {
message: "Error installing resources."
});
});
req.pipe(unzipper);
userConfig.set('hasRun', true);
});
}
function maybeShowSplash() {
var suppressSplash = userConfig.get('doNotShowSplash', false);
if (!suppressSplash) {
const zoomFactor = 0.8;
var window = new BrowserWindow({
icon: appIcon,
width: 1600 * zoomFactor,
height: 737 * zoomFactor,
center: true,
frame: true,
useContentSize: true,
zoomFactor: zoomFactor,
resizable: false
});
window.loadURL('file://' + __dirname + '/splash.html');
if (!debug) {
window.setMenu(null);
}
window.show();
window.webContents.on('new-window', function(e, url) {
e.preventDefault();
require('shell').openExternal(url);
});
}
}
const trayFilename = (osType == "Darwin" ? "console-tray-Template.png" : "console-tray.png");
const trayIcon = path.join(__dirname, '../resources/' + trayFilename);
const notificationIcon = path.join(__dirname, '../resources/console-notification-win.png');
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
@ -222,13 +559,11 @@ app.on('ready', function() {
if (app.dock) {
// hide the dock icon on OS X
app.dock.hide()
app.dock.hide();
}
logPath = path.join(app.getAppPath(), 'logs');
// Create tray icon
tray = new Tray(TRAY_ICON);
tray = new Tray(trayIcon);
tray.setToolTip('High Fidelity Server Console');
tray.on('click', function() {
@ -237,26 +572,56 @@ app.on('ready', function() {
updateTrayMenu(ProcessGroupStates.STOPPED);
if (dsPath && acPath) {
homeServer = new ProcessGroup('home', [
new Process('domain-server', dsPath),
new Process('ac-monitor', acPath, ['-n6', '--log-directory', logPath])
]);
maybeInstallDefaultContentSet(function() {
maybeShowSplash();
// make sure we stop child processes on app quit
app.on('quit', function(){
homeServer.stop();
});
if (buildInfo.releaseType == 'PRODUCTION') {
var currentVersion = null;
try {
currentVersion = parseInt(buildInfo.buildIdentifier);
} catch (e) {
}
var processes = {
home: homeServer
};
if (currentVersion !== null) {
const CHECK_FOR_UPDATES_INTERVAL_SECONDS = 60 * 30;
var hasShownUpdateNotification = false;
const updateChecker = new updater.UpdateChecker(currentVersion, CHECK_FOR_UPDATES_INTERVAL_SECONDS);
updateChecker.on('update-available', function(latestVersion, url) {
if (!hasShownUpdateNotification) {
notifier.notify({
icon: notificationIcon,
title: 'An update is available!',
message: 'High Fidelity version ' + latestVersion + ' is available',
wait: true,
url: url
});
hasShownUpdateNotification = true;
}
});
notifier.on('click', function(notifierObject, options) {
console.log("Got click", options.url);
shell.openExternal(options.url);
});
}
}
// handle process updates
// homeServer.on('process-update', sendProcessUpdate);
homeServer.on('state-update', function(processGroup) { updateTrayMenu(processGroup.state); });
if (dsPath && acPath) {
domainServer = new Process('domain-server', dsPath, ["--get-temp-name"], logPath);
acMonitor = new ACMonitorProcess('ac-monitor', acPath, ['-n6',
'--log-directory', logPath,
'--http-status-port', httpStatusPort], httpStatusPort, logPath);
homeServer = new ProcessGroup('home', [domainServer, acMonitor]);
logWindow = new LogWindow(acMonitor, domainServer);
// start the home server
homeServer.start();
}
var processes = {
home: homeServer
};
// handle process updates
homeServer.on('state-update', function(processGroup) { updateTrayMenu(processGroup.state); });
// start the home server
homeServer.start();
}
});
});

View file

@ -0,0 +1,45 @@
var fs = require('fs');
var extend = require('extend');
function Config() {
this.data = {};
}
Config.prototype = {
load: function(filePath) {
var rawData = null;
try {
rawData = fs.readFileSync(filePath);
} catch(e) {
console.log("Config file not found");
}
var configData = {};
try {
if (rawData) {
configData = JSON.parse(rawData);
} else {
configData = {};
}
} catch(e) {
console.error("Error parsing config file", filePath)
}
this.data = {};
extend(true, this.data, configData);
},
save: function(filePath) {
fs.writeFileSync(filePath, JSON.stringify(this.data));
},
get: function(key, defaultValue) {
if (this.data.hasOwnProperty(key)) {
return this.data[key];
}
return defaultValue;
},
set: function(key, value) {
console.log("Setting", key, "to", value);
this.data[key] = value;
}
};
exports.Config = Config;

View file

@ -1,11 +1,13 @@
'use strict'
var extend = require('extend');
var util = require('util');
var events = require('events');
var childProcess = require('child_process');
var fs = require('fs');
var os = require('os');
const request = require('request');
const extend = require('extend');
const util = require('util');
const events = require('events');
const childProcess = require('child_process');
const fs = require('fs');
const os = require('os');
const path = require('path');
const ProcessGroupStates = {
STOPPED: 'stopped',
@ -19,6 +21,8 @@ const ProcessStates = {
STOPPING: 'stopping'
};
function ProcessGroup(name, processes) {
events.EventEmitter.call(this);
@ -107,6 +111,8 @@ function Process(name, command, commandArgs, logDirectory) {
this.commandArgs = commandArgs ? commandArgs : [];
this.child = null;
this.logDirectory = logDirectory;
this.logStdout = null;
this.logStderr = null;
this.state = ProcessStates.STOPPED;
};
@ -126,7 +132,7 @@ Process.prototype = extend(Process.prototype, {
var logDirectoryCreated = false;
try {
fs.mkdirSync('logs');
fs.mkdirSync(this.logDirectory);
logDirectoryCreated = true;
} catch (e) {
if (e.code == 'EEXIST') {
@ -139,8 +145,8 @@ Process.prototype = extend(Process.prototype, {
if (logDirectoryCreated) {
// Create a temporary file with the current time
var time = (new Date).getTime();
var tmpLogStdout = this.logDirectory + '/' + this.name + '-' + time + '-stdout.txt';
var tmpLogStderr = this.logDirectory + '/' + this.name + '-' + time + '-stderr.txt';
var tmpLogStdout = path.resolve(this.logDirectory + '/' + this.name + '-' + time + '-stdout.txt');
var tmpLogStderr = path.resolve(this.logDirectory + '/' + this.name + '-' + time + '-stderr.txt');
try {
logStdout = fs.openSync(tmpLogStdout, 'ax');
@ -165,63 +171,182 @@ Process.prototype = extend(Process.prototype, {
} catch (e) {
console.log("Got error starting child process for " + this.name, e);
this.child = null;
this.state = ProcessStates.STOPPED;
this.updateState(ProcessStates.STOPPED);
return;
}
if (logStdout != 'ignore') {
var pidLogStdout = './logs/' + this.name + "-" + this.child.pid + "-" + time + "-stdout.txt";
var pidLogStdout = path.resolve(this.logDirectory + '/' + this.name + "-" + this.child.pid + "-" + time + "-stdout.txt");
fs.rename(tmpLogStdout, pidLogStdout, function(e) {
if (e !== null) {
console.log("Error renaming log file from " + tmpLogStdout + " to " + pidLogStdout, e);
}
});
this.logStdout = pidLogStdout;
fs.closeSync(logStdout);
}
if (logStderr != 'ignore') {
var pidLogStderr = './logs/' + this.name + "-" + this.child.pid + "-" + time + "-stderr.txt";
var pidLogStderr = path.resolve(this.logDirectory + '/' + this.name + "-" + this.child.pid + "-" + time + "-stderr.txt");
fs.rename(tmpLogStderr, pidLogStderr, function(e) {
if (e !== null) {
console.log("Error renaming log file from " + tmpLogStdout + " to " + pidLogStdout, e);
}
});
this.logStderr = pidLogStderr;
fs.closeSync(logStderr);
}
this.child.on('error', this.onChildStartError.bind(this));
this.child.on('close', this.onChildClose.bind(this));
this.state = ProcessStates.STARTED;
console.log("Child process started");
this.emit('state-update', this);
console.log("Child process started");
this.updateState(ProcessStates.STARTED);
this.emit('logs-updated');
},
stop: function() {
if (this.state != ProcessStates.STARTED) {
console.warn("Can't stop process that is not started.");
stop: function(force) {
if (this.state == ProcessStates.STOPPED) {
console.warn("Can't stop process that is not started or stopping.");
return;
}
if (os.type() == "Windows_NT") {
childProcess.spawn("taskkill", ["/pid", this.child.pid, '/f', '/t']);
var command = "taskkill /pid " + this.child.pid;
if (force) {
command += " /f /t";
}
childProcess.exec(command, {}, function(error) {
if (error) {
console.error('Error executing taskkill:', error);
}
});
} else {
this.child.kill();
var signal = force ? 'SIGKILL' : null;
this.child.kill(signal);
}
this.state = ProcessStates.STOPPING;
this.emit('state-update', this);
console.log("Stopping child process:", this.child.pid, this.name);
if (!force) {
this.stoppingTimeoutID = setTimeout(function() {
if (this.state == ProcessStates.STOPPING) {
console.log("Force killling", this.name, this.child.pid);
this.stop(true);
}
}.bind(this), 2500);
}
this.updateState(ProcessStates.STOPPING);
},
updateState: function(newState) {
if (this.state != newState) {
this.state = newState;
this.emit('state-update', this);
return true;
}
return false;
},
getLogs: function() {
var logs = {};
logs[this.child.pid] = {
stdout: this.logStdout == 'ignore' ? null : this.logStdout,
stderr: this.logStderr == 'ignore' ? null : this.logStderr
};
return logs;
},
// Events
onChildStartError: function(error) {
console.log("Child process error ", error);
this.state = ProcessStates.STOPPED;
this.emit('state-update', this);
this.updateState(ProcessStates.STOPPED);
},
onChildClose: function(code) {
console.log("Child process closed with code ", code);
this.state = ProcessStates.STOPPED;
this.emit('state-update', this);
console.log("Child process closed with code ", code, this.name);
if (this.stoppingTimeoutID) {
clearTimeout(this.stoppingTimeoutID);
this.stoppingTimeoutID = null;
}
this.updateState(ProcessStates.STOPPED);
}
});
// ACMonitorProcess is an extension of Process that keeps track of the AC Montior's
// children status and log locations.
const CHECK_AC_STATUS_INTERVAL = 5000;
function ACMonitorProcess(name, path, args, httpStatusPort, logPath) {
Process.call(this, name, path, args, logPath);
this.httpStatusPort = httpStatusPort;
this.requestTimeoutID = null;
this.pendingRequest = null;
this.childServers = {};
};
util.inherits(ACMonitorProcess, Process);
ACMonitorProcess.prototype = extend(ACMonitorProcess.prototype, {
updateState: function(newState) {
if (ACMonitorProcess.super_.prototype.updateState.call(this, newState)) {
if (this.state == ProcessStates.STARTED) {
this._updateACMonitorStatus();
} else {
if (this.requestTimeoutID) {
clearTimeout(this.requestTimeoutID);
this.requestTimeoutID = null;
}
if (this.pendingRequest) {
this.pendingRequest.destroy();
this.pendingRequest = null;
}
}
}
},
getLogs: function() {
var logs = {};
logs[this.child.pid] = {
stdout: this.logStdout == 'ignore' ? null : this.logStdout,
stderr: this.logStderr == 'ignore' ? null : this.logStderr
};
for (var pid in this.childServers) {
logs[pid] = {
stdout: this.childServers[pid].logStdout,
stderr: this.childServers[pid].logStderr
}
}
console.log(logs);
return logs;
},
_updateACMonitorStatus: function() {
if (this.state != ProcessStates.STARTED) {
return;
}
// If there is a pending request, return
if (this.pendingRequest) {
return;
}
console.log("Checking AC Monitor status");
var options = {
url: "http://localhost:" + this.httpStatusPort + "/status",
json: true
};
this.pendingRequest = request(options, function(error, response, body) {
if (error) {
console.error('ERROR Getting AC Monitor status', error);
} else {
this.childServers = body.servers;
}
console.log(body);
this.emit('logs-updated');
this.requestTimeoutID = setTimeout(this._updateACMonitorStatus.bind(this), CHECK_AC_STATUS_INTERVAL);
}.bind(this));
}
});
module.exports.Process = Process;
module.exports.ACMonitorProcess = ACMonitorProcess;
module.exports.ProcessGroup = ProcessGroup;
module.exports.ProcessGroupStates = ProcessGroupStates;
module.exports.ProcessStates = ProcessStates;

View file

@ -0,0 +1,46 @@
const request = require('request');
const extend = require('extend');
const util = require('util');
const events = require('events');
const cheerio = require('cheerio');
const os = require('os');
const platform = os.type() == 'Windows_NT' ? 'windows' : 'mac';
const BUILDS_URL = 'https://highfidelity.com/builds.xml';
function UpdateChecker(currentVersion, checkForUpdatesEveryXSeconds) {
this.currentVersion = currentVersion;
console.log('cur', currentVersion);
setInterval(this.checkForUpdates.bind(this), checkForUpdatesEveryXSeconds * 1000);
this.checkForUpdates();
};
util.inherits(UpdateChecker, events.EventEmitter);
UpdateChecker.prototype = extend(UpdateChecker.prototype, {
checkForUpdates: function() {
console.log("Checking for updates");
request(BUILDS_URL, (error, response, body) => {
if (error) {
console.log("Error", error);
return;
}
if (response.statusCode == 200) {
try {
var $ = cheerio.load(body, { xmlMode: true });
const latestBuild = $('project[name="interface"] platform[name="' + platform + '"]').children().first();
const latestVersion = parseInt(latestBuild.find('version').text());
console.log("Latest version is:", latestVersion, this.currentVersion);
if (latestVersion > this.currentVersion) {
const url = latestBuild.find('url').text();
this.emit('update-available', latestVersion, url);
}
} catch (e) {
console.warn("Error when checking for updates", e);
}
}
});
}
});
exports.UpdateChecker = UpdateChecker;

View file

@ -1,6 +1,7 @@
var fs = require('fs');
var path = require('path');
exports.searchPaths = function(name, preferRelease) {
exports.searchPaths = function(name, binaryType) {
function platformExtension(name) {
if (name == "Interface") {
if (process.platform == "darwin") {
@ -16,28 +17,58 @@ exports.searchPaths = function(name, preferRelease) {
}
var extension = platformExtension(name);
var basePath = "../build/" + name + "/";
var devBasePath = "../build/" + name + "/";
return [
basePath + name + extension,
basePath + (preferRelease ? "Release/" : "Debug/") + name + extension
];
var paths = [];
if (binaryType == "local-release" || binaryType == "local-debug") {
// check in the developer build tree for binaries
paths = [
devBasePath + name + extension,
devBasePath + (binaryType == "local-release" ? "Release/" : "Debug/") + name + extension
]
} else {
// check directly beside the binary
paths = [
path.join(path.dirname(process.execPath), name + extension)
];
// assume we're inside an app bundle on OS X
if (process.platform == "darwin") {
var contentPath = ".app/Contents/";
var contentEndIndex = __dirname.indexOf(contentPath);
if (contentEndIndex != -1) {
// this is an app bundle
var appPath = __dirname.substring(0, contentEndIndex) + ".app";
// check in Contents/MacOS for the binaries
var componentsPath = appPath + "/Contents/MacOS/Components.app/Contents/MacOS/";
paths.push(componentsPath + name + extension);
// check beside the app bundle for the binaries
paths.push(path.join(path.dirname(appPath), name + extension));
}
}
}
return paths;
}
exports.discoveredPath = function (name, preferRelease) {
exports.discoveredPath = function (name, binaryType) {
function binaryFromPaths(name, paths) {
for (var i = 0; i < paths.length; i++) {
var path = paths[i];
var testPath = paths[i];
try {
var stats = fs.lstatSync(path);
var stats = fs.lstatSync(testPath);
if (stats.isFile() || (stats.isDirectory() && extension == ".app")) {
console.log("Found " + name + " at " + path);
return path;
console.log("Found " + name + " at " + testPath);
return testPath;
}
} catch (e) {
console.warn("Executable with name " + name + " not found at path " + path);
console.log("Executable with name " + name + " not found at path " + testPath);
}
}
@ -45,5 +76,5 @@ exports.discoveredPath = function (name, preferRelease) {
}
// attempt to find a binary at the usual paths, return null if it doesn't exist
return binaryFromPaths(name, this.searchPaths(name, preferRelease));
return binaryFromPaths(name, this.searchPaths(name, binaryType));
}

128
console/src/splash.css Normal file
View file

@ -0,0 +1,128 @@
@font-face {
font-family: 'Proxima Nova';
src: url('vendor/ProximaNova/ProximaNova-Regular.otf');
}
body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
color: #414141;
-webkit-touch-callout: none;
-webkit-user-select: none;
cursor: default;
}
* {
font-family: "Proxima Nova", "Open Sans", Arial, Helvetica, sans-serif;
font-size: 14.5pt;
line-height: 130%;
}
a:link,
a:visited,
a:hover,
a:active {
font-weight: bold;
color: #2D88A4;
}
a:hover {
font-weight: bold;
color: #00B4EF;
}
h1 {
font-weight: normal;
color: #6D7472;
font-size: 30pt;
margin: 0;
padding: 0;
}
h2 {
color: #6D7472;
font-weight: bold;
margin: 0;
padding: 0;
}
.header-title {
padding-top: 80px;
}
.content {
margin: 0 110px;
}
.column {
display: inline-block;
float: left;
padding-top: 26px;
}
.column.left {
width: 415px;
padding-right: 120px;
}
.column.center {
width: 540px;
}
.column.right {
z-index: -1;
float: right;
padding-top: 16px;
padding-left: 60px;
position: absolute;
right: -30px;
}
.top {
height: 168px;
border-bottom: 2px solid #F5F6F6;
}
.middle {
width: 1364px;
/* 1584 - (110 * 2) */
position: absolute;
top: 168px;
bottom: 98px;
}
.bottom {
width: 100%;
position: absolute;
height: 98px;
background-color: #F5F6F6;
bottom: 0;
/* padding-top: 34px; */
}
#main-content {
height: 350px;
border-bottom: 2px solid #F5F6F6;
}
#existing-resources-area {
padding-top: 20px;
}
.footer {
padding-top: 34px;
}
.header-right {
/* float: right; */
position: absolute;
top: 63px;
right: 114px;
}
input[type="checkbox"] {
-webkit-transform: scale(1.4);
display: inline-block;
}

86
console/src/splash.html Normal file
View file

@ -0,0 +1,86 @@
<!DOCTYPE html>
<html>
<head>
<title>High Fidelity</title>
<script src="splash.js"></script>
<link rel="stylesheet" type="text/css" href="splash.css"></link>
</head>
<body onload="ready()">
<div class="top content">
<div class="header-title">
<h1>Hello Worlds!</h1>
</div>
<div class="header-right">
<img src="images/console-hf-logo-2x.png" width=300px />
</div>
</div>
<div class="middle content">
<div id="main-content">
<div class="column left">
<p>
<h2>What now?</h2>
High Fidelity is now installed and your Home domain is ready for you to explore. To start you off, we've put a few things in your home to play around with and learn the ropes.
</p>
<p>
You can make your home yours by uploading your own models and scripts, and adding items from the Market.
</p>
<p>
<em>To see how,</em> <a target="_blank" href="https://docs.highfidelity.com/docs/the-basics">check out 'The Basics'</a>
</p>
</div>
<div class="column center">
<p>
<h2>How do I use it?</h2>
You can manage your server by clicking on the High Fidelity icon in your
<script>
var osType = require('os').type();
document.write(osType == 'Windows_NT' ? 'system tray.' : 'menu bar.');
</script>
In the menu that opens, you can:
</p>
<p>
<ul>
<li>go to your 'Home,' automatically launching High Fidelity</li>
<li>administer basic function like starting and stopping your server</li>
<li>access your server's settings and logs</li>
</ul>
</p>
<p>
<em>For more information on managing your server,</em> <a target="_blank" href="https://docs.highfidelity.com/">visit our documentation</a>
</p>
</div>
<div class="column right">
<script>
var osType = require('os').type();
menuBarImageURL = '';
if (osType == 'Windows_NT') {
menuBarImageURL = "images/console-menubar-windows-2x.png";
} else {
menuBarImageURL = "images/console-menubar-osx-2x.png";
}
document.write('<img src="' + menuBarImageURL + '" width=384px/>');
</script>
</div>
</div>
<div id="existing-resources-area">
<p>
<h2>Your existing Stack Manager content is safe.</h2>
Server Console comes with demo content but does not overwrite your data. <a target="_blank" href="https://docs.highfidelity.com/v1.0/docs/migrate-sm-to-sc">See our guide to importing content previously managed with Stack Manager</a>.
</p>
</div>
</div>
<div class="bottom">
<div class="content footer">
<input type="checkbox" id="suppress-splash"> </input>
<label for="suppress-splash">
Don't show this screen next time
</label>
</div>
</div>
</body>
</html>

11
console/src/splash.js Normal file
View file

@ -0,0 +1,11 @@
var remote = require('electron').remote;
ready = function() {
window.$ = require('./vendor/jquery/jquery-2.1.4.min.js');
var userConfig = remote.getGlobal('userConfig');
$('#suppress-splash').change(function() {
console.log("updating");
userConfig.set('doNotShowSplash', $(this).is(':checked'));
});
}

View file

@ -34,7 +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 ()
package_libraries_for_deployment()
consolidate_installer_components()
if (WIN32)
package_libraries_for_deployment()
endif ()
install_beside_console()

View file

@ -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, function(data){ callback(data) }).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)
});
}

File diff suppressed because one or more lines are too long

View file

@ -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);
}
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);

View file

@ -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;
};

View file

@ -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() {

View file

@ -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

View file

@ -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;

View file

@ -63,22 +63,23 @@ 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 "")
@ -88,29 +89,36 @@ 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()
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes")
# 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)
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
@ -136,7 +144,7 @@ target_glew()
target_opengl()
if (WIN32 OR APPLE)
target_faceshift()
target_faceshift()
endif()
# perform standard include and linking for found externals
@ -190,7 +198,7 @@ target_link_libraries(
# 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
@ -203,11 +211,17 @@ if (APPLE)
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
@ -222,14 +236,37 @@ else (APPLE)
# 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_installer_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()

View file

@ -60,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>
@ -306,7 +306,7 @@ bool setupEssentials(int& argc, char** argv) {
listenPort = atoi(portStr);
}
// Set build version
QCoreApplication::setApplicationVersion(BUILD_VERSION);
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
Setting::preInit();

View file

@ -91,7 +91,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;
@ -104,7 +104,7 @@ public:
Application(int& argc, char** argv, QElapsedTimer& startup_time);
~Application();
void postLambdaEvent(std::function<void()> f);
void postLambdaEvent(std::function<void()> f) override;
void loadScripts();
QString getPreviousScriptLocation();
@ -115,8 +115,8 @@ public:
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;
@ -135,7 +135,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; }
@ -157,7 +157,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
@ -172,19 +172,19 @@ public:
ToolWindow* getToolWindow() { return _toolWindow ; }
virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; }
virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine);
virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) override;
QImage renderAvatarBillboard(RenderArgs* renderArgs);
virtual ViewFrustum* getCurrentViewFrustum() { return getDisplayViewFrustum(); }
virtual QThread* getMainThread() { return thread(); }
virtual float getSizeScale() const;
virtual int getBoundaryLevelAdjust() const;
virtual PickRay computePickRay(float x, float y) const;
virtual glm::vec3 getAvatarPosition() const;
virtual void overrideEnvironmentData(const EnvironmentData& newData) { _environment.override(newData); }
virtual void endOverrideEnvironmentData() { _environment.endOverride(); }
virtual qreal getDevicePixelRatio();
virtual ViewFrustum* getCurrentViewFrustum() override { return getDisplayViewFrustum(); }
virtual QThread* getMainThread() override { return thread(); }
virtual float getSizeScale() const override;
virtual int getBoundaryLevelAdjust() const override;
virtual PickRay computePickRay(float x, float y) const override;
virtual glm::vec3 getAvatarPosition() const override;
virtual void overrideEnvironmentData(const EnvironmentData& newData) override { _environment.override(newData); }
virtual void endOverrideEnvironmentData() override { _environment.endOverride(); }
virtual qreal getDevicePixelRatio() override;
void setActiveDisplayPlugin(const QString& pluginName);
@ -226,9 +226,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; }
@ -289,7 +289,7 @@ public slots:
void resetSensors(bool andReload = false);
void setActiveFaceTracker();
#ifdef HAVE_IVIEWHMD
void setActiveEyeTracker();
void calibrateEyeTracker1Point();
@ -306,11 +306,11 @@ public slots:
void reloadResourceCaches();
void crashApplication();
void rotationModeChanged();
void runTests();
private slots:
void clearDomainOctreeDetails();
void idle(uint64_t now);
@ -325,19 +325,19 @@ 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();
void scriptFinished(const QString& scriptName, ScriptEngine* engine);
void saveScripts();
void reloadScript(const QString& scriptName, bool isUserLoaded = true);
bool acceptSnapshot(const QString& urlString);
bool askToSetAvatarUrl(const QString& url);
bool askToLoadScript(const QString& scriptFilenameOrURL);
@ -356,13 +356,13 @@ private slots:
void packetSent(quint64 length);
void updateDisplayMode();
void updateInputModes();
private:
void initDisplay();
void init();
void cleanupBeforeQuit();
void emptyLocalCache();
void update(float deltaTime);
@ -382,45 +382,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;
@ -510,7 +510,7 @@ private:
quint64 _lastNackTime;
quint64 _lastSendDownstreamAudioStats;
bool _aboutToQuit;
Bookmarks* _bookmarks;
@ -519,9 +519,9 @@ private:
QThread _settingsThread;
QTimer _settingsTimer;
GLCanvas* _glWidget{ nullptr };
typedef bool (Application::* AcceptURLMethod)(const QString &);
static const QHash<QString, AcceptURLMethod> _acceptedExtensions;

View file

@ -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(); }

View file

@ -78,8 +78,11 @@ int main(int argc, const char* argv[]) {
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());
socket.waitForBytesWritten(5000);
if (!socket.waitForBytesWritten(5000)) {
qDebug() << "Error writing URL to local socket";
}
}
}
@ -95,12 +98,6 @@ int main(int argc, const char* argv[]) {
#endif
}
// Setup local server
QLocalServer server;
// We failed to connect to a local server, so we remove any existing servers.
server.removeServer(applicationName);
server.listen(applicationName);
QElapsedTimer startupTime;
startupTime.start();
@ -125,6 +122,13 @@ 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;

View file

@ -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;

View file

@ -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;

View file

@ -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)

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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;
}
}

View file

@ -788,8 +788,6 @@ void LimitedNodeList::processSTUNResponse(std::unique_ptr<udt::BasePacket> packe
}
void LimitedNodeList::startSTUNPublicSocketUpdate() {
assert(!_initialSTUNTimer);
if (!_initialSTUNTimer) {
// if we don't know the STUN IP yet we need to have ourselves be called once it is known
if (_stunSockAddr.getAddress().isNull()) {

View file

@ -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;

View file

@ -40,7 +40,7 @@ public:
virtual ViewFrustum* getShadowViewFrustum() = 0;
virtual QThread* getMainThread() = 0;
virtual float getSizeScale() const = 0;
virtual int getBoundaryLevelAdjust() const = 0;
virtual PickRay computePickRay(float x, float y) const = 0;

View file

@ -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;

View file

@ -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;

View file

@ -42,6 +42,8 @@ LogHandler::LogHandler() :
const char* stringForLogType(LogMsgType msgType) {
switch (msgType) {
case LogInfo:
return "INFO";
case LogDebug:
return "DEBUG";
case LogWarning:

View file

@ -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

View 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);
}

View 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

View file

@ -1,219 +0,0 @@
!include LogicLib.nsh
!include x64.nsh
!include MUI2.nsh
;------------------------------------------------------------------------------------------------------
; Source Directory Definition
;
; installer_srcdir = Source directory for Interface
; scripts_srcdir = Source directory for JS scripts
!define installer_srcdir "$%INSTALLER_SOURCE_DIR%"
!define scripts_srcdir "$%INSTALLER_SCRIPTS_DIR%"
; Install Directories, Icons and Registry entries
;
; setup = Name of the installer executable that will be produced
; uninstaller = Name of the uninstaller executable
; company = String to use for company name, includes build type suffix [eg. High Fidelity - PR] for non-release installers
; install_directory = Subdirectory where this specific version will be installed, in the case of dev and pr builds, its a
; unique subdirectory inside a company parent [eg. \High Fidelity - PR\1234\ ]
!define setup "$%INSTALLER_NAME%"
!define uninstaller "uninstall.exe"
!define company "$%INSTALLER_COMPANY%"
!define install_directory "$%INSTALLER_DIRECTORY%"
; Executables and icons for GUI applications that will be added as shortcuts.
!define interface_exec "interface.exe"
!define console_exec "server-console.exe"
!define interface_icon "interface.ico"
!define console_icon "server-console.ico"
; Registry entries
!define regkey "Software\${install_directory}"
!define uninstkey "Software\Microsoft\Windows\CurrentVersion\Uninstall\${install_directory}"
!define instdir "$PROGRAMFILES64\${install_directory}"
; Start Menu program group
!define startmenu_company "$SMPROGRAMS\${install_directory}"
;------------------------------------------------------------------------------------------------------
; Local Variables and Other Options
var ChosenInstallDir
SetCompressor bzip2
ShowInstDetails hide
ShowUninstDetails hide
AutoCloseWindow true
ShowInstDetails show
SetDateSave on
SetDatablockOptimize on
CRCCheck on
SilentInstall normal
Icon "${installer_srcdir}\${interface_icon}"
UninstallIcon "${installer_srcdir}\${interface_icon}"
UninstallText "This will uninstall ${company}."
Name "${company}"
Caption "${company}"
OutFile "${setup}"
;------------------------------------------------------------------------------------------------------
; Components
Section /o "DDE Face Recognition" "DDE"
SetOutPath "$ChosenInstallDir"
CreateDirectory $ChosenInstallDir\dde
NSISdl::download "https://s3-us-west-1.amazonaws.com/hifi-production/optionals/dde-installer.exe" "$ChosenInstallDir\dde-installer.exe"
ExecWait '"$ChosenInstallDir\dde-installer.exe" /q:a /t:"$ChosenInstallDir\dde"'
SectionEnd
Section /o "Default Content Set" "CONTENT"
SetOutPath "$ChosenInstallDir\resources"
NSISdl::download "https://s3-us-west-1.amazonaws.com/hifi-production/content/temp.exe" "$ChosenInstallDir\content.exe"
ExecWait '"$ChosenInstallDir\content.exe" /S'
Delete "$ChosenInstallDir\content.exe"
SectionEnd
Section "Registry Entries and Protocol Handler" "REGISTRY"
SetRegView 64
SectionIn RO
WriteRegStr HKLM "${regkey}" "Install_Dir" "$ChosenInstallDir"
WriteRegStr HKLM "${uninstkey}" "DisplayName" "${install_directory} (remove only)"
WriteRegStr HKLM "${uninstkey}" "UninstallString" '"$ChosenInstallDir\${uninstaller}"'
WriteRegStr HKCR "${company}\Shell\open\command\" "" '"$ChosenInstallDir\${interface_exec} "%1"'
WriteRegStr HKCR "${company}\DefaultIcon" "" "$ChosenInstallDir\${interface_icon}"
; hifi:// protocol handler registry entries
WriteRegStr HKCR 'hifi' '' 'URL:Alert Protocol'
WriteRegStr HKCR 'hifi' 'URL Protocol' ''
WriteRegStr HKCR 'hifi\DefaultIcon' '' '$ChosenInstallDir\${interface_icon},1'
WriteRegStr HKCR 'hifi\shell\open\command' '' '$ChosenInstallDir\${interface_exec} --url "%1"'
SetOutPath $ChosenInstallDir
WriteUninstaller "$ChosenInstallDir\${uninstaller}"
Exec '"$ChosenInstallDir\2013_vcredist_x64.exe" /q /norestart'
Exec '"$ChosenInstallDir\2010_vcredist_x86.exe" /q /norestart'
SectionEnd
Section "Base Files" "BASE"
SectionIn RO
SetOutPath $ChosenInstallDir
File /r /x assignment-client.* /x domain-server.* /x interface.* /x server-console.* "${installer_srcdir}\"
SectionEnd
Section "High Fidelity Interface" "CLIENT"
SetOutPath $ChosenInstallDir
File /a "${installer_srcdir}\interface.*"
File /a "${installer_srcdir}\${interface_icon}"
SectionEnd
Section "High Fidelity Server" "SERVER"
SetOutPath $ChosenInstallDir
File /a "${installer_srcdir}\server-console.*"
File /a "${installer_srcdir}\domain-server.*"
File /a "${installer_srcdir}\assignment-client.*"
SectionEnd
Section "Start Menu Shortcuts" "SHORTCUTS"
SetShellVarContext all
CreateDirectory "${startmenu_company}"
SetOutPath $ChosenInstallDir
CreateShortCut "${startmenu_company}\High Fidelity.lnk" "$ChosenInstallDir\${interface_exec}" "" "$ChosenInstallDir\${interface_icon}"
CreateShortCut "${startmenu_company}\Server Console.lnk" "$ChosenInstallDir\${console_exec}" "" "$ChosenInstallDir\${console_icon}"
CreateShortCut "${startmenu_company}\Uninstall ${company}.lnk" "$ChosenInstallDir\${uninstaller}"
SectionEnd
Section "Uninstall"
SetRegView 64
Delete "$INSTDIR\${uninstaller}"
Delete "$SMSTARTUP\High Fidelity Server Console.lnk"
RMDir /r "$INSTDIR"
RMDir /r "${startmenu_company}"
RMDir /r "$0"
DeleteRegKey HKLM "${uninstkey}"
DeleteRegKey HKLM "${regkey}"
DeleteRegKey HKCR "${company}"
DeleteRegKey HKCR 'hifi'
SectionEnd
;------------------------------------------------------------------------------------------------------
; Functions
Function .onInit
StrCpy $ChosenInstallDir "${instdir}"
SectionSetText ${REGISTRY} ""
SectionSetText ${SHORTCUTS} ""
SectionSetText ${BASE} ""
FunctionEnd
var ServerCheckBox
var ServerCheckBox_state
var RunOnStartupCheckBox
var RunOnStartupCheckBox_state
Function RunCheckboxes
${If} ${SectionIsSelected} ${SERVER}
${NSD_CreateCheckbox} 36.2% 56% 100% 10u "&Start Home Server"
Pop $ServerCheckBox
SetCtlColors $ServerCheckBox "" "ffffff"
${NSD_CreateCheckbox} 36.2% 65% 100% 10u "&Always launch your Home Server on startup"
Pop $RunOnStartupCheckBox
SetCtlColors $RunOnStartupCheckBox "" "ffffff"
${EndIf}
FunctionEnd
Function HandleCheckBoxes
${If} ${SectionIsSelected} ${SERVER}
${NSD_GetState} $ServerCheckBox $ServerCheckBox_state
${If} $ServerCheckBox_state == ${BST_CHECKED}
SetOutPath $ChosenInstallDir
ExecShell "" '"$ChosenInstallDir\${console_exec}"'
${EndIf}
${NSD_GetState} $RunOnStartupCheckBox $RunOnStartupCheckBox_state
${If} $ServerCheckBox_state == ${BST_CHECKED}
CreateShortCut "$SMSTARTUP\High Fidelity Server Console.lnk" "$ChosenInstallDir\${console_exec}" "" "$ChosenInstallDir\${console_icon}"
${EndIf}
${EndIf}
FunctionEnd
;------------------------------------------------------------------------------------------------------
; User interface macros and other definitions
!define MUI_WELCOMEFINISHPAGE_BITMAP "installer_vertical.bmp"
!define MUI_WELCOMEPAGE_TITLE "High Fidelity - Integrated Installer"
!define MUI_WELCOMEPAGE_TEXT "Welcome to High Fidelity! This installer includes both High Fidelity Interface for VR access as well as the High Fidelity Server for you to host your own domain in the metaverse."
!insertmacro MUI_PAGE_WELCOME
!define MUI_PAGE_HEADER_TEXT "Please select the components you want to install"
!define MUI_COMPONENTSPAGE_TEXT_DESCRIPTION_INFO "Hover over a component for a brief description"
!insertmacro MUI_PAGE_COMPONENTS
!define MUI_DIRECTORYPAGE_VARIABLE $ChosenInstallDir
!define MUI_PAGE_HEADER_TEXT "High Fidelity"
!define MUI_PAGE_HEADER_SUBTEXT ""
!define MUI_DIRECTORYPAGE_TEXT_TOP "Choose a location for your High Fidelity installation."
!define MUI_DIRECTORYPAGE_TEXT_DESTINATION "Install Directory"
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!define MUI_PAGE_CUSTOMFUNCTION_SHOW RunCheckboxes
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE HandleCheckboxes
!define MUI_FINISHPAGE_RUN_NOTCHECKED
!define MUI_FINISHPAGE_RUN "$ChosenInstallDir\interface.exe"
!define MUI_FINISHPAGE_RUN_TEXT "Start High Fidelity Interface"
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${DDE} "DDE enables facial gesture recognition using a standard 2D webcam"
!insertmacro MUI_DESCRIPTION_TEXT ${CONTENT} "Demo content set for your home server"
!insertmacro MUI_DESCRIPTION_TEXT ${CLIENT} "The High Fidelity Interface Client for connection to domains in the metaverse."
!insertmacro MUI_DESCRIPTION_TEXT ${SERVER} "The High Fidelity Server - run your own home domain"
!insertmacro MUI_FUNCTION_DESCRIPTION_END
!insertmacro MUI_LANGUAGE "English"

View file

@ -1,5 +1,7 @@
set(TARGET_NAME udt-test)
setup_hifi_project()
set_target_properties(${TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL TRUE EXCLUDE_FROM_DEFAULT_BUILD TRUE)
link_hifi_libraries(networking shared)
package_libraries_for_deployment()
package_libraries_for_deployment()