9 Commits

Author SHA1 Message Date
fac2feb598 less borders 2025-06-26 11:33:03 +02:00
3e8be87ad1 something working? 2025-06-26 11:24:50 +02:00
1a2f7fc32b dump 3 2025-06-26 08:03:35 +02:00
49b16cda2f webview jank 2025-06-25 19:21:34 +02:00
2bad240a21 some stuff
but it's somehow not possible to restart jvm after destruction, so it has to be redone anyway
2025-06-25 19:21:34 +02:00
5d88401775 a little exception handling 2025-06-25 19:21:34 +02:00
f3a6650cb7 dump 2 2025-06-25 19:21:34 +02:00
53ba9dc12e a start button 2025-06-25 19:21:34 +02:00
3f6d66330a dump 2025-06-25 19:21:34 +02:00
22 changed files with 2264 additions and 0 deletions

80
launcher/.gitignore vendored Normal file
View File

@@ -0,0 +1,80 @@
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
build/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
Testing

33
launcher/CMakeLists.txt Normal file
View File

@@ -0,0 +1,33 @@
cmake_minimum_required(VERSION 3.10)
project(launcher)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
# if (NOT DEFINED SANITIZE)
# set(SANITIZE YES)
# endif ()
endif ()
if (SANITIZE STREQUAL "YES")
message(STATUS "Enabling sanitizers!")
add_compile_options(-Werror -O0 -Wall -Wextra -pedantic -Wno-unused-parameter -Wno-unused-variable
-Wno-error=unused-function
-Wshadow -Wformat=2 -Wfloat-equal -D_GLIBCXX_DEBUG -Wconversion)
add_compile_options(-fsanitize=address -fno-sanitize-recover)
add_link_options(-fsanitize=address -fno-sanitize-recover)
endif ()
if (CMAKE_BUILD_TYPE STREQUAL "Release")
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif ()
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_options(-O3)
add_link_options(-O3)
endif ()
add_subdirectory(utils)
add_subdirectory(backend)
add_subdirectory(gui)

View File

@@ -0,0 +1,19 @@
find_package(wxWidgets REQUIRED COMPONENTS base)
if (wxWidgets_USE_FILE) # not defined in CONFIG mode
include(${wxWidgets_USE_FILE})
endif ()
add_library(backend
src/DhfsInstance.cpp
include_public/DhfsInstance.hpp
src/DhfsStartOptions.cpp
include_public/DhfsStartOptions.hpp
src/DhfsWxProcess.cpp
include_public/DhfsWxProcess.hpp
)
target_include_directories(backend PRIVATE include)
target_include_directories(backend PUBLIC include_public)
target_link_libraries(backend PRIVATE ${wxWidgets_LIBRARIES})
target_link_libraries(backend PUBLIC utils)

View File

@@ -0,0 +1,49 @@
//
// Created by stepus53 on 24.6.25.
//
#ifndef DHFSINSTANCE_HPP
#define DHFSINSTANCE_HPP
#include <wx/process.h>
#include <string>
#include <vector>
#include <thread>
#include<mutex>
#include "DhfsStartOptions.hpp"
#include "DhfsWxProcess.hpp"
enum class DhfsInstanceState {
RUNNING,
STOPPED,
};
class DhfsInstance {
public:
DhfsInstance();
virtual ~DhfsInstance();
DhfsInstanceState state();
void start(DhfsStartOptions start_options);
void stop();
virtual void OnTerminate(int pid, int status) = 0;
virtual void OnRead(std::string s) = 0;
protected:
std::unique_ptr<DhfsWxProcess> process = std::make_unique<DhfsWxProcess>(*this);
private:
DhfsInstanceState _state = DhfsInstanceState::STOPPED;
std::thread _readThread;
std::thread _readThreadErr;
std::mutex _mutex;
};
#endif //DHFSINSTANCE_HPP

View File

@@ -0,0 +1,25 @@
//
// Created by Stepan Usatiuk on 25.06.2025.
//
#ifndef DHFSSTARTOPTIONS_HPP
#define DHFSSTARTOPTIONS_HPP
#include <string>
#include <vector>
class DhfsStartOptions {
public:
std::string java_home;
std::string xmx;
std::string mount_path;
std::string data_path;
std::string jar_path;
std::string webui_path;
std::vector<std::string> extra_options;
std::vector<std::string> getOptions();
};
#endif //DHFSSTARTOPTIONS_HPP

View File

@@ -0,0 +1,24 @@
//
// Created by Stepan Usatiuk on 25.06.2025.
//
#ifndef DHFSWXPROCESS_HPP
#define DHFSWXPROCESS_HPP
#include <wx/process.h>
class DhfsInstance;
class DhfsWxProcess : public wxProcess {
public:
DhfsWxProcess(DhfsInstance& parent);
protected:
void OnTerminate(int pid, int status) override;
private:
DhfsInstance& _instance;
};
#endif //DHFSWXPROCESS_HPP

View File

@@ -0,0 +1,100 @@
//
// Created by stepus53 on 24.6.25.
//
#include "DhfsInstance.hpp"
#include <stdexcept>
#include <vector>
#include "Exception.h"
DhfsInstance::DhfsInstance() {
}
DhfsInstance::~DhfsInstance() {
stop();
}
DhfsInstanceState DhfsInstance::state() {
std::lock_guard<std::mutex> lock(_mutex);
return _state;
}
void DhfsInstance::start(DhfsStartOptions options) {
std::lock_guard<std::mutex> lock(_mutex);
switch (_state) {
case DhfsInstanceState::RUNNING:
return;
case DhfsInstanceState::STOPPED:
break;
default:
throw std::runtime_error("Unknown DhfsInstanceState");
}
_state = DhfsInstanceState::RUNNING;
std::vector<char*> args;
auto readyOptions = options.getOptions();
for (const auto& option: readyOptions) {
args.push_back(const_cast<char*>(option.c_str()));
}
long ret = wxExecute(args.data(), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER, process.get(),
nullptr);
if (ret == 0) {
_state = DhfsInstanceState::STOPPED;
throw Exception("Failed to start DHFS");
}
OnRead("Started! " + std::to_string(ret) + " PID: " + std::to_string(process->GetPid()) + "\n");
_readThread = std::thread([&]() {
auto stream = process->GetInputStream();
while (!stream->Eof() || stream->CanRead()) {
char buffer[1024];
size_t bytesRead = stream->Read(buffer, sizeof(buffer) - 1).LastRead();
if (bytesRead > 0) {
buffer[bytesRead] = '\0'; // Null-terminate the string
OnRead(std::string(buffer));
} else if (bytesRead == 0) {
break; // EOF reached
}
}
});
_readThreadErr = std::thread([&]() {
auto stream = process->GetErrorStream();
while (!stream->Eof() || stream->CanRead()) {
char buffer[1024];
size_t bytesRead = stream->Read(buffer, sizeof(buffer) - 1).LastRead();
if (bytesRead > 0) {
buffer[bytesRead] = '\0'; // Null-terminate the string
OnRead(std::string(buffer));
} else if (bytesRead == 0) {
break; // EOF reached
}
}
});
}
void DhfsInstance::stop() {
std::lock_guard<std::mutex> lock(_mutex);
switch (_state) {
case DhfsInstanceState::RUNNING:
break;
case DhfsInstanceState::STOPPED:
return;
default:
throw std::runtime_error("Unknown DhfsInstanceState");
}
_state = DhfsInstanceState::STOPPED;
int err = wxProcess::Kill(process->GetPid(), wxSIGTERM, wxKILL_CHILDREN);
_readThread.join();
_readThreadErr.join();
OnRead("Stopped!\n");
if (err != wxKILL_OK) {
OnRead("Failed to stop DHFS: " + std::to_string(err) + "\n");
}
OnTerminate(0, 0);
}

View File

@@ -0,0 +1,31 @@
//
// Created by Stepan Usatiuk on 25.06.2025.
//
#include "DhfsStartOptions.hpp"
std::vector<std::string> DhfsStartOptions::getOptions() {
std::vector<std::string> out;
out.emplace_back(java_home + "/bin/java");
out.emplace_back("--enable-preview");
out.emplace_back("-Xmx" + xmx);
out.emplace_back("-Ddhfs.objects.writeback.limit=16777216");
out.emplace_back("-Ddhfs.objects.lru.limit=67108864");
out.emplace_back("--add-exports");
out.emplace_back("java.base/sun.nio.ch=ALL-UNNAMED");
out.emplace_back("--add-exports");
out.emplace_back("java.base/jdk.internal.access=ALL-UNNAMED");
out.emplace_back("--add-opens=java.base/java.nio=ALL-UNNAMED");
out.emplace_back("-Dquarkus.http.host=0.0.0.0");
out.emplace_back("-Dquarkus.log.category.\"com.usatiuk\".level=INFO");
out.emplace_back("-Dquarkus.log.category.\"com.usatiuk.dhfs\".level=INFO");
out.emplace_back("-Ddhfs.fuse.root=" + mount_path);
out.emplace_back("-Ddhfs.objects.persistence.root=" + data_path);
out.emplace_back("-Ddhfs.webui.root=" + webui_path);
for (auto option: extra_options) {
out.emplace_back(option);
}
out.emplace_back("-jar");
out.emplace_back(jar_path);
return out;
}

View File

@@ -0,0 +1,14 @@
//
// Created by Stepan Usatiuk on 25.06.2025.
//
#include "DhfsWxProcess.hpp"
#include "DhfsInstance.hpp"
DhfsWxProcess::DhfsWxProcess(DhfsInstance& parent): wxProcess(wxPROCESS_REDIRECT), _instance(parent) {
}
void DhfsWxProcess::OnTerminate(int pid, int status) {
_instance.stop();
}

View File

@@ -0,0 +1,16 @@
find_package(wxWidgets REQUIRED COMPONENTS net core base webview)
if (wxWidgets_USE_FILE) # not defined in CONFIG mode
include(${wxWidgets_USE_FILE})
endif ()
add_executable(launcher
src/LauncherApp.cpp
src/GLauncherApp.cpp
src/LauncherAppMainFrame.cpp
src/DhfsGuiInstance.cpp
src/DhfsGuiInstance.hpp
)
target_link_libraries(launcher ${wxWidgets_LIBRARIES})
target_link_libraries(launcher backend utils)

View File

@@ -0,0 +1,23 @@
//
// Created by Stepan Usatiuk on 25.06.2025.
//
#include "DhfsGuiInstance.hpp"
#include "LauncherAppMainFrame.h"
DhfsGuiInstance::DhfsGuiInstance(LauncherAppMainFrame& parent): _parent(parent) {
}
void DhfsGuiInstance::OnTerminate(int pid, int status) {
wxCommandEvent* event = new wxCommandEvent(SHUTDOWN_EVENT, _parent.GetId());
event->SetEventObject(&_parent);
_parent.GetEventHandler()->QueueEvent(event);
}
void DhfsGuiInstance::OnRead(std::string s) {
wxCommandEvent* event = new wxCommandEvent(NEW_LINE_OUTPUT_EVENT, _parent.GetId());
event->SetEventObject(&_parent);
event->SetString(std::move(s));
_parent.GetEventHandler()->QueueEvent(event);
}

View File

@@ -0,0 +1,25 @@
//
// Created by Stepan Usatiuk on 25.06.2025.
//
#ifndef DHFSGUIINSTANCE_HPP
#define DHFSGUIINSTANCE_HPP
#include "DhfsInstance.hpp"
class LauncherAppMainFrame;
class DhfsGuiInstance : public DhfsInstance {
public:
DhfsGuiInstance(LauncherAppMainFrame& parent);
void OnTerminate(int pid, int status) override;
void OnRead(std::string s) override;
protected:
LauncherAppMainFrame& _parent;
};
#endif //DHFSGUIINSTANCE_HPP

View File

@@ -0,0 +1,161 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "GLauncherApp.h"
///////////////////////////////////////////////////////////////////////////
MainFrame::MainFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : wxFrame( parent, id, title, pos, size, style, name )
{
this->SetSizeHints( wxSize( 600,400 ), wxDefaultSize );
m_statusBar1 = this->CreateStatusBar( 1, wxSTB_SIZEGRIP, wxID_ANY );
wxBoxSizer* bSizer3;
bSizer3 = new wxBoxSizer( wxVERTICAL );
m_notebook1 = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0|wxBORDER_NONE );
m_panel1 = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer2;
bSizer2 = new wxBoxSizer( wxVERTICAL );
wxStaticBoxSizer* sbSizer4;
sbSizer4 = new wxStaticBoxSizer( new wxStaticBox( m_panel1, wxID_ANY, _("Status") ), wxVERTICAL );
wxGridBagSizer* gbSizer1;
gbSizer1 = new wxGridBagSizer( 0, 0 );
gbSizer1->SetFlexibleDirection( wxBOTH );
gbSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_statusText = new wxStaticText( sbSizer4->GetStaticBox(), wxID_ANY, _("Running"), wxDefaultPosition, wxDefaultSize, 0 );
m_statusText->Wrap( -1 );
gbSizer1->Add( m_statusText, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_startStopButton = new wxButton( sbSizer4->GetStaticBox(), wxID_ANY, _("Start"), wxDefaultPosition, wxDefaultSize, 0 );
gbSizer1->Add( m_startStopButton, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
sbSizer4->Add( gbSizer1, 1, wxEXPAND, 5 );
bSizer2->Add( sbSizer4, 1, wxALL|wxEXPAND, 5 );
wxStaticBoxSizer* sbSizer6;
sbSizer6 = new wxStaticBoxSizer( new wxStaticBox( m_panel1, wxID_ANY, _("Statistics") ), wxVERTICAL );
bSizer2->Add( sbSizer6, 1, wxALL|wxEXPAND, 5 );
m_panel1->SetSizer( bSizer2 );
m_panel1->Layout();
bSizer2->Fit( m_panel1 );
m_notebook1->AddPage( m_panel1, _("Info"), false );
m_panel3 = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxGridSizer* gSizer1;
gSizer1 = new wxGridSizer( 1, 1, 0, 0 );
m_logOutputTextCtrl = new wxTextCtrl( m_panel3, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxBORDER_NONE );
gSizer1->Add( m_logOutputTextCtrl, 0, wxALL|wxEXPAND, 5 );
m_panel3->SetSizer( gSizer1 );
m_panel3->Layout();
gSizer1->Fit( m_panel3 );
m_notebook1->AddPage( m_panel3, _("Logs"), true );
m_panel2 = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer5;
bSizer5 = new wxBoxSizer( wxVERTICAL );
wxStaticBoxSizer* sbSizer3;
sbSizer3 = new wxStaticBoxSizer( new wxStaticBox( m_panel2, wxID_ANY, _("JVM") ), wxVERTICAL );
wxGridBagSizer* gbSizer2;
gbSizer2 = new wxGridBagSizer( 0, 0 );
gbSizer2->SetFlexibleDirection( wxBOTH );
gbSizer2->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_button2 = new wxButton( sbSizer3->GetStaticBox(), wxID_ANY, _("Reset"), wxDefaultPosition, wxDefaultSize, 0 );
gbSizer2->Add( m_button2, wxGBPosition( 0, 3 ), wxGBSpan( 1, 1 ), wxALL, 5 );
gbSizer2->Add( 50, 0, wxGBPosition( 0, 2 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 );
m_javaHomeDirPicker = new wxDirPickerCtrl( sbSizer3->GetStaticBox(), wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_DEFAULT_STYLE|wxDIRP_USE_TEXTCTRL );
gbSizer2->Add( m_javaHomeDirPicker, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 );
m_staticText2 = new wxStaticText( sbSizer3->GetStaticBox(), wxID_ANY, _("Java Home"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText2->Wrap( -1 );
gbSizer2->Add( m_staticText2, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 );
gbSizer2->AddGrowableCol( 1 );
sbSizer3->Add( gbSizer2, 1, wxEXPAND, 5 );
bSizer5->Add( sbSizer3, 1, wxALL|wxEXPAND|wxFIXED_MINSIZE, 5 );
wxStaticBoxSizer* sbSizer41;
sbSizer41 = new wxStaticBoxSizer( new wxStaticBox( m_panel2, wxID_ANY, _("Paths") ), wxVERTICAL );
wxGridBagSizer* gbSizer3;
gbSizer3 = new wxGridBagSizer( 0, 0 );
gbSizer3->SetFlexibleDirection( wxBOTH );
gbSizer3->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText6 = new wxStaticText( sbSizer41->GetStaticBox(), wxID_ANY, _("Mount path"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText6->Wrap( -1 );
gbSizer3->Add( m_staticText6, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_staticText61 = new wxStaticText( sbSizer41->GetStaticBox(), wxID_ANY, _("Data path"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText61->Wrap( -1 );
gbSizer3->Add( m_staticText61, wxGBPosition( 1, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_mountPathDirPicker = new wxDirPickerCtrl( sbSizer41->GetStaticBox(), wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL );
gbSizer3->Add( m_mountPathDirPicker, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 );
m_dataPathDirPicker = new wxDirPickerCtrl( sbSizer41->GetStaticBox(), wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL );
gbSizer3->Add( m_dataPathDirPicker, wxGBPosition( 1, 1 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 );
gbSizer3->AddGrowableCol( 1 );
sbSizer41->Add( gbSizer3, 1, wxEXPAND, 5 );
bSizer5->Add( sbSizer41, 1, wxALL|wxEXPAND, 5 );
m_panel2->SetSizer( bSizer5 );
m_panel2->Layout();
bSizer5->Fit( m_panel2 );
m_notebook1->AddPage( m_panel2, _("Settings"), false );
m_panel4 = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_notebook1->AddPage( m_panel4, _("Advanced Settings"), false );
m_panel5 = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_notebook1->AddPage( m_panel5, _("a page"), false );
bSizer3->Add( m_notebook1, 1, wxEXPAND, 5 );
this->SetSizer( bSizer3 );
this->Layout();
this->Centre( wxBOTH );
// Connect Events
m_notebook1->Connect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler( MainFrame::OnNotebookPageChanged ), NULL, this );
m_notebook1->Connect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, wxNotebookEventHandler( MainFrame::OnNotebookPageChanging ), NULL, this );
m_startStopButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::OnStartStopButtonClick ), NULL, this );
m_javaHomeDirPicker->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainFrame::OnJavaHomeChanged ), NULL, this );
m_mountPathDirPicker->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainFrame::OnMountPathChanged ), NULL, this );
m_dataPathDirPicker->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainFrame::OnDataPathChanged ), NULL, this );
}
MainFrame::~MainFrame()
{
}

View File

@@ -0,0 +1,77 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
#include <wx/statusbr.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/button.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/gbsizer.h>
#include <wx/sizer.h>
#include <wx/statbox.h>
#include <wx/panel.h>
#include <wx/textctrl.h>
#include <wx/filepicker.h>
#include <wx/notebook.h>
#include <wx/frame.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class MainFrame
///////////////////////////////////////////////////////////////////////////////
class MainFrame : public wxFrame
{
private:
protected:
wxStatusBar* m_statusBar1;
wxNotebook* m_notebook1;
wxPanel* m_panel1;
wxStaticText* m_statusText;
wxButton* m_startStopButton;
wxPanel* m_panel3;
wxTextCtrl* m_logOutputTextCtrl;
wxPanel* m_panel2;
wxButton* m_button2;
wxDirPickerCtrl* m_javaHomeDirPicker;
wxStaticText* m_staticText2;
wxStaticText* m_staticText6;
wxStaticText* m_staticText61;
wxDirPickerCtrl* m_mountPathDirPicker;
wxDirPickerCtrl* m_dataPathDirPicker;
wxPanel* m_panel4;
wxPanel* m_panel5;
// Virtual event handlers, override them in your derived class
virtual void OnNotebookPageChanged( wxNotebookEvent& event ) { event.Skip(); }
virtual void OnNotebookPageChanging( wxNotebookEvent& event ) { event.Skip(); }
virtual void OnStartStopButtonClick( wxCommandEvent& event ) { event.Skip(); }
virtual void OnJavaHomeChanged( wxFileDirPickerEvent& event ) { event.Skip(); }
virtual void OnMountPathChanged( wxFileDirPickerEvent& event ) { event.Skip(); }
virtual void OnDataPathChanged( wxFileDirPickerEvent& event ) { event.Skip(); }
public:
MainFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("DHFS"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 600,400 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL, const wxString& name = wxT("DHFS") );
~MainFrame();
};

View File

@@ -0,0 +1,44 @@
//
// Created by Stepan Usatiuk on 11.07.2024.
//
// For compilers that don't support precompilation, include "wx/wx.h"
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
# include "wx/wx.h"
#endif
#include "wx/notebook.h"
#include "LauncherApp.h"
#include "LauncherAppMainFrame.h"
#include "wx/taskbar.h"
#include <wx/fileconf.h>
IMPLEMENT_APP(LauncherApp)
// This is executed upon startup, like 'main()' in non-wxWidgets programs.
bool LauncherApp::OnInit() {
wxFileConfig::Get()->SetAppName("DHFS");
wxFrame* frame = new LauncherAppMainFrame(NULL);
frame->Show(true);
SetTopWindow(frame);
// wxTaskBarIcon* tb = new wxTaskBarIcon();
// auto img = new wxImage(32, 32, false);
// img->Clear(128);
// tb->SetIcon(*(new wxBitmapBundle(*(new wxBitmap(*img)))), "e");
return true;
}
bool LauncherApp::OnExceptionInMainLoop() {
try {
std::rethrow_exception(std::current_exception());
} catch (const std::exception& e) {
wxMessageBox(e.what(), "Error", wxOK | wxICON_ERROR | wxCENTRE, GetTopWindow());
}
return true;
}

View File

@@ -0,0 +1,19 @@
//
// Created by Stepan Usatiuk on 11.07.2024.
//
#ifndef HELLOWORLDAPP_H
#define HELLOWORLDAPP_H
// The HelloWorldApp class. This class shows a window
// containing a statusbar with the text "Hello World"
class LauncherApp : public wxApp {
public:
virtual bool OnInit() override;
virtual bool OnExceptionInMainLoop() override;
};
DECLARE_APP(LauncherApp)
#endif //HELLOWORLDAPP_H

View File

@@ -0,0 +1,115 @@
#include "LauncherAppMainFrame.h"
#include <iostream>
#include <wx/fileconf.h>
#include "Exception.h"
wxDEFINE_EVENT(NEW_LINE_OUTPUT_EVENT, wxCommandEvent);
wxDEFINE_EVENT(SHUTDOWN_EVENT, wxCommandEvent);
LauncherAppMainFrame::LauncherAppMainFrame(wxWindow* parent)
: MainFrame(parent) {
m_javaHomeDirPicker->SetPath(wxFileConfig::Get()->Read(kJavaHomeSettingsKey));
m_mountPathDirPicker->SetPath(wxFileConfig::Get()->Read(kMountPointSettingsKey));
m_dataPathDirPicker->SetPath(wxFileConfig::Get()->Read(kDataDirSettingsKey));
m_webViewSizer = new wxGridSizer(1, 0, 0);
m_panel5->SetSizer(m_webViewSizer);
m_panel5->Layout();
m_webViewSizer->Fit(m_panel5);
Bind(NEW_LINE_OUTPUT_EVENT, &LauncherAppMainFrame::onNewLineOutput, this);
Bind(SHUTDOWN_EVENT, &LauncherAppMainFrame::onShutdown, this);
wxFont font = wxFont(wxSize(16, 16),
wxFontFamily::wxFONTFAMILY_TELETYPE,
wxFontStyle::wxFONTSTYLE_NORMAL,
wxFontWeight::wxFONTWEIGHT_NORMAL);
m_logOutputTextCtrl->SetFont(font);
updateState();
}
void LauncherAppMainFrame::updateState() {
switch (_dhfsInstance.state()) {
case DhfsInstanceState::RUNNING:
m_statusText->SetLabel("Running");
m_startStopButton->SetLabel("Stop");
m_statusBar1->SetStatusText("Running", 0);
break;
case DhfsInstanceState::STOPPED: {
m_statusText->SetLabel("Stopped");
m_startStopButton->SetLabel("Start");
m_statusBar1->SetStatusText("Stopped", 0);
break;
}
default:
throw Exception("Unhandled switch case");
}
}
void LauncherAppMainFrame::OnStartStopButtonClick(wxCommandEvent& event) {
switch (_dhfsInstance.state()) {
case DhfsInstanceState::RUNNING:
_dhfsInstance.stop();
break;
case DhfsInstanceState::STOPPED: {
DhfsStartOptions options;
options.java_home = wxFileConfig::Get()->Read(kJavaHomeSettingsKey);
options.xmx = "512m";
options.mount_path = wxFileConfig::Get()->Read(kMountPointSettingsKey);
options.data_path = wxFileConfig::Get()->Read(kDataDirSettingsKey);
std::string bundlePath = wxGetenv("DHFS_BUNDLE_PATH");
options.jar_path = bundlePath + "/app/Server/quarkus-run.jar";
options.webui_path = bundlePath + "/app/Webui";
_dhfsInstance.start(options);
break;
}
default:
throw Exception("Unhandled switch case");
}
updateState();
}
void LauncherAppMainFrame::OnJavaHomeChanged(wxFileDirPickerEvent& event) {
wxFileConfig::Get()->Write(kJavaHomeSettingsKey, event.GetPath());
}
void LauncherAppMainFrame::OnMountPathChanged(wxFileDirPickerEvent& event) {
wxFileConfig::Get()->Write(kMountPointSettingsKey, event.GetPath());
}
void LauncherAppMainFrame::OnDataPathChanged(wxFileDirPickerEvent& event) {
wxFileConfig::Get()->Write(kDataDirSettingsKey, event.GetPath());
}
void LauncherAppMainFrame::onNewLineOutput(wxCommandEvent& event) {
m_logOutputTextCtrl->AppendText(event.GetString());
}
void LauncherAppMainFrame::OnNotebookPageChanged(wxBookCtrlEvent& event) {
}
void LauncherAppMainFrame::OnNotebookPageChanging(wxBookCtrlEvent& event) {
if (event.GetSelection() == 4) prepareWebview();
else unloadWebview();
}
void LauncherAppMainFrame::onShutdown(wxCommandEvent& event) {
updateState();
}
void LauncherAppMainFrame::unloadWebview() {
if (m_webView != nullptr) {
m_webViewSizer->Detach(m_webView);
m_webView->Destroy();
m_webView = nullptr;
}
}
void LauncherAppMainFrame::prepareWebview() {
m_webView = wxWebView::New(m_panel5, wxID_ANY);
m_webViewSizer->Add(m_webView, 0, wxALL | wxEXPAND);
m_webView->LoadURL("http://localhost:8080");
m_panel5->Layout();
}

View File

@@ -0,0 +1,62 @@
#ifndef __LauncherAppMainFrame__
#define __LauncherAppMainFrame__
/**
@file
Subclass of MainFrame, which is generated by wxFormBuilder.
*/
#include "GLauncherApp.h"
//// end generated include
#include <wx/webview.h>
#include "DhfsGuiInstance.hpp"
static constexpr auto kJavaHomeSettingsKey = "DHFS/JavaHome";
static constexpr auto kMountPointSettingsKey = "DHFS/MountDir";
static constexpr auto kDataDirSettingsKey = "DHFS/DataDir";
wxDECLARE_EVENT(NEW_LINE_OUTPUT_EVENT, wxCommandEvent);
wxDECLARE_EVENT(SHUTDOWN_EVENT, wxCommandEvent);
/** Implementing MainFrame */
class LauncherAppMainFrame : public MainFrame {
protected:
// Handlers for MainFrame events.
void OnStartStopButtonClick(wxCommandEvent& event) override;
void OnJavaHomeChanged(wxFileDirPickerEvent& event) override;
void OnMountPathChanged(wxFileDirPickerEvent& event) override;
void OnDataPathChanged(wxFileDirPickerEvent& event) override;
void OnNotebookPageChanged(wxNotebookEvent& event) override;
void OnNotebookPageChanging(wxNotebookEvent& event) override;
void onNewLineOutput(wxCommandEvent& event);
void onShutdown(wxCommandEvent& event);
void updateState();
void unloadWebview();
void prepareWebview();
public:
/** Constructor */
LauncherAppMainFrame(wxWindow* parent);
//// end generated class members
private:
wxWebView* m_webView = nullptr;
wxGridSizer* m_webViewSizer;
DhfsGuiInstance _dhfsInstance{*this};
};
#endif // __LauncherAppMainFrame__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
add_library(utils
src/Exception.cpp
include_public/Exception.h
)
target_include_directories(utils PRIVATE include)
target_include_directories(utils PUBLIC include_public)

View File

@@ -0,0 +1,30 @@
//
// Created by Stepan Usatiuk on 01.05.2023.
//
#ifndef SEMBACKUP_EXCEPTION_H
#define SEMBACKUP_EXCEPTION_H
#include <cstring>
#include <stdexcept>
#include <string>
#include <vector>
/// Custom exception class that uses execinfo to append a stacktrace to the exception message
class Exception : public std::runtime_error {
public:
Exception(const std::string& text);
Exception(const char* text);
private:
/// Static function to get the current stacktrace
static std::string getStacktrace();
};
class ErrnoException : public Exception {
public:
ErrnoException(const std::string& text) : Exception(text + " " + std::strerror(errno)) {}
ErrnoException(const char* text) : Exception(std::string(text) + " " + std::strerror(errno)) {}
};
#endif // SEMBACKUP_EXCEPTION_H

View File

@@ -0,0 +1,35 @@
//
// Created by Stepan Usatiuk on 01.05.2023.
//
#include "Exception.h"
#include <execinfo.h>
#include <sstream>
Exception::Exception(const std::string& text) : runtime_error(text + "\n" + getStacktrace()) {
}
Exception::Exception(const char* text) : runtime_error(std::string(text) + "\n" + getStacktrace()) {
}
// Based on: https://www.gnu.org/software/libc/manual/html_node/Backtraces.html
std::string Exception::getStacktrace() {
std::vector<void*> functions(50);
char** strings;
int n;
n = backtrace(functions.data(), 50);
strings = backtrace_symbols(functions.data(), n);
std::stringstream out;
if (strings != nullptr) {
out << "Stacktrace:" << std::endl;
for (int i = 0; i < n; i++)
out << strings[i] << std::endl;
}
free(strings);
return out.str();
}