mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-16 05:33:07 +02:00
Move all plugin group handling boilerplate
This commit is contained in:
+21
-100
@@ -16,12 +16,7 @@
|
||||
|
||||
#include "boost-fix.h"
|
||||
|
||||
#include <boost/asio/read_until.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <thread>
|
||||
|
||||
// Generated inside of build directory
|
||||
#include <src/common/config/config.h>
|
||||
@@ -30,27 +25,6 @@
|
||||
#include "bridges/group.h"
|
||||
#include "bridges/vst2.h"
|
||||
|
||||
// FIXME: `std::filesystem` is broken in wineg++, at least under Wine 5.8. Any
|
||||
// path operation will thrown an encoding related error.
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
// TODO: Move most plumbing to another file
|
||||
|
||||
/**
|
||||
* Create a logger prefix containing the group name based on the socket path.
|
||||
*/
|
||||
std::string create_logger_prefix(const fs::path& socket_path);
|
||||
|
||||
/**
|
||||
* Continuously Read from a stream and write the lines to a logger instance.
|
||||
*
|
||||
* TODO: Merge this with the other similar function in `PluginBridge`
|
||||
*/
|
||||
void log_lines(Logger& logger,
|
||||
boost::asio::posix::stream_descriptor& pipe,
|
||||
boost::asio::streambuf& buffer,
|
||||
std::string prefix);
|
||||
|
||||
/**
|
||||
* This works very similar to the host application defined in
|
||||
* `individual-host.cpp`, but instead of just loading a single plugin this will
|
||||
@@ -82,84 +56,31 @@ int __cdecl main(int argc, char* argv[]) {
|
||||
|
||||
const std::string group_socket_endpoint_path(argv[1]);
|
||||
|
||||
// TODO: Before doing anything, try listening on the socket and fail
|
||||
// silently (or log a message?) if another application is already
|
||||
// listening on the socket. This way we don't need any complicated
|
||||
// inter-process synchronization to ensure that there is a single
|
||||
// active group host listening for this group.
|
||||
|
||||
// Has to be initialized before redirecting the STDIO streams
|
||||
Logger logger = Logger::create_from_environment(
|
||||
create_logger_prefix(group_socket_endpoint_path));
|
||||
|
||||
// Redirect this process's STDOUT and STDERR streams to a pipe so we can
|
||||
// process the output and redirect it to a logger. Needed to capture Wine
|
||||
// debug output, since this process will likely outlive the yabridge
|
||||
// instance that originally spawned it.
|
||||
boost::asio::io_context io_context;
|
||||
boost::asio::streambuf stdout_buffer;
|
||||
boost::asio::streambuf stderr_buffer;
|
||||
StdIoCapture stdout_redirect(io_context, STDOUT_FILENO);
|
||||
StdIoCapture stderr_redirect(io_context, STDERR_FILENO);
|
||||
log_lines(logger, stdout_redirect.pipe, stdout_buffer, "[STDOUT] ");
|
||||
log_lines(logger, stderr_redirect.pipe, stderr_buffer, "[STDERR] ");
|
||||
|
||||
std::thread io_handler([&]() { io_context.run(); });
|
||||
|
||||
logger.log("Initializing yabridge group host version " +
|
||||
std::string(yabridge_git_version)
|
||||
// TODO: Catch exception during initialization when another process is
|
||||
// already listening on the socket. Make sure to print a more useful
|
||||
// message instead.
|
||||
try {
|
||||
std::cerr << "Initializing yabridge group host version "
|
||||
<< yabridge_git_version
|
||||
#ifdef __i386__
|
||||
+ " (32-bit compatibility mode)"
|
||||
<< " (32-bit compatibility mode)"
|
||||
#endif
|
||||
);
|
||||
<< std::endl;
|
||||
|
||||
// TODO: Remove debug prints
|
||||
printf("This should be caught now!\n");
|
||||
std::cerr << "This too!" << std::endl;
|
||||
GroupBridge bridge(group_socket_endpoint_path);
|
||||
|
||||
// TODO: After initializing, listen for connections and spawn plugins
|
||||
// the exact same way as what happens in `individual-host.cpp`
|
||||
// TODO: Allow this process to exit when the last plugin exits. Make sure
|
||||
// that that doesn't cause any race conditions.
|
||||
// Blocks the main thread until all plugins have exited
|
||||
bridge.handle_incoming_connections();
|
||||
} catch (const std::runtime_error& error) {
|
||||
// Even though the process will likely outlive the yabridge instance
|
||||
// that spawns it, we can still print any initialization messages and
|
||||
// errors to STDERR since at this point there will still be a yabridge
|
||||
// instance capturing this process's output.
|
||||
// TODO: Check if this is printed on the right stream
|
||||
std::cerr << "Error while initializing the group host process:"
|
||||
<< std::endl;
|
||||
std::cerr << error.what() << std::endl;
|
||||
|
||||
// TODO: This usleep() is just to ensure that the second print to stderr
|
||||
// also gets processed before stopping the IO context since we're
|
||||
// immediately stopping it after starting. This would not needed in
|
||||
// normal use.
|
||||
usleep(1000);
|
||||
io_context.stop();
|
||||
io_handler.join();
|
||||
}
|
||||
|
||||
void log_lines(Logger& logger,
|
||||
boost::asio::posix::stream_descriptor& pipe,
|
||||
boost::asio::streambuf& buffer,
|
||||
std::string prefix) {
|
||||
boost::asio::async_read_until(pipe, buffer, '\n',
|
||||
[&, prefix](const auto&, size_t) {
|
||||
std::string line;
|
||||
std::getline(std::istream(&buffer), line);
|
||||
logger.log(prefix + line);
|
||||
|
||||
log_lines(logger, pipe, buffer, prefix);
|
||||
});
|
||||
}
|
||||
|
||||
std::string create_logger_prefix(const fs::path& socket_path) {
|
||||
// The group socket filename will be in the format
|
||||
// '/tmp/yabridge-group-<group_name>-<wine_prefix_id>-<architecture>.sock',
|
||||
// where Wine prefix ID is just Wine prefix ran through `std::hash` to
|
||||
// prevent collisions without needing complicated filenames. We want to
|
||||
// extract the group name.
|
||||
std::string socket_name =
|
||||
socket_path.filename().replace_extension().string();
|
||||
|
||||
std::smatch group_match;
|
||||
std::regex group_regexp("^yabridge-group-(.*)-[^-]+-[^-]+$",
|
||||
std::regex::ECMAScript);
|
||||
if (std::regex_match(socket_name, group_match, group_regexp)) {
|
||||
socket_name = group_match[1].str();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return "[" + socket_name + "] ";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user