Files
i2pd/daemon/HaikuDaemon.cpp
T
2026-06-17 20:04:08 +03:00

302 lines
7.5 KiB
C++

/*
* Copyright (c) 2025, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#if defined(__HAIKU__)
#include <memory>
#include <string>
#include <MenuItem.h>
#include <MenuBar.h>
#include <StringView.h>
#include <Font.h>
#include <MessageRunner.h>
#include <Window.h>
#include <Application.h>
#include <Alert.h>
#include<sstream>
//#include<Roster.h>
#include "version.h"
#include "Log.h"
#include "Config.h"
#include "RouterContext.h"
#include "Tunnel.h"
#include "Transports.h"
#include "Daemon.h"
#include "ClientContext.h"
enum
{
M_GRACEFUL_SHUTDOWN = 1,
M_RUN_PEER_TEST,
M_DUMMY_COMMAND,
C_GRACEFUL_SHUTDOWN_UPDATE,
C_MAIN_VIEW_UPDATE,
M_SHOW_TUNNEL,
C_OPENHTTP
};
constexpr bigtime_t GRACEFUL_SHUTDOWN_UPDATE_INTERVAL = 1000*1100; // in microseconds, ~ 1 sec
constexpr int GRACEFUL_SHUTDOWN_UPDATE_COUNT = 600; // 10 minutes
constexpr bigtime_t MAIN_VIEW_UPDATE_INTERVAL = 5000*1000; // in miscroseconds, 5 secs
class MainWindow: public BWindow
{
public:
MainWindow ();
private:
void MessageReceived (BMessage * msg) override;
bool QuitRequested () override;
void GetInfoAboutTunnel(BMessage * msg);
void UpdateMainView ();
void OpenHTTPInterface(void);
template <class T> void DrawTunnel(T tun);
private:
BMessenger m_Messenger;
BStringView * m_MainView;
std::unique_ptr<BMessageRunner> m_MainViewUpdateTimer, m_GracefulShutdownTimer;
bool m_IsGracefulShutdownComplete = false;
};
class I2PApp: public BApplication
{
public:
I2PApp ();
void CreateMainWindow ();
};
MainWindow::MainWindow ():
BWindow (BRect(100, 100, 500, 400), "i2pd " VERSION, B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE),
m_Messenger (nullptr, this)
{
auto r = Bounds (); r.bottom = 20;
auto menuBar = new BMenuBar (r, "menubar");
AddChild (menuBar);
auto runMenu = new BMenu ("Run");
runMenu->AddItem (new BMenuItem ("Open web interface", new BMessage(C_OPENHTTP)));
runMenu->AddItem (new BMenuItem ("Graceful shutdown", new BMessage (M_GRACEFUL_SHUTDOWN), 'G'));
runMenu->AddItem (new BMenuItem ("Quit", new BMessage (B_QUIT_REQUESTED), 'Q'));
menuBar->AddItem (runMenu);
auto commandsMenu = new BMenu ("Commands");
commandsMenu->AddItem (new BMenuItem ("Run peer test", new BMessage (M_RUN_PEER_TEST), 'P'));
menuBar->AddItem (commandsMenu);
auto tunnelsMenu = new BMenu ("Tunnels");
for (auto& it: i2p::client::context.GetClientTunnels ())
{
auto msg = new BMessage{M_SHOW_TUNNEL};
msg->AddString("tunnel_name", BString(it.second->GetName()));
msg->AddBool("is_client_tunnel", true);
tunnelsMenu->AddItem (new BMenuItem (it.second->GetName (), msg));
}
for (auto& it: i2p::client::context.GetServerTunnels ())
{
auto msg = new BMessage{M_SHOW_TUNNEL};
msg->AddString("tunnel_name", BString(it.second->GetName()));
msg->AddBool("is_client_tunnel", false);
tunnelsMenu->AddItem (new BMenuItem (it.second->GetName (), msg));
}
menuBar->AddItem (tunnelsMenu);
m_MainView = new BStringView (BRect (20, 21, 300, 250), nullptr, "Starting...", B_FOLLOW_ALL, B_WILL_DRAW);
m_MainView->SetViewColor (255, 255, 255);
m_MainView->SetHighColor (0xD4, 0x3B, 0x69);
BFont font = *be_plain_font;
font.SetSize (12);
m_MainView->SetFont (&font);
AddChild (m_MainView);
m_MainViewUpdateTimer = std::make_unique<BMessageRunner>(m_Messenger,
BMessage (C_MAIN_VIEW_UPDATE), MAIN_VIEW_UPDATE_INTERVAL);
}
void MainWindow::UpdateMainView ()
{
std::stringstream s;
i2p::util::PrintMainWindowText (s);
m_MainView->SetText (s.str ().c_str ());
}
template <class T>
void MainWindow :: DrawTunnel(T tun) // idk about type, so todo: change to normal type
{
m_MainView->SetText( i2p::client::context.GetAddressBook().ToAddress(tun).c_str() );
}
void MainWindow :: GetInfoAboutTunnel(BMessage * msg)
{
if(!msg) return;
bool isClient = false;
BString name{};
msg->FindString("tunnel_name", &name);
msg->FindBool("is_client_tunnel", &isClient);
if (isClient)
{
for(auto it :i2p::client::context.GetClientTunnels () )
{
if( BString(it.second->GetName()) == name )
{
auto & ident = it.second->GetLocalDestination()->GetIdentHash();
return DrawTunnel(ident);
//TODO:
}
}
}else {
for(auto it: i2p::client::context.GetServerTunnels())
{
if( BString(it.second->GetName()) == name)
{
auto & ident = it.second->GetLocalDestination()->GetIdentHash();
return DrawTunnel(ident);
//TODO:
}
}
}// if not client tunnel
}
void MainWindow :: OpenHTTPInterface()
{
bool enabled; i2p::config::GetOption("http.enabled", enabled);
uint16_t port; i2p::config::GetOption("http.port", port);
std::string address; i2p::config::GetOption("http.address", address);
if(!enabled)
{
return m_MainView->SetText("Not enabled http server");
}
// int pid;
std::ostringstream com;
com << "WebPositive http://" << address << ":" << port;
//char * argv[] = {(char*)url.str().c_str() , NULL, NULL};
//BRoster{}.Launch( "application/x-vnd.Haiku-WebPositive", 2, argv);
std::string url_s{url.str()};
std::thread ([url_s]() {
system(url_s.c_str());
}).detach();
}
void MainWindow::MessageReceived (BMessage * msg)
{
if (!msg) return;
switch (msg->what)
{
case C_MAIN_VIEW_UPDATE:
UpdateMainView ();
break;
case C_OPENHTTP:
OpenHTTPInterface();
break;
case M_SHOW_TUNNEL:
GetInfoAboutTunnel(msg);
break;
case M_GRACEFUL_SHUTDOWN:
if (!m_GracefulShutdownTimer)
{
i2p::context.SetAcceptsTunnels (false);
Daemon.gracefulShutdownInterval = GRACEFUL_SHUTDOWN_UPDATE_COUNT;
m_MainViewUpdateTimer = nullptr;
m_GracefulShutdownTimer = std::make_unique<BMessageRunner>(m_Messenger,
BMessage (C_GRACEFUL_SHUTDOWN_UPDATE), GRACEFUL_SHUTDOWN_UPDATE_INTERVAL);
}
break;
case C_GRACEFUL_SHUTDOWN_UPDATE:
if (Daemon.gracefulShutdownInterval > 0)
{
UpdateMainView ();
Daemon.gracefulShutdownInterval--;
}
if (!Daemon.gracefulShutdownInterval || i2p::tunnel::tunnels.CountTransitTunnels () <= 0)
{
m_GracefulShutdownTimer = nullptr;
Daemon.gracefulShutdownInterval = 0;
m_IsGracefulShutdownComplete = true;
m_Messenger.SendMessage (B_QUIT_REQUESTED);
}
break;
case M_RUN_PEER_TEST:
i2p::transport::transports.PeerTest ();
break;
default:
BWindow::MessageReceived (msg);
}
}
bool MainWindow::QuitRequested ()
{
bool isQuit = true;
if (!m_IsGracefulShutdownComplete)
{
auto alert = new BAlert (nullptr, "This will stop i2pd. Are you sure?", "Cancel", "Yes", "No",
B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT);
alert->SetShortcut (0, B_ESCAPE);
isQuit = alert->Go () == 1; // Yes
}
if (isQuit)
{
m_MainViewUpdateTimer = nullptr;
m_GracefulShutdownTimer = nullptr;
}
return isQuit;
}
I2PApp::I2PApp (): BApplication("application/x-vnd.purplei2p-i2pd")
{
}
void I2PApp::CreateMainWindow ()
{
auto mainWindow = new MainWindow ();
mainWindow->Show ();
}
namespace i2p
{
namespace util
{
bool DaemonHaiku::start ()
{
I2PApp * app = nullptr;
if (!isDaemon)
{
app = new I2PApp(); // set be_app
i2p::log::SetThrowFunction ([](const std::string& s)
{
auto alert = new BAlert (nullptr, s.c_str (), "Quit", nullptr, nullptr,
B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_STOP_ALERT);
alert->Go ();
});
}
bool ret = false;
if (app)
{
ret = Daemon_Singleton::start ();
if (ret)
app->CreateMainWindow ();
}
else
ret = DaemonUnix::start ();
return ret;
}
void DaemonHaiku::run ()
{
if (be_app)
{
be_app->Run ();
delete be_app;
}
else
DaemonUnix::run ();
}
}
}
#endif