Merge pull request #69 from huffman/console-post-demo
Console post demo
5
.gitignore
vendored
|
@ -36,7 +36,7 @@ interface/external/*/*
|
|||
# Ignore interfaceCache for Linux users
|
||||
interface/interfaceCache/
|
||||
|
||||
# ignore audio-client externals
|
||||
# ignore audio-client externals
|
||||
libraries/audio-client/external/*/*
|
||||
!libraries/audio-client/external/*/readme.txt
|
||||
|
||||
|
@ -48,4 +48,5 @@ TAGS
|
|||
*.swp
|
||||
|
||||
# ignore node files for the console
|
||||
node_modules
|
||||
node_modules
|
||||
npm-debug.log
|
||||
|
|
|
@ -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
|
@ -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.
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "NodeType.h"
|
||||
#include "SendAssetTask.h"
|
||||
#include "UploadAssetTask.h"
|
||||
#include <ServerPathUtils.h>
|
||||
|
||||
const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server";
|
||||
|
||||
|
@ -49,8 +50,27 @@ void AssetServer::run() {
|
|||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
|
||||
|
||||
_resourcesDirectory = QDir(QCoreApplication::applicationDirPath()).filePath("resources/assets");
|
||||
const QString RESOURCES_PATH = "assets";
|
||||
|
||||
_resourcesDirectory = QDir(ServerPathUtils::getDataDirectory()).filePath(RESOURCES_PATH);
|
||||
if (!_resourcesDirectory.exists()) {
|
||||
qDebug() << "Asset resources directory not found, searching for existing asset resources";
|
||||
QString oldDataDirectory = QCoreApplication::applicationDirPath();
|
||||
auto oldResourcesDirectory = QDir(oldDataDirectory).filePath(RESOURCES_PATH);
|
||||
|
||||
if (QDir(oldResourcesDirectory).exists()) {
|
||||
qDebug() << "Existing assets found in " << oldResourcesDirectory << ", copying to " << _resourcesDirectory;
|
||||
|
||||
|
||||
QDir resourcesParentDirectory = _resourcesDirectory.filePath("..");
|
||||
if (!resourcesParentDirectory.exists()) {
|
||||
qDebug() << "Creating data directory " << resourcesParentDirectory.absolutePath();
|
||||
resourcesParentDirectory.mkpath(".");
|
||||
}
|
||||
|
||||
QFile::copy(oldResourcesDirectory, _resourcesDirectory.absolutePath());
|
||||
}
|
||||
|
||||
qDebug() << "Creating resources directory";
|
||||
_resourcesDirectory.mkpath(".");
|
||||
}
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
|
||||
#include "OctreeQueryNode.h"
|
||||
#include "OctreeServerConsts.h"
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <ServerPathUtils.h>
|
||||
#include <QtCore/QDir>
|
||||
|
||||
int OctreeServer::_clientCount = 0;
|
||||
const int MOVING_AVERAGE_SAMPLE_COUNTS = 1000000;
|
||||
|
@ -280,10 +283,10 @@ OctreeServer::~OctreeServer() {
|
|||
void OctreeServer::initHTTPManager(int port) {
|
||||
// setup the embedded web server
|
||||
|
||||
QString documentRoot = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath());
|
||||
QString documentRoot = QString("%1/web").arg(ServerPathUtils::getDataDirectory());
|
||||
|
||||
// setup an httpManager with us as the request handler and the parent
|
||||
_httpManager = new HTTPManager(port, documentRoot, this, this);
|
||||
_httpManager = new HTTPManager(QHostAddress::AnyIPv4, port, documentRoot, this, this);
|
||||
}
|
||||
|
||||
bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) {
|
||||
|
@ -1031,6 +1034,7 @@ void OctreeServer::readConfiguration() {
|
|||
if (!readOptionString(QString("persistFilename"), settingsSectionObject, persistFilename)) {
|
||||
persistFilename = getMyDefaultPersistFilename();
|
||||
}
|
||||
|
||||
strcpy(_persistFilename, qPrintable(persistFilename));
|
||||
qDebug("persistFilename=%s", _persistFilename);
|
||||
|
||||
|
@ -1096,7 +1100,7 @@ void OctreeServer::run() {
|
|||
_tree->setIsServer(true);
|
||||
|
||||
qDebug() << "Waiting for connection to domain to request settings from domain-server.";
|
||||
|
||||
|
||||
// wait until we have the domain-server settings, otherwise we bail
|
||||
DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||
connect(&domainHandler, &DomainHandler::settingsReceived, this, &OctreeServer::domainSettingsRequestComplete);
|
||||
|
@ -1139,9 +1143,30 @@ void OctreeServer::domainSettingsRequestComplete() {
|
|||
|
||||
// if we want Persistence, set up the local file and persist thread
|
||||
if (_wantPersist) {
|
||||
// If persist filename does not exist, let's see if there is one beside the application binary
|
||||
// If there is, let's copy it over to our target persist directory
|
||||
QString oldResourcesDirectory = QCoreApplication::applicationDirPath();
|
||||
auto oldPersistPath = QDir(oldResourcesDirectory).absoluteFilePath(_persistFilename);
|
||||
auto persistPath = ServerPathUtils::getDataFilePath("entities/" + QString(_persistFilename));
|
||||
if (oldPersistPath != persistPath && !QFile::exists(persistPath)) {
|
||||
qDebug() << "Persist file does not exist, checking for existence of persist file next to application";
|
||||
if (QFile::exists(oldPersistPath)) {
|
||||
qDebug() << "Old persist file found, copying from " << oldPersistPath << " to " << persistPath;
|
||||
|
||||
QDir persistFileDirectory = QDir(persistPath).filePath("..");
|
||||
|
||||
if (!persistFileDirectory.exists()) {
|
||||
qDebug() << "Creating data directory " << persistFileDirectory.path();
|
||||
persistFileDirectory.mkpath(".");
|
||||
}
|
||||
QFile::copy(oldPersistPath, persistPath);
|
||||
} else {
|
||||
qDebug() << "No existing persist file found";
|
||||
}
|
||||
}
|
||||
|
||||
// now set up PersistThread
|
||||
_persistThread = new OctreePersistThread(_tree, _persistFilename, _persistInterval,
|
||||
_persistThread = new OctreePersistThread(_tree, persistPath, _persistInterval,
|
||||
_wantBackup, _settings, _debugTimestampNow, _persistAsFileType);
|
||||
_persistThread->initialize(true);
|
||||
}
|
||||
|
|
21
cmake/externals/faceshift/CMakeLists.txt
vendored
|
@ -21,10 +21,23 @@ ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
|||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE FILEPATH "Path to Faceshift include directory")
|
||||
|
||||
set(LIBRARY_DEBUG_PATH "lib/Debug")
|
||||
set(LIBRARY_RELEASE_PATH "lib/Release")
|
||||
|
||||
if (WIN32)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/Debug/faceshift.lib CACHE FILEPATH "Faceshift libraries")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/Release/faceshift.lib CACHE FILEPATH "Faceshift libraries")
|
||||
set(LIBRARY_PREFIX "")
|
||||
set(LIBRARY_EXT "lib")
|
||||
elseif (APPLE)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/Debug/libfaceshift.a CACHE FILEPATH "Faceshift libraries")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/Release/libfaceshift.a CACHE FILEPATH "Faceshift libraries")
|
||||
set(LIBRARY_EXT "a")
|
||||
set(LIBRARY_PREFIX "lib")
|
||||
|
||||
if (CMAKE_GENERATOR STREQUAL "Unix Makefiles")
|
||||
set(LIBRARY_DEBUG_PATH "build")
|
||||
set(LIBRARY_RELEASE_PATH "build")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG
|
||||
${INSTALL_DIR}/${LIBRARY_DEBUG_PATH}/${LIBRARY_PREFIX}faceshift.${LIBRARY_EXT} CACHE FILEPATH "Faceshift libraries")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE
|
||||
${INSTALL_DIR}/${LIBRARY_RELEASE_PATH}/${LIBRARY_PREFIX}faceshift.${LIBRARY_EXT} CACHE FILEPATH "Faceshift libraries")
|
||||
|
|
BIN
cmake/installer/installer-header.bmp
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
cmake/installer/installer.ico
Normal file
After Width: | Height: | Size: 153 KiB |
BIN
cmake/installer/uninstaller-header.bmp
Normal file
After Width: | Height: | Size: 100 KiB |
|
@ -1,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()
|
16
cmake/macros/FixPathForNSIS.cmake
Normal file
|
@ -0,0 +1,16 @@
|
|||
#
|
||||
# FixPathForNSIS.cmake
|
||||
#
|
||||
# Created by Sam Gateau on 1/14/16.
|
||||
# Copyright 2016 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(fix_path_for_nsis INITIAL_PATH RESULTING_PATH)
|
||||
# replace forward slash with backslash
|
||||
string(REPLACE "/" "\\\\" _BACKSLASHED_PATH ${INITIAL_PATH})
|
||||
# set the resulting path variable
|
||||
set(${RESULTING_PATH} ${_BACKSLASHED_PATH})
|
||||
endmacro()
|
58
cmake/macros/FixupInterface.cmake
Normal file
|
@ -0,0 +1,58 @@
|
|||
#
|
||||
# FixupInterface.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2016 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on January 6th, 2016
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(fixup_interface)
|
||||
if (APPLE)
|
||||
|
||||
string(REPLACE " " "\\ " ESCAPED_BUNDLE_NAME ${INTERFACE_BUNDLE_NAME})
|
||||
string(REPLACE " " "\\ " ESCAPED_INSTALL_PATH ${INTERFACE_INSTALL_DIR})
|
||||
set(_INTERFACE_INSTALL_PATH "${ESCAPED_INSTALL_PATH}/${ESCAPED_BUNDLE_NAME}.app")
|
||||
|
||||
# install QtWebProcess from Qt to the application bundle
|
||||
# since it is missed by macdeployqt
|
||||
# https://bugreports.qt.io/browse/QTBUG-35211
|
||||
set(LIBEXEC_PATH "${_INTERFACE_INSTALL_PATH}/Contents/libexec")
|
||||
install(
|
||||
PROGRAMS "${QT_DIR}/libexec/QtWebProcess"
|
||||
DESTINATION ${LIBEXEC_PATH}
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
|
||||
set(QTWEBPROCESS_PATH "\${CMAKE_INSTALL_PREFIX}/${LIBEXEC_PATH}")
|
||||
|
||||
# we also need a qt.conf in the directory of QtWebProcess
|
||||
install(CODE "
|
||||
file(WRITE ${QTWEBPROCESS_PATH}/qt.conf
|
||||
\"[Paths]\nPlugins = ../PlugIns\nImports = ../Resources/qml\nQml2Imports = ../Resources/qml\"
|
||||
)"
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
|
||||
find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS "${QT_DIR}/bin" NO_DEFAULT_PATH)
|
||||
|
||||
if (NOT MACDEPLOYQT_COMMAND AND (PRODUCTION_BUILD OR PR_BUILD))
|
||||
message(FATAL_ERROR "Could not find macdeployqt at ${QT_DIR}/bin.\
|
||||
It is required to produce an relocatable interface application.\
|
||||
Check that the environment variable QT_DIR points to your Qt installation.\
|
||||
")
|
||||
endif ()
|
||||
|
||||
install(CODE "
|
||||
execute_process(COMMAND ${MACDEPLOYQT_COMMAND}\
|
||||
\${CMAKE_INSTALL_PREFIX}/${_INTERFACE_INSTALL_PATH}/\
|
||||
-verbose=2 -qmldir=${CMAKE_SOURCE_DIR}/interface/resources/qml/\
|
||||
-executable=\${CMAKE_INSTALL_PREFIX}/${_INTERFACE_INSTALL_PATH}/Contents/libexec/QtWebProcess\
|
||||
)"
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
|
||||
endif ()
|
||||
endmacro()
|
|
@ -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()
|
||||
|
|
72
cmake/macros/InstallBesideConsole.cmake
Normal file
|
@ -0,0 +1,72 @@
|
|||
#
|
||||
# InstallBesideConsole.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2016 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on January 5th, 2016
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(install_beside_console)
|
||||
if (WIN32 OR APPLE)
|
||||
# install this component beside the installed server-console executable
|
||||
if (APPLE)
|
||||
set(CONSOLE_APP_CONTENTS "${CONSOLE_INSTALL_APP_PATH}/Contents")
|
||||
set(COMPONENT_DESTINATION "${CONSOLE_APP_CONTENTS}/MacOS/Components.app/Contents/MacOS")
|
||||
else ()
|
||||
set(COMPONENT_DESTINATION ${CONSOLE_INSTALL_DIR})
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
install(
|
||||
TARGETS ${TARGET_NAME}
|
||||
RUNTIME DESTINATION ${COMPONENT_DESTINATION}
|
||||
COMPONENT ${SERVER_COMPONENT}
|
||||
)
|
||||
else ()
|
||||
# setup install of executable and things copied by fixup/windeployqt
|
||||
install(
|
||||
FILES "$<TARGET_FILE_DIR:${TARGET_NAME}>/"
|
||||
DESTINATION ${COMPONENT_DESTINATION}
|
||||
COMPONENT ${SERVER_COMPONENT}
|
||||
)
|
||||
|
||||
# on windows for PR and production builds, sign the executable
|
||||
set(EXECUTABLE_COMPONENT ${SERVER_COMPONENT})
|
||||
optional_win_executable_signing()
|
||||
endif ()
|
||||
|
||||
if (TARGET_NAME STREQUAL domain-server)
|
||||
if (APPLE)
|
||||
set(RESOURCES_DESTINATION ${COMPONENT_DESTINATION})
|
||||
else ()
|
||||
set(RESOURCES_DESTINATION ${CONSOLE_INSTALL_DIR})
|
||||
endif ()
|
||||
|
||||
# install the resources folder for the domain-server where its executable will be
|
||||
install(
|
||||
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/resources
|
||||
DESTINATION ${RESOURCES_DESTINATION}
|
||||
USE_SOURCE_PERMISSIONS
|
||||
COMPONENT ${SERVER_COMPONENT}
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
# during the install phase, call fixup to drop the shared libraries for these components in the right place
|
||||
set(EXECUTABLE_NEEDING_FIXUP "\${CMAKE_INSTALL_PREFIX}/${COMPONENT_DESTINATION}/${TARGET_NAME}")
|
||||
install(CODE "
|
||||
include(BundleUtilities)
|
||||
fixup_bundle(\"${EXECUTABLE_NEEDING_FIXUP}\" \"\" \"${FIXUP_LIBS}\")
|
||||
" COMPONENT ${SERVER_COMPONENT})
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# set variables used by manual ssleay library copy
|
||||
set(TARGET_INSTALL_DIR ${COMPONENT_DESTINATION})
|
||||
set(TARGET_INSTALL_COMPONENT ${SERVER_COMPONENT})
|
||||
manually_install_ssl_eay()
|
||||
|
||||
endmacro()
|
28
cmake/macros/ManuallyInstallSSLEay.cmake
Normal file
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
# ManuallyInstallSSLEay.cmake
|
||||
#
|
||||
# Created by Stephen Birarda on 1/15/16.
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(manually_install_ssl_eay)
|
||||
|
||||
# on windows we have had issues with targets missing ssleay library
|
||||
# not convinced we actually need it (I assume it would show up in the dependency tree)
|
||||
# but to be safe we install it manually beside the current target
|
||||
if (WIN32)
|
||||
# we need to find SSL_EAY_LIBRARY_* so we can install it beside this target
|
||||
# so we have to call find_package(OpenSSL) here even though this target may not specifically need it
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
install(
|
||||
FILES "${OPENSSL_DLL_PATH}/ssleay32.dll"
|
||||
DESTINATION ${TARGET_INSTALL_DIR}
|
||||
COMPONENT ${TARGET_INSTALL_COMPONENT}
|
||||
)
|
||||
endif()
|
||||
|
||||
endmacro()
|
34
cmake/macros/OptionalWinExecutableSigning.cmake
Normal file
|
@ -0,0 +1,34 @@
|
|||
#
|
||||
# OptionalWinExecutableSigning.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2016 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on January 12, 2016
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(optional_win_executable_signing)
|
||||
if (WIN32 AND PRODUCTION_BUILD)
|
||||
if (DEFINED ENV{HF_PFX_FILE})
|
||||
if (DEFINED ENV{HF_PFX_PASSPHRASE})
|
||||
message(STATUS "Executable for ${TARGET_NAME} will be signed with SignTool.")
|
||||
|
||||
if (NOT EXECUTABLE_PATH)
|
||||
set(EXECUTABLE_PATH "$<TARGET_FILE:${TARGET_NAME}>")
|
||||
endif ()
|
||||
|
||||
# setup a post build command to sign the executable
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND ${SIGNTOOL_EXECUTABLE} sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 ${EXECUTABLE_PATH}
|
||||
)
|
||||
else ()
|
||||
message(FATAL_ERROR "HF_PFX_PASSPHRASE must be set for executables to be signed.")
|
||||
endif ()
|
||||
else ()
|
||||
message(WARNING "Creating a production build but not code signing since HF_PFX_FILE is not set.")
|
||||
endif ()
|
||||
endif ()
|
||||
endmacro()
|
|
@ -1,25 +1,24 @@
|
|||
#
|
||||
#
|
||||
# PackageLibrariesForDeployment.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on February 17, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
#
|
||||
|
||||
macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT)
|
||||
|
||||
if (WIN32)
|
||||
configure_file(
|
||||
${HIFI_CMAKE_DIR}/templates/FixupBundlePostBuild.cmake.in
|
||||
${HF_CMAKE_DIR}/templates/FixupBundlePostBuild.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/FixupBundlePostBuild.cmake
|
||||
@ONLY
|
||||
)
|
||||
|
||||
|
||||
set(PLUGIN_PATH "plugins")
|
||||
|
||||
|
||||
# add a post-build command to copy DLLs beside the executable
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME}
|
||||
|
@ -29,31 +28,18 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT)
|
|||
-DBUNDLE_PLUGIN_DIR=$<TARGET_FILE_DIR:${TARGET_NAME}>/${PLUGIN_PATH}
|
||||
-P ${CMAKE_CURRENT_BINARY_DIR}/FixupBundlePostBuild.cmake
|
||||
)
|
||||
|
||||
|
||||
find_program(WINDEPLOYQT_COMMAND windeployqt PATHS ${QT_DIR}/bin NO_DEFAULT_PATH)
|
||||
|
||||
|
||||
if (NOT WINDEPLOYQT_COMMAND)
|
||||
message(FATAL_ERROR "Could not find windeployqt at ${QT_DIR}/bin. windeployqt is required.")
|
||||
endif ()
|
||||
|
||||
|
||||
# add a post-build command to call windeployqt to copy Qt plugins
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME}
|
||||
POST_BUILD
|
||||
COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} ${EXTRA_DEPLOY_OPTIONS} $<$<OR:$<CONFIG:Release>,$<CONFIG:MinSizeRel>,$<CONFIG:RelWithDebInfo>>:--release> $<TARGET_FILE:${TARGET_NAME}>"
|
||||
)
|
||||
elseif (DEFINED BUILD_BUNDLE AND BUILD_BUNDLE AND APPLE)
|
||||
find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS ${QT_DIR}/bin NO_DEFAULT_PATH)
|
||||
|
||||
if (NOT MACDEPLOYQT_COMMAND)
|
||||
message(FATAL_ERROR "Could not find macdeployqt at ${QT_DIR}/bin. macdeployqt is required.")
|
||||
endif ()
|
||||
|
||||
# add a post-build command to call macdeployqt to copy Qt plugins
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME}
|
||||
POST_BUILD
|
||||
COMMAND ${MACDEPLOYQT_COMMAND} ${CMAKE_CURRENT_BINARY_DIR}/\${CONFIGURATION}/${TARGET_NAME}.app -verbose 0
|
||||
)
|
||||
endif ()
|
||||
endmacro()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# CopyDirectoryBesideTarget.cmake
|
||||
# CopyDirectoryBesideTarget.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Created by Stephen Birarda on 04/30/15.
|
||||
|
@ -10,22 +10,22 @@
|
|||
#
|
||||
|
||||
macro(SYMLINK_OR_COPY_DIRECTORY_BESIDE_TARGET _SHOULD_SYMLINK _DIRECTORY _DESTINATION)
|
||||
|
||||
|
||||
# remove the current directory
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E remove_directory $<TARGET_FILE_DIR:${TARGET_NAME}>/${_DESTINATION}
|
||||
)
|
||||
|
||||
|
||||
if (${_SHOULD_SYMLINK})
|
||||
|
||||
|
||||
# first create the destination
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E make_directory
|
||||
$<TARGET_FILE_DIR:${TARGET_NAME}>/${_DESTINATION}
|
||||
)
|
||||
|
||||
|
||||
# the caller wants a symlink, so just add a command to symlink all contents of _DIRECTORY
|
||||
# in the destination - we can't simply create a symlink for _DESTINATION
|
||||
# because the remove_directory call above would delete the original files
|
||||
|
@ -35,20 +35,20 @@ macro(SYMLINK_OR_COPY_DIRECTORY_BESIDE_TARGET _SHOULD_SYMLINK _DIRECTORY _DESTIN
|
|||
foreach(_ITEM ${_DIR_ITEMS})
|
||||
# get the filename for this item
|
||||
get_filename_component(_ITEM_FILENAME ${_ITEM} NAME)
|
||||
|
||||
|
||||
# add the command to symlink this item
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E create_symlink
|
||||
${_ITEM}
|
||||
$<TARGET_FILE_DIR:${TARGET_NAME}>/${_DESTINATION}/${_ITEM_FILENAME}
|
||||
)
|
||||
endforeach()
|
||||
)
|
||||
endforeach()
|
||||
else ()
|
||||
# copy the directory
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${_DIRECTORY}
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${_DIRECTORY}
|
||||
$<TARGET_FILE_DIR:${TARGET_NAME}>/${_DESTINATION}
|
||||
)
|
||||
endif ()
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Bradley Austin Davis on 2015/10/10
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
#
|
||||
macro(TARGET_SIXENSE)
|
||||
add_dependency_external_projects(sixense)
|
||||
find_package(Sixense REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES})
|
||||
add_definitions(-DHAVE_SIXENSE)
|
||||
endmacro()
|
||||
endmacro()
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
# OPENSSL_INCLUDE_DIR - the OpenSSL include directory
|
||||
# OPENSSL_LIBRARIES - The libraries needed to use OpenSSL
|
||||
# OPENSSL_VERSION - This is set to $major.$minor.$revision$path (eg. 0.9.8s)
|
||||
#
|
||||
#
|
||||
# Modified on 7/16/2014 by Stephen Birarda
|
||||
# This is an adapted version of the FindOpenSSL.cmake module distributed with Cmake 2.8.12.2
|
||||
# The original license for that file is displayed below.
|
||||
#
|
||||
#
|
||||
#=============================================================================
|
||||
# Copyright 2006-2009 Kitware, Inc.
|
||||
# Copyright 2006 Alexander Neundorf <neundorf@kde.org>
|
||||
|
@ -50,18 +50,18 @@ if (WIN32)
|
|||
)
|
||||
set(_OPENSSL_ROOT_PATHS "${_programfiles}/OpenSSL" "${_programfiles}/OpenSSL-Win32" "C:/OpenSSL/" "C:/OpenSSL-Win32/")
|
||||
endif()
|
||||
|
||||
|
||||
unset(_programfiles)
|
||||
set(_OPENSSL_ROOT_HINTS_AND_PATHS HINTS ${_OPENSSL_ROOT_HINTS} PATHS ${_OPENSSL_ROOT_PATHS})
|
||||
|
||||
|
||||
else ()
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("openssl")
|
||||
|
||||
|
||||
set(_OPENSSL_ROOT_HINTS_AND_PATHS ${OPENSSL_SEARCH_DIRS})
|
||||
endif ()
|
||||
|
||||
find_path(OPENSSL_INCLUDE_DIR NAMES openssl/ssl.h HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_INCLUDEDIR}
|
||||
find_path(OPENSSL_INCLUDE_DIR NAMES openssl/ssl.h HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_INCLUDEDIR}
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
|
@ -81,15 +81,15 @@ if (WIN32 AND NOT CYGWIN)
|
|||
# We are using the libraries located in the VC subdir instead of the parent directory eventhough :
|
||||
# libeay32MD.lib is identical to ../libeay32.lib, and
|
||||
# ssleay32MD.lib is identical to ../ssleay32.lib
|
||||
find_library(LIB_EAY_DEBUG NAMES libeay32MDd libeay32d
|
||||
find_library(LIB_EAY_DEBUG NAMES libeay32MDd libeay32d
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC"
|
||||
)
|
||||
|
||||
find_library(LIB_EAY_RELEASE NAMES libeay32MD libeay32
|
||||
find_library(LIB_EAY_RELEASE NAMES libeay32MD libeay32
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC"
|
||||
)
|
||||
|
||||
find_library(SSL_EAY_DEBUG NAMES ssleay32MDd ssleay32d
|
||||
find_library(SSL_EAY_DEBUG NAMES ssleay32MDd ssleay32d
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC"
|
||||
)
|
||||
|
||||
|
@ -109,22 +109,22 @@ if (WIN32 AND NOT CYGWIN)
|
|||
set(OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY})
|
||||
|
||||
find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" ${_OPENSSL_ROOT_HINTS_AND_PATHS})
|
||||
|
||||
|
||||
elseif (MINGW)
|
||||
# same player, for MinGW
|
||||
set(LIB_EAY_NAMES libeay32)
|
||||
set(SSL_EAY_NAMES ssleay32)
|
||||
|
||||
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
list(APPEND LIB_EAY_NAMES crypto)
|
||||
list(APPEND SSL_EAY_NAMES ssl)
|
||||
endif ()
|
||||
|
||||
|
||||
find_library(LIB_EAY NAMES ${LIB_EAY_NAMES}
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "lib/MinGW"
|
||||
)
|
||||
|
||||
find_library(SSL_EAY NAMES ${SSL_EAY_NAMES}
|
||||
find_library(SSL_EAY NAMES ${SSL_EAY_NAMES}
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "lib/MinGW"
|
||||
)
|
||||
|
||||
|
@ -147,7 +147,7 @@ else()
|
|||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
find_library(OPENSSL_CRYPTO_LIBRARY NAMES crypto HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_LIBDIR}
|
||||
find_library(OPENSSL_CRYPTO_LIBRARY NAMES crypto HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_LIBDIR}
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
|
@ -196,7 +196,7 @@ if (OPENSSL_INCLUDE_DIR)
|
|||
if(OPENSSL_INCLUDE_DIR AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h")
|
||||
file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str
|
||||
REGEX "^#[ ]?define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])+.*")
|
||||
|
||||
|
||||
# The version number is encoded as 0xMNNFFPPS: major minor fix patch status
|
||||
# The status gives if this is a developer or prerelease and is ignored here.
|
||||
# Major, minor, and fix directly translate into the version numbers shown in
|
||||
|
@ -252,15 +252,6 @@ endif ()
|
|||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${OPENSSL_DLL_PATH})
|
||||
#
|
||||
# For some reason fixup misses the following DLL and only copies libeay32. There's gotta be a better way to handle this
|
||||
# but for now resorting to the following interm solution
|
||||
if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE)
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy ${OPENSSL_DLL_PATH}/ssleay32.dll ${CMAKE_BINARY_DIR}/package-bundle/
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES OPENSSL_SEARCH_DIRS)
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
//
|
||||
// ApplicationVersion.h.in
|
||||
// BuildInfo.h.in
|
||||
// cmake/macros
|
||||
//
|
||||
// Created by Leonardo Murillo on 8/13/15.
|
||||
// Created by Stephen Birarda on 1/14/16.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
const QString BUILD_VERSION = "@BUILD_SEQ@";
|
||||
namespace BuildInfo {
|
||||
const QString MODIFIED_ORGANIZATION = "@BUILD_ORGANIZATION@";
|
||||
const QString VERSION = "@BUILD_VERSION@";
|
||||
}
|
35
cmake/templates/CPackProperties.cmake.in
Normal file
|
@ -0,0 +1,35 @@
|
|||
#
|
||||
# CPackProperties.cmake.in
|
||||
# cmake/templates
|
||||
#
|
||||
# Copyright 2016 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on January 11, 2016
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
set(INTERFACE_SHORTCUT_NAME "@INTERFACE_SM_SHORTCUT_NAME@")
|
||||
set(INTERFACE_WIN_EXEC_NAME "@INTERFACE_EXEC_PREFIX@.exe")
|
||||
set(CONSOLE_SHORTCUT_NAME "@CONSOLE_SM_SHORTCUT_NAME@")
|
||||
set(CONSOLE_WIN_EXEC_NAME "@CONSOLE_EXEC_NAME@")
|
||||
set(DS_EXEC_NAME "@DS_EXEC_NAME@")
|
||||
set(AC_EXEC_NAME "@AC_EXEC_NAME@")
|
||||
set(HIGH_FIDELITY_PROTOCOL "@HIGH_FIDELITY_PROTOCOL@")
|
||||
set(PRODUCTION_BUILD "@PRODUCTION_BUILD@")
|
||||
set(PR_BUILD "@PR_BUILD@")
|
||||
set(BUILD_ORGANIZATION "@BUILD_ORGANIZATION@")
|
||||
set(POST_INSTALL_OPTIONS_PATH "@POST_INSTALL_OPTIONS_PATH@")
|
||||
set(CLIENT_COMPONENT_NAME "@CLIENT_COMPONENT@")
|
||||
set(SERVER_COMPONENT_NAME "@SERVER_COMPONENT@")
|
||||
set(SIGNTOOL_EXECUTABLE "@SIGNTOOL_EXECUTABLE@")
|
||||
set(UNINSTALLER_NAME "@GENERATED_UNINSTALLER_EXEC_NAME@")
|
||||
set(REGISTRY_HKLM_INSTALL_ROOT "@REGISTRY_HKLM_INSTALL_ROOT@")
|
||||
set(POST_INSTALL_OPTIONS_REG_GROUP "@POST_INSTALL_OPTIONS_REG_GROUP@")
|
||||
set(CLIENT_DESKTOP_SHORTCUT_REG_KEY "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@")
|
||||
set(CONSOLE_DESKTOP_SHORTCUT_REG_KEY "@CONSOLE_DESKTOP_SHORTCUT_REG_KEY@")
|
||||
set(CONSOLE_STARTUP_REG_KEY "@CONSOLE_STARTUP_REG_KEY@")
|
||||
set(LAUNCH_NOW_REG_KEY "@LAUNCH_NOW_REG_KEY@")
|
||||
set(INSTALLER_HEADER_IMAGE "@INSTALLER_HEADER_IMAGE@")
|
||||
set(UNINSTALLER_HEADER_IMAGE "@UNINSTALLER_HEADER_IMAGE@")
|
||||
set(ADD_REMOVE_ICON_PATH "@ADD_REMOVE_ICON_PATH@")
|
|
@ -1,56 +1,54 @@
|
|||
#
|
||||
#
|
||||
# FixupBundlePostBuild.cmake.in
|
||||
# cmake/templates
|
||||
#
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on February 13, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
#
|
||||
|
||||
include(BundleUtilities)
|
||||
|
||||
|
||||
# replace copy_resolved_item_into_bundle
|
||||
# replace copy_resolved_item_into_bundle
|
||||
#
|
||||
# The official version of copy_resolved_item_into_bundle will print out a "warning:" when
|
||||
# the resolved item matches the resolved embedded item. This not not really an issue that
|
||||
# should rise to the level of a "warning" so we replace this message with a "status:"
|
||||
#
|
||||
function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item)
|
||||
if(WIN32)
|
||||
# ignore case on Windows
|
||||
string(TOLOWER "${resolved_item}" resolved_item_compare)
|
||||
string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
|
||||
else()
|
||||
set(resolved_item_compare "${resolved_item}")
|
||||
set(resolved_embedded_item_compare "${resolved_embedded_item}")
|
||||
endif()
|
||||
if (WIN32)
|
||||
# ignore case on Windows
|
||||
string(TOLOWER "${resolved_item}" resolved_item_compare)
|
||||
string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
|
||||
else()
|
||||
set(resolved_item_compare "${resolved_item}")
|
||||
set(resolved_embedded_item_compare "${resolved_embedded_item}")
|
||||
endif()
|
||||
|
||||
if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
|
||||
# this is our only change from the original version
|
||||
message(STATUS "status: resolved_item == resolved_embedded_item - not copying...")
|
||||
else()
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
|
||||
if(UNIX AND NOT APPLE)
|
||||
file(RPATH_REMOVE FILE "${resolved_embedded_item}")
|
||||
endif()
|
||||
if ("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
|
||||
# this is our only change from the original version
|
||||
message(STATUS "status: resolved_item == resolved_embedded_item - not copying...")
|
||||
else()
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
|
||||
if(UNIX AND NOT APPLE)
|
||||
file(RPATH_REMOVE FILE "${resolved_embedded_item}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
message(STATUS "FIXUP_LIBS for fixup_bundle called for bundle ${BUNDLE_EXECUTABLE} are @FIXUP_LIBS@")
|
||||
|
||||
message(STATUS "Scanning for plugins from ${BUNDLE_PLUGIN_DIR}")
|
||||
|
||||
if (APPLE)
|
||||
set(PLUGIN_EXTENSION "dylib")
|
||||
elseif (WIN32)
|
||||
set(PLUGIN_EXTENSION "dll")
|
||||
else()
|
||||
set(PLUGIN_EXTENSION "so")
|
||||
set(PLUGIN_EXTENSION "dylib")
|
||||
elseif (WIN32)
|
||||
set(PLUGIN_EXTENSION "dll")
|
||||
else()
|
||||
set(PLUGIN_EXTENSION "so")
|
||||
endif()
|
||||
|
||||
file(GLOB RUNTIME_PLUGINS "${BUNDLE_PLUGIN_DIR}/*.${PLUGIN_EXTENSION}")
|
||||
fixup_bundle("${BUNDLE_EXECUTABLE}" "${RUNTIME_PLUGINS}" "@FIXUP_LIBS@")
|
||||
file(GLOB EXTRA_PLUGINS "${BUNDLE_PLUGIN_DIR}/*.${PLUGIN_EXTENSION}")
|
||||
fixup_bundle("${BUNDLE_EXECUTABLE}" "${EXTRA_PLUGINS}" "@FIXUP_LIBS@")
|
||||
|
|
1
cmake/templates/Icon.rc.in
Normal file
|
@ -0,0 +1 @@
|
|||
IDI_ICON1 ICON DISCARDABLE "@CONFIGURE_ICON_PATH@"
|
1359
cmake/templates/NSIS.template.in
Normal file
4
cmake/templates/console-build-info.json.in
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"releaseType": "@RELEASE_TYPE@",
|
||||
"buildIdentifier": "@BUILD_VERSION@"
|
||||
}
|
1
console/.gitignore
vendored
|
@ -1,4 +1,5 @@
|
|||
Server\ Console-*/
|
||||
server-console-*/
|
||||
electron-packager/
|
||||
npm-debug.log
|
||||
logs/
|
||||
|
|
|
@ -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 ()
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"] = {
|
||||
|
|
BIN
console/resources/console-notification-win.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
console/resources/console-tray.ico
Normal file
After Width: | Height: | Size: 5.3 KiB |
135
console/src/downloader.css
Normal 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;
|
||||
}
|
||||
}
|
34
console/src/downloader.html
Normal file
|
@ -0,0 +1,34 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>High Fidelity</title>
|
||||
<script src="downloader.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="downloader.css"></link>
|
||||
</head>
|
||||
<body onload="ready()">
|
||||
<div id="state-downloading" class="state">
|
||||
<h1>Downloading<span class="one">.</span><span class="two">.</span><span class="three">.</span></h1>
|
||||
<progress max="100" value="80" id="download-progress"></progress>
|
||||
<div id="progress-bytes">10 MB / 4.0 MB</div>
|
||||
<div id="download-summary">
|
||||
Sit tight, we are downloading content for your home
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="state-installing" class="state">
|
||||
<h1>Installing<span class="one">.</span><span class="two">.</span><span class="three">.</span></h1>
|
||||
<em>Just a moment</em>
|
||||
</div>
|
||||
|
||||
<div id="state-complete" class="state">
|
||||
<h1>Success!</h1>
|
||||
<em>You're all set.</em>
|
||||
</div>
|
||||
|
||||
<div id="state-error" class="state">
|
||||
<h1>Houston...</h1>
|
||||
<em>An unfortunate error has occurred:</em>
|
||||
<div id="error-message" class="selectable">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
52
console/src/downloader.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
function ready() {
|
||||
console.log("Ready");
|
||||
|
||||
const electron = require('electron');
|
||||
const remote = require('remote');
|
||||
window.$ = require('./vendor/jquery/jquery-2.1.4.min.js');
|
||||
|
||||
$(".state").hide();
|
||||
|
||||
var currentState = null;
|
||||
|
||||
function updateState(state, args) {
|
||||
if (state == 'downloading') {
|
||||
function formatBytes(size) {
|
||||
return (size / 1000000).toFixed('2');
|
||||
}
|
||||
$('#download-progress').attr('value', args.percentage * 100);
|
||||
if (args.size !== null && args.size.transferred !== null && args.size.total !== null) {
|
||||
var progressString = formatBytes(args.size.transferred) + "MB / " + formatBytes(args.size.total) + "MB";
|
||||
$('#progress-bytes').html(progressString);
|
||||
} else {
|
||||
$('#progress-bytes').html("Retrieving resources...");
|
||||
}
|
||||
} else if (state == 'installing') {
|
||||
} else if (state == 'complete') {
|
||||
setTimeout(function() {
|
||||
remote.getCurrentWindow().close();
|
||||
}, 2000);
|
||||
} else if (state == 'error') {
|
||||
$('#error-message').html(args.message);
|
||||
}
|
||||
|
||||
if (currentState != state) {
|
||||
if (currentState) {
|
||||
$('#state-' + currentState).hide();
|
||||
}
|
||||
$('#state-' + state).show();
|
||||
currentState = state;
|
||||
}
|
||||
}
|
||||
|
||||
electron.ipcRenderer.on('update', function(event, message) {
|
||||
updateState(message.state, message.args);
|
||||
});
|
||||
|
||||
// updateState('error', { message: "This is an error message", progress: 0.5 });
|
||||
// updateState('complete', { progress: 0 });
|
||||
// updateState('downloading', { percentage: 0.5, size: { total: 83040400, transferred: 500308} });
|
||||
|
||||
updateState('downloading', { percentage: 0, size: null });
|
||||
electron.ipcRenderer.send('ready');
|
||||
}
|
BIN
console/src/images/console-hf-logo-2x.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
console/src/images/console-menubar-osx-2x.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
console/src/images/console-menubar-windows-2x.png
Normal file
After Width: | Height: | Size: 52 KiB |
67
console/src/log.css
Normal 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
|
@ -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
|
@ -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();
|
||||
};
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
45
console/src/modules/config.js
Normal 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;
|
|
@ -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;
|
||||
|
|
46
console/src/modules/hf-updater.js
Normal 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;
|
|
@ -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
|
@ -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
|
@ -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
|
@ -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'));
|
||||
});
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -74,6 +74,9 @@ private slots:
|
|||
void sendHeartbeatToIceServer();
|
||||
|
||||
void handleConnectedNode(SharedNodePointer newNode);
|
||||
|
||||
void handleTempDomainSuccess(QNetworkReply& requestReply);
|
||||
void handleTempDomainError(QNetworkReply& requestReply);
|
||||
|
||||
private:
|
||||
void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid());
|
||||
|
@ -81,10 +84,13 @@ private:
|
|||
bool optionallyReadX509KeyAndCertificate();
|
||||
bool optionallySetupAssignmentPayment();
|
||||
|
||||
void optionallyGetTemporaryName(const QStringList& arguments);
|
||||
|
||||
bool didSetupAccountManagerWithAccessToken();
|
||||
bool resetAccountManagerAccessToken();
|
||||
|
||||
void setupAutomaticNetworking();
|
||||
void setupICEHeartbeatForFullNetworking();
|
||||
void sendHeartbeatToDataServer(const QString& networkAddress);
|
||||
|
||||
unsigned int countConnectedUsers();
|
||||
|
@ -144,6 +150,8 @@ private:
|
|||
DomainServerSettingsManager _settingsManager;
|
||||
|
||||
HifiSockAddr _iceServerSocket;
|
||||
|
||||
QTimer* _iceHeartbeatTimer { nullptr }; // this looks like it dangles when created but it's parented to the DomainServer
|
||||
|
||||
friend class DomainGatekeeper;
|
||||
};
|
||||
|
|
|
@ -193,7 +193,7 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection
|
|||
qDebug() << "DomainServerSettingsManager postedObject -" << postedObject;
|
||||
|
||||
// we recurse one level deep below each group for the appropriate setting
|
||||
recurseJSONObjectAndOverwriteSettings(postedObject, _configMap.getUserConfig());
|
||||
recurseJSONObjectAndOverwriteSettings(postedObject);
|
||||
|
||||
// store whatever the current _settingsMap is to file
|
||||
persistToFile();
|
||||
|
@ -407,8 +407,9 @@ QJsonObject DomainServerSettingsManager::settingDescriptionFromGroup(const QJson
|
|||
return QJsonObject();
|
||||
}
|
||||
|
||||
void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject,
|
||||
QVariantMap& settingsVariant) {
|
||||
void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject) {
|
||||
auto& settingsVariant = _configMap.getUserConfig();
|
||||
|
||||
// Iterate on the setting groups
|
||||
foreach(const QString& rootKey, postedObject.keys()) {
|
||||
QJsonValue rootValue = postedObject[rootKey];
|
||||
|
@ -481,6 +482,9 @@ void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
|||
settingsVariant.remove(rootKey);
|
||||
}
|
||||
}
|
||||
|
||||
// re-merge the user and master configs after a settings change
|
||||
_configMap.mergeMasterAndUserConfigs();
|
||||
}
|
||||
|
||||
void DomainServerSettingsManager::persistToFile() {
|
||||
|
|
|
@ -46,7 +46,7 @@ private slots:
|
|||
|
||||
private:
|
||||
QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false);
|
||||
void recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, QVariantMap& settingsVariant);
|
||||
void recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject);
|
||||
|
||||
void updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap,
|
||||
const QJsonObject& settingDescription);
|
||||
|
@ -56,6 +56,8 @@ private:
|
|||
double _descriptionVersion;
|
||||
QJsonArray _descriptionArray;
|
||||
HifiConfigVariantMap _configMap;
|
||||
|
||||
friend class DomainServer;
|
||||
};
|
||||
|
||||
#endif // hifi_DomainServerSettingsManager_h
|
||||
|
|
|
@ -27,7 +27,7 @@ IceServer::IceServer(int argc, char* argv[]) :
|
|||
_id(QUuid::createUuid()),
|
||||
_serverSocket(),
|
||||
_activePeers(),
|
||||
_httpManager(ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this)
|
||||
_httpManager(QHostAddress::AnyIPv4, ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this)
|
||||
{
|
||||
// start the ice-server socket
|
||||
qDebug() << "ice-server socket is listening on" << ICE_SERVER_DEFAULT_PORT;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -23,8 +23,9 @@
|
|||
const int SOCKET_ERROR_EXIT_CODE = 2;
|
||||
const int SOCKET_CHECK_INTERVAL_IN_MS = 30000;
|
||||
|
||||
HTTPManager::HTTPManager(quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler, QObject* parent) :
|
||||
HTTPManager::HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler, QObject* parent) :
|
||||
QTcpServer(parent),
|
||||
_listenAddress(listenAddress),
|
||||
_documentRoot(documentRoot),
|
||||
_requestHandler(requestHandler),
|
||||
_port(port)
|
||||
|
@ -178,7 +179,7 @@ void HTTPManager::isTcpServerListening() {
|
|||
bool HTTPManager::bindSocket() {
|
||||
qCDebug(embeddedwebserver) << "Attempting to bind TCP socket on port " << QString::number(_port);
|
||||
|
||||
if (listen(QHostAddress::AnyIPv4, _port)) {
|
||||
if (listen(_listenAddress, _port)) {
|
||||
qCDebug(embeddedwebserver) << "TCP socket is listening on" << serverAddress() << "and port" << serverPort();
|
||||
|
||||
return true;
|
||||
|
|
|
@ -33,7 +33,7 @@ class HTTPManager : public QTcpServer, public HTTPRequestHandler {
|
|||
Q_OBJECT
|
||||
public:
|
||||
/// Initializes the manager.
|
||||
HTTPManager(quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler = NULL, QObject* parent = 0);
|
||||
HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler = NULL, QObject* parent = 0);
|
||||
|
||||
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false);
|
||||
|
||||
|
@ -49,6 +49,7 @@ protected:
|
|||
virtual void incomingConnection(qintptr socketDescriptor);
|
||||
virtual bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url);
|
||||
|
||||
QHostAddress _listenAddress;
|
||||
QString _documentRoot;
|
||||
HTTPRequestHandler* _requestHandler;
|
||||
QTimer* _isListeningTimer;
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
|
||||
#include "HTTPSManager.h"
|
||||
|
||||
HTTPSManager::HTTPSManager(quint16 port, const QSslCertificate& certificate, const QSslKey& privateKey,
|
||||
HTTPSManager::HTTPSManager(QHostAddress listenAddress, quint16 port, const QSslCertificate& certificate, const QSslKey& privateKey,
|
||||
const QString& documentRoot, HTTPSRequestHandler* requestHandler, QObject* parent) :
|
||||
HTTPManager(port, documentRoot, requestHandler, parent),
|
||||
HTTPManager(listenAddress, port, documentRoot, requestHandler, parent),
|
||||
_certificate(certificate),
|
||||
_privateKey(privateKey),
|
||||
_sslRequestHandler(requestHandler)
|
||||
|
|
|
@ -26,7 +26,8 @@ public:
|
|||
class HTTPSManager : public HTTPManager, public HTTPSRequestHandler {
|
||||
Q_OBJECT
|
||||
public:
|
||||
HTTPSManager(quint16 port,
|
||||
HTTPSManager(QHostAddress listenAddress,
|
||||
quint16 port,
|
||||
const QSslCertificate& certificate,
|
||||
const QSslKey& privateKey,
|
||||
const QString& documentRoot,
|
||||
|
@ -35,12 +36,12 @@ public:
|
|||
void setCertificate(const QSslCertificate& certificate) { _certificate = certificate; }
|
||||
void setPrivateKey(const QSslKey& privateKey) { _privateKey = privateKey; }
|
||||
|
||||
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false);
|
||||
bool handleHTTPSRequest(HTTPSConnection* connection, const QUrl& url, bool skipSubHandler = false);
|
||||
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override;
|
||||
bool handleHTTPSRequest(HTTPSConnection* connection, const QUrl& url, bool skipSubHandler = false) override;
|
||||
|
||||
protected:
|
||||
void incomingConnection(qintptr socketDescriptor);
|
||||
bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url);
|
||||
void incomingConnection(qintptr socketDescriptor) override;
|
||||
bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url) override;
|
||||
private:
|
||||
QSslCertificate _certificate;
|
||||
QSslKey _privateKey;
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const RenderableEntityItemProxy::Pointer& payload);
|
||||
template <> const ItemKey payloadGetKey(const RenderableEntityItemProxy::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const RenderableEntityItemProxy::Pointer& payload);
|
||||
template <> void payloadRender(const RenderableEntityItemProxy::Pointer& payload, RenderArgs* args);
|
||||
}
|
||||
|
@ -73,8 +73,8 @@ private:
|
|||
|
||||
#define SIMPLE_RENDERABLE() \
|
||||
public: \
|
||||
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) { return _renderHelper.addToScene(self, scene, pendingChanges); } \
|
||||
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) { _renderHelper.removeFromScene(self, scene, pendingChanges); } \
|
||||
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override { return _renderHelper.addToScene(self, scene, pendingChanges); } \
|
||||
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override { _renderHelper.removeFromScene(self, scene, pendingChanges); } \
|
||||
private: \
|
||||
SimpleRenderableEntityItem _renderHelper;
|
||||
|
||||
|
|
|
@ -27,19 +27,19 @@ public:
|
|||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
static void createPipeline();
|
||||
RenderablePolyLineEntityItem(const EntityItemID& entityItemID);
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
|
||||
virtual void render(RenderArgs* args) override;
|
||||
virtual void update(const quint64& now) override;
|
||||
virtual bool needsToCallUpdate() const { return true; };
|
||||
|
||||
virtual bool needsToCallUpdate() const override { return true; };
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
|
||||
|
||||
NetworkTexturePointer _texture;
|
||||
|
||||
static gpu::PipelinePointer _pipeline;
|
||||
static gpu::Stream::FormatPointer _format;
|
||||
static int32_t PAINTSTROKE_GPU_SLOT;
|
||||
|
||||
|
||||
protected:
|
||||
void updateGeometry();
|
||||
void updateVertices();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -9,8 +9,11 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "HifiConfigVariantMap.h"
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonArray>
|
||||
|
@ -18,8 +21,8 @@
|
|||
#include <QtCore/QStandardPaths>
|
||||
#include <QtCore/QVariant>
|
||||
|
||||
#include "ServerPathUtils.h"
|
||||
#include "SharedLogging.h"
|
||||
#include "HifiConfigVariantMap.h"
|
||||
|
||||
QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringList& argumentList) {
|
||||
|
||||
|
@ -110,18 +113,54 @@ void HifiConfigVariantMap::loadMasterAndUserConfig(const QStringList& argumentLi
|
|||
|
||||
// load the user config
|
||||
const QString USER_CONFIG_FILE_OPTION = "--user-config";
|
||||
static const QString USER_CONFIG_FILE_NAME = "config.json";
|
||||
|
||||
int userConfigIndex = argumentList.indexOf(USER_CONFIG_FILE_OPTION);
|
||||
if (userConfigIndex != -1) {
|
||||
_userConfigFilename = argumentList[userConfigIndex + 1];
|
||||
} else {
|
||||
_userConfigFilename = QString("%1/%2/%3/config.json").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation),
|
||||
QCoreApplication::organizationName(),
|
||||
QCoreApplication::applicationName());
|
||||
// we weren't passed a user config path
|
||||
_userConfigFilename = ServerPathUtils::getDataFilePath(USER_CONFIG_FILE_NAME);
|
||||
|
||||
// as of 1/19/2016 this path was moved so we attempt a migration for first run post migration here
|
||||
|
||||
// figure out what the old path was
|
||||
auto oldConfigFilename = QString("%1/%2/%3/%4").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation),
|
||||
QCoreApplication::organizationName(),
|
||||
QCoreApplication::applicationName(),
|
||||
USER_CONFIG_FILE_NAME);
|
||||
|
||||
// check if there's already a config file at the new path
|
||||
QFile newConfigFile { _userConfigFilename };
|
||||
if (!newConfigFile.exists()) {
|
||||
QFile oldConfigFile { oldConfigFilename };
|
||||
|
||||
if (oldConfigFile.exists()) {
|
||||
// we have the old file and not the new file - time to copy the file
|
||||
|
||||
// make the destination directory if it doesn't exist
|
||||
auto dataDirectory = ServerPathUtils::getDataDirectory();
|
||||
if (QDir().mkpath(dataDirectory)) {
|
||||
if (oldConfigFile.copy(_userConfigFilename)) {
|
||||
qDebug() << "Migrated config file from" << oldConfigFilename << "to" << _userConfigFilename;
|
||||
} else {
|
||||
qWarning() << "Could not copy previous config file from" << oldConfigFilename << "to" << _userConfigFilename
|
||||
<< "- please try to copy manually and restart.";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Could not create application data directory" << dataDirectory << "- unable to migrate previous config file.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
loadMapFromJSONFile(_userConfig, _userConfigFilename);
|
||||
|
||||
mergeMasterAndUserConfigs();
|
||||
}
|
||||
|
||||
void HifiConfigVariantMap::mergeMasterAndUserConfigs() {
|
||||
// the merged config is initially matched to the master config
|
||||
_mergedConfig = _masterConfig;
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_HifiConfigVariantMap_h
|
||||
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVariantMap>
|
||||
|
||||
class HifiConfigVariantMap {
|
||||
public:
|
||||
|
@ -25,6 +26,8 @@ public:
|
|||
QVariantMap& getUserConfig() { return _userConfig; }
|
||||
QVariantMap& getMergedConfig() { return _mergedConfig; }
|
||||
|
||||
void mergeMasterAndUserConfigs();
|
||||
|
||||
const QString& getUserConfigFilename() const { return _userConfigFilename; }
|
||||
private:
|
||||
QString _userConfigFilename;
|
||||
|
|
|
@ -42,6 +42,8 @@ LogHandler::LogHandler() :
|
|||
|
||||
const char* stringForLogType(LogMsgType msgType) {
|
||||
switch (msgType) {
|
||||
case LogInfo:
|
||||
return "INFO";
|
||||
case LogDebug:
|
||||
return "DEBUG";
|
||||
case LogWarning:
|
||||
|
|
|
@ -22,11 +22,12 @@
|
|||
const int VERBOSE_LOG_INTERVAL_SECONDS = 5;
|
||||
|
||||
enum LogMsgType {
|
||||
LogInfo = QtInfoMsg,
|
||||
LogDebug = QtDebugMsg,
|
||||
LogWarning = QtWarningMsg,
|
||||
LogCritical = QtCriticalMsg,
|
||||
LogFatal = QtFatalMsg,
|
||||
LogSuppressed
|
||||
LogSuppressed = 100
|
||||
};
|
||||
|
||||
/// Handles custom message handling and sending of stats/logs to Logstash instance
|
||||
|
|
37
libraries/shared/src/ServerPathUtils.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// ServerPathUtils.cpp
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Ryan Huffman on 01/12/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "ServerPathUtils.h"
|
||||
|
||||
#include <QStandardPaths>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtWidgets/qapplication.h>
|
||||
#include <QDebug>
|
||||
|
||||
QString ServerPathUtils::getDataDirectory() {
|
||||
auto dataPath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
dataPath += "/AppData/Roaming/";
|
||||
#elif defined(Q_OS_OSX)
|
||||
dataPath += "/Library/Application Support/";
|
||||
#else
|
||||
dataPath += "/.local/share/";
|
||||
#endif
|
||||
|
||||
dataPath += qApp->organizationName() + "/" + qApp->applicationName();
|
||||
|
||||
return QDir::cleanPath(dataPath);
|
||||
}
|
||||
|
||||
QString ServerPathUtils::getDataFilePath(QString filename) {
|
||||
return QDir(getDataDirectory()).absoluteFilePath(filename);
|
||||
}
|
||||
|
22
libraries/shared/src/ServerPathUtils.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// ServerPathUtils.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Ryan Huffman on 01/12/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ServerPathUtils_h
|
||||
#define hifi_ServerPathUtils_h
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace ServerPathUtils {
|
||||
QString getDataDirectory();
|
||||
QString getDataFilePath(QString filename);
|
||||
}
|
||||
|
||||
#endif // hifi_ServerPathUtils_h
|
Before Width: | Height: | Size: 151 KiB |
|
@ -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"
|
|
@ -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()
|
||||
|
|