Add application uploading
This commit is contained in:
parent
a6b151e7bd
commit
2c8ecf21b5
1
deps/tools/Makefile
vendored
1
deps/tools/Makefile
vendored
|
@ -39,6 +39,7 @@ _cscore.so: ../robotpy-cscore/src/_cscore.cpp ../robotpy-cscore/src/ndarray_conv
|
||||||
|
|
||||||
RPICONFIGSERVER_OBJS= \
|
RPICONFIGSERVER_OBJS= \
|
||||||
rpiConfigServer_src/main.o \
|
rpiConfigServer_src/main.o \
|
||||||
|
rpiConfigServer_src/Application.o \
|
||||||
rpiConfigServer_src/MyHttpConnection.o \
|
rpiConfigServer_src/MyHttpConnection.o \
|
||||||
rpiConfigServer_src/NetworkSettings.o \
|
rpiConfigServer_src/NetworkSettings.o \
|
||||||
rpiConfigServer_src/SystemStatus.o \
|
rpiConfigServer_src/SystemStatus.o \
|
||||||
|
|
148
deps/tools/rpiConfigServer_src/Application.cpp
vendored
Normal file
148
deps/tools/rpiConfigServer_src/Application.cpp
vendored
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||||
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||||
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||||
|
/* the project. */
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
|
#include <wpi/FileSystem.h>
|
||||||
|
#include <wpi/json.h>
|
||||||
|
#include <wpi/raw_istream.h>
|
||||||
|
#include <wpi/raw_ostream.h>
|
||||||
|
|
||||||
|
#include "VisionStatus.h"
|
||||||
|
|
||||||
|
#define TYPE_TAG "### TYPE:"
|
||||||
|
|
||||||
|
std::shared_ptr<Application> Application::GetInstance() {
|
||||||
|
static auto inst = std::make_shared<Application>(private_init{});
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::Set(wpi::StringRef appType,
|
||||||
|
std::function<void(wpi::StringRef)> onFail) {
|
||||||
|
wpi::StringRef appDir;
|
||||||
|
wpi::StringRef appCommand;
|
||||||
|
|
||||||
|
if (appType == "builtin") {
|
||||||
|
appCommand = "./multiCameraServer";
|
||||||
|
} else if (appType == "example-java") {
|
||||||
|
appDir = "java-multiCameraServer";
|
||||||
|
appCommand =
|
||||||
|
"env LD_LIBRARY_PATH=/usr/local/frc/lib java -jar "
|
||||||
|
"build/libs/java-multiCameraServer-all.jar";
|
||||||
|
} else if (appType == "example-cpp") {
|
||||||
|
appDir = "cpp-multiCameraServer";
|
||||||
|
appCommand = "./multiCameraServerExample";
|
||||||
|
} else if (appType == "example-python") {
|
||||||
|
appDir = "python-multiCameraServer";
|
||||||
|
appCommand = "./multiCameraServer.py";
|
||||||
|
} else if (appType == "upload-java") {
|
||||||
|
appCommand =
|
||||||
|
"env LD_LIBRARY_PATH=/usr/local/frc/lib java -jar uploaded.jar";
|
||||||
|
} else if (appType == "upload-cpp") {
|
||||||
|
appCommand = "./uploaded";
|
||||||
|
} else if (appType == "upload-python") {
|
||||||
|
appCommand = "./uploaded.py";
|
||||||
|
} else if (appType == "custom") {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
wpi::SmallString<64> msg;
|
||||||
|
msg = "unrecognized application type '";
|
||||||
|
msg += appType;
|
||||||
|
msg += "'";
|
||||||
|
onFail(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// write file
|
||||||
|
std::error_code ec;
|
||||||
|
wpi::raw_fd_ostream os(EXEC_HOME "/runCamera", ec, wpi::sys::fs::F_Text);
|
||||||
|
if (ec) {
|
||||||
|
onFail("could not write " EXEC_HOME "/runCamera");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
os << "#!/bin/sh\n";
|
||||||
|
os << TYPE_TAG << ' ' << appType << '\n';
|
||||||
|
os << "echo \"Waiting 5 seconds...\"\n";
|
||||||
|
os << "sleep 5\n";
|
||||||
|
if (!appDir.empty()) os << "cd " << appDir << '\n';
|
||||||
|
os << "exec " << appCommand << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
m_appType = appType;
|
||||||
|
|
||||||
|
// terminate vision process so it reloads
|
||||||
|
VisionStatus::GetInstance()->Terminate(onFail);
|
||||||
|
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::Upload(wpi::ArrayRef<uint8_t> contents,
|
||||||
|
std::function<void(wpi::StringRef)> onFail) {
|
||||||
|
wpi::StringRef filename;
|
||||||
|
if (m_appType == "upload-java") {
|
||||||
|
filename = "/uploaded.jar";
|
||||||
|
} else if (m_appType == "upload-cpp") {
|
||||||
|
filename = "/uploaded";
|
||||||
|
} else if (m_appType == "upload-python") {
|
||||||
|
filename = "/uploaded.py";
|
||||||
|
} else {
|
||||||
|
wpi::SmallString<64> msg;
|
||||||
|
msg = "cannot upload application type '";
|
||||||
|
msg += m_appType;
|
||||||
|
msg += "'";
|
||||||
|
onFail(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpi::SmallString<64> pathname;
|
||||||
|
pathname = EXEC_HOME;
|
||||||
|
pathname += filename;
|
||||||
|
|
||||||
|
{
|
||||||
|
// write file
|
||||||
|
std::error_code ec;
|
||||||
|
wpi::raw_fd_ostream os(pathname, ec, wpi::sys::fs::F_None);
|
||||||
|
if (ec) {
|
||||||
|
wpi::SmallString<64> msg;
|
||||||
|
msg = "could not write ";
|
||||||
|
msg += pathname;
|
||||||
|
onFail(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
os << contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
// terminate vision process so it reloads
|
||||||
|
VisionStatus::GetInstance()->Terminate(onFail);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::UpdateStatus() { status(GetStatusJson()); }
|
||||||
|
|
||||||
|
wpi::json Application::GetStatusJson() {
|
||||||
|
wpi::json j = {{"type", "applicationSettings"},
|
||||||
|
{"applicationType", "custom"}};
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
wpi::raw_fd_istream is(EXEC_HOME "/runCamera", ec);
|
||||||
|
if (ec) {
|
||||||
|
wpi::errs() << "could not read " EXEC_HOME "/runCamera\n";
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
// scan file
|
||||||
|
wpi::SmallString<256> lineBuf;
|
||||||
|
while (!is.has_error()) {
|
||||||
|
wpi::StringRef line = is.getline(lineBuf, 256).trim();
|
||||||
|
if (line.startswith(TYPE_TAG)) {
|
||||||
|
j["applicationType"] = line.substr(strlen(TYPE_TAG)).trim();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return j;
|
||||||
|
}
|
48
deps/tools/rpiConfigServer_src/Application.h
vendored
Normal file
48
deps/tools/rpiConfigServer_src/Application.h
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||||
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||||
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||||
|
/* the project. */
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef RPICONFIGSERVER_APPLICATION_H_
|
||||||
|
#define RPICONFIGSERVER_APPLICATION_H_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <wpi/ArrayRef.h>
|
||||||
|
#include <wpi/Signal.h>
|
||||||
|
#include <wpi/StringRef.h>
|
||||||
|
|
||||||
|
namespace wpi {
|
||||||
|
class json;
|
||||||
|
} // namespace wpi
|
||||||
|
|
||||||
|
class Application {
|
||||||
|
struct private_init {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Application(const private_init&) {}
|
||||||
|
Application(const Application&) = delete;
|
||||||
|
Application& operator=(const Application&) = delete;
|
||||||
|
|
||||||
|
void Set(wpi::StringRef appType, std::function<void(wpi::StringRef)> onFail);
|
||||||
|
|
||||||
|
void Upload(wpi::ArrayRef<uint8_t> contents,
|
||||||
|
std::function<void(wpi::StringRef)> onFail);
|
||||||
|
|
||||||
|
void UpdateStatus();
|
||||||
|
|
||||||
|
wpi::json GetStatusJson();
|
||||||
|
|
||||||
|
wpi::sig::Signal<const wpi::json&> status;
|
||||||
|
|
||||||
|
static std::shared_ptr<Application> GetInstance();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_appType;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // RPICONFIGSERVER_APPLICATION_H_
|
|
@ -18,6 +18,7 @@
|
||||||
#include <wpi/uv/Pipe.h>
|
#include <wpi/uv/Pipe.h>
|
||||||
#include <wpi/uv/Process.h>
|
#include <wpi/uv/Process.h>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
#include "NetworkSettings.h"
|
#include "NetworkSettings.h"
|
||||||
#include "SystemStatus.h"
|
#include "SystemStatus.h"
|
||||||
#include "VisionSettings.h"
|
#include "VisionSettings.h"
|
||||||
|
@ -36,6 +37,7 @@ struct WebSocketData {
|
||||||
wpi::sig::ScopedConnection visLogConn;
|
wpi::sig::ScopedConnection visLogConn;
|
||||||
wpi::sig::ScopedConnection netSettingsConn;
|
wpi::sig::ScopedConnection netSettingsConn;
|
||||||
wpi::sig::ScopedConnection visSettingsConn;
|
wpi::sig::ScopedConnection visSettingsConn;
|
||||||
|
wpi::sig::ScopedConnection appSettingsConn;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void SendWsText(wpi::WebSocket& ws, const wpi::json& j) {
|
static void SendWsText(wpi::WebSocket& ws, const wpi::json& j) {
|
||||||
|
@ -136,6 +138,13 @@ void InitWs(wpi::WebSocket& ws) {
|
||||||
visSettingsFunc(visSettings->GetStatusJson());
|
visSettingsFunc(visSettings->GetStatusJson());
|
||||||
data->visSettingsConn =
|
data->visSettingsConn =
|
||||||
visSettings->status.connect_connection(visSettingsFunc);
|
visSettings->status.connect_connection(visSettingsFunc);
|
||||||
|
|
||||||
|
// send initial application settings
|
||||||
|
auto appSettings = Application::GetInstance();
|
||||||
|
auto appSettingsFunc = [&ws](const wpi::json& j) { SendWsText(ws, j); };
|
||||||
|
appSettingsFunc(appSettings->GetStatusJson());
|
||||||
|
data->appSettingsConn =
|
||||||
|
appSettings->status.connect_connection(appSettingsFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessWsText(wpi::WebSocket& ws, wpi::StringRef msg) {
|
void ProcessWsText(wpi::WebSocket& ws, wpi::StringRef msg) {
|
||||||
|
@ -251,8 +260,25 @@ void ProcessWsText(wpi::WebSocket& ws, wpi::StringRef msg) {
|
||||||
wpi::errs() << "could not read networkSave value: " << e.what() << '\n';
|
wpi::errs() << "could not read networkSave value: " << e.what() << '\n';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (t == "applicationSave") {
|
||||||
|
auto statusFunc = [s = ws.shared_from_this()](wpi::StringRef msg) {
|
||||||
|
SendWsText(*s, {{"type", "status"}, {"message", msg}});
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
Application::GetInstance()->Set(
|
||||||
|
j.at("applicationType").get_ref<const std::string&>(), statusFunc);
|
||||||
|
} catch (const wpi::json::exception& e) {
|
||||||
|
wpi::errs() << "could not read applicationSave value: " << e.what()
|
||||||
|
<< '\n';
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessWsBinary(wpi::WebSocket& ws, wpi::ArrayRef<uint8_t> msg) {}
|
void ProcessWsBinary(wpi::WebSocket& ws, wpi::ArrayRef<uint8_t> msg) {
|
||||||
|
auto statusFunc = [s = ws.shared_from_this()](wpi::StringRef msg) {
|
||||||
|
SendWsText(*s, {{"type", "status"}, {"message", msg}});
|
||||||
|
};
|
||||||
|
Application::GetInstance()->Upload(msg, statusFunc);
|
||||||
|
SendWsText(ws, {{"type", "applicationSaveComplete"}});
|
||||||
|
}
|
||||||
|
|
|
@ -484,6 +484,8 @@ $('#addCamera').click(function() {
|
||||||
appendNewVisionCameraView({}, i);
|
appendNewVisionCameraView({}, i);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var applicationFiles = [];
|
||||||
|
|
||||||
// Show details when appropriate for application type
|
// Show details when appropriate for application type
|
||||||
function updateApplicationView() {
|
function updateApplicationView() {
|
||||||
if ($('#applicationType').val().startsWith("upload")) {
|
if ($('#applicationType').val().startsWith("upload")) {
|
||||||
|
@ -492,12 +494,17 @@ function updateApplicationView() {
|
||||||
$('#applicationUpload').collapse('hide');
|
$('#applicationUpload').collapse('hide');
|
||||||
}
|
}
|
||||||
$('#applicationFile').val(null);
|
$('#applicationFile').val(null);
|
||||||
|
applicationFiles = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#applicationType').change(function() {
|
$('#applicationType').change(function() {
|
||||||
updateApplicationView();
|
updateApplicationView();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#applicationFile').change(function() {
|
||||||
|
applicationFiles = this.files;
|
||||||
|
});
|
||||||
|
|
||||||
$('#applicationSave').click(function() {
|
$('#applicationSave').click(function() {
|
||||||
var msg = {
|
var msg = {
|
||||||
type: 'applicationSave',
|
type: 'applicationSave',
|
||||||
|
@ -506,8 +513,7 @@ $('#applicationSave').click(function() {
|
||||||
connection.send(JSON.stringify(msg));
|
connection.send(JSON.stringify(msg));
|
||||||
|
|
||||||
// upload the file if requested
|
// upload the file if requested
|
||||||
var f = $('#applicationFile');
|
if (applicationFiles.length <= 0) {
|
||||||
if (f.files.length <= 0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$('#applicationSave').button('loading');
|
$('#applicationSave').button('loading');
|
||||||
|
@ -515,7 +521,7 @@ $('#applicationSave').click(function() {
|
||||||
fr.onload = function(e) {
|
fr.onload = function(e) {
|
||||||
connection.send(e.target.result);
|
connection.send(e.target.result);
|
||||||
};
|
};
|
||||||
fr.readAsArrayBuffer(f.files.item(0));
|
fr.readAsArrayBuffer(applicationFiles.item(0));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start with display disconnected and start initial connection attempt
|
// Start with display disconnected and start initial connection attempt
|
||||||
|
|
Loading…
Reference in New Issue
Block a user