mirror of
https://github.com/open-goal/jak-project
synced 2026-06-08 12:27:57 -04:00
nrepl: default to a single port, nothing breaks if the port is already bound to
This commit is contained in:
@@ -35,7 +35,7 @@ void XSocketServer::shutdown_server() {
|
||||
close_server_socket();
|
||||
}
|
||||
|
||||
bool XSocketServer::init_server() {
|
||||
bool XSocketServer::init_server(bool failure_may_occur) {
|
||||
listening_socket = open_socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (listening_socket < 0) {
|
||||
listening_socket = -1;
|
||||
@@ -76,19 +76,27 @@ bool XSocketServer::init_server() {
|
||||
addr.sin_port = htons(tcp_port);
|
||||
|
||||
if (bind(listening_socket, (sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
lg::error("[XSocketServer:{}] failed to bind", tcp_port);
|
||||
if (failure_may_occur) {
|
||||
lg::debug("[XSocketServer:{}] failed to bind", tcp_port);
|
||||
} else {
|
||||
lg::error("[XSocketServer:{}] failed to bind", tcp_port);
|
||||
}
|
||||
close_server_socket();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (listen(listening_socket, 0) < 0) {
|
||||
lg::error("[XSocketServer:{}] failed to listen", tcp_port);
|
||||
if (failure_may_occur) {
|
||||
lg::debug("[XSocketServer:{}] failed to listen", tcp_port);
|
||||
} else {
|
||||
lg::error("[XSocketServer:{}] failed to listen", tcp_port);
|
||||
}
|
||||
close_server_socket();
|
||||
return false;
|
||||
}
|
||||
|
||||
server_initialized = true;
|
||||
lg::info("[XSocketServer:{}] initialized", tcp_port);
|
||||
lg::debug("[XSocketServer:{}] initialized", tcp_port);
|
||||
post_init();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class XSocketServer {
|
||||
XSocketServer(const XSocketServer&) = delete;
|
||||
XSocketServer& operator=(const XSocketServer&) = delete;
|
||||
|
||||
bool init_server();
|
||||
bool init_server(bool failure_may_occur = false);
|
||||
void shutdown_server();
|
||||
void close_server_socket();
|
||||
|
||||
|
||||
+3
-3
@@ -163,7 +163,7 @@ void set_file(const std::string& filename,
|
||||
file_util::find_files_in_dir(fs::path(complete_filename).parent_path(),
|
||||
std::regex(fmt::format("{}\\.(\\d\\.)?log", filename)));
|
||||
for (const auto& file : old_log_files) {
|
||||
lg::info("removing {}", file.string());
|
||||
lg::debug("removing {}", file.string());
|
||||
fs::remove(file);
|
||||
}
|
||||
// remove the oldest log file if there are more than LOG_ROTATE_MAX
|
||||
@@ -172,9 +172,9 @@ void set_file(const std::string& filename,
|
||||
// sort the names and remove them
|
||||
existing_log_files = file_util::sort_filepaths(existing_log_files, true);
|
||||
if (existing_log_files.size() > (LOG_ROTATE_MAX - 1)) {
|
||||
lg::info("removing {} log files", existing_log_files.size() - (LOG_ROTATE_MAX - 1));
|
||||
lg::debug("removing {} log files", existing_log_files.size() - (LOG_ROTATE_MAX - 1));
|
||||
for (int i = 0; i < (int)existing_log_files.size() - (LOG_ROTATE_MAX - 1); i++) {
|
||||
lg::info("removing {}", existing_log_files.at(i).string());
|
||||
lg::debug("removing {}", existing_log_files.at(i).string());
|
||||
fs::remove(existing_log_files.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,15 +7,21 @@
|
||||
namespace REPL {
|
||||
void to_json(json& j, const Config& obj) {
|
||||
j = json{
|
||||
{"nreplPort", obj.nrepl_port},
|
||||
{"gameVersionFolder", obj.game_version_folder},
|
||||
{"numConnectToTargetAttempts", obj.target_connect_attempts},
|
||||
{"asmFileSearchDirs", obj.asm_file_search_dirs},
|
||||
{"keybinds", obj.keybinds},
|
||||
{"perGameHistory", obj.per_game_history},
|
||||
{"permissiveRedefinitions", obj.permissive_redefinitions},
|
||||
};
|
||||
}
|
||||
|
||||
void from_json(const json& j, Config& obj) {
|
||||
// TODO - make a camelCase variant of json_serialize/deserialize macros
|
||||
if (j.contains("nreplPort")) {
|
||||
j.at("nreplPort").get_to(obj.nrepl_port);
|
||||
}
|
||||
if (j.contains("gameVersionFolder")) {
|
||||
j.at("gameVersionFolder").get_to(obj.game_version_folder);
|
||||
}
|
||||
@@ -55,6 +61,9 @@ void from_json(const json& j, Config& obj) {
|
||||
if (j.contains("perGameHistory")) {
|
||||
j.at("perGameHistory").get_to(obj.per_game_history);
|
||||
}
|
||||
if (j.contains("permissiveRedefinitions")) {
|
||||
j.at("permissiveRedefinitions").get_to(obj.permissive_redefinitions);
|
||||
}
|
||||
// if there is game specific configuration, override any values we just set
|
||||
if (j.contains(version_to_game_name(obj.game_version))) {
|
||||
from_json(j.at(version_to_game_name(obj.game_version)), obj);
|
||||
|
||||
@@ -26,11 +26,14 @@ struct KeyBind {
|
||||
void to_json(json& j, const KeyBind& obj);
|
||||
void from_json(const json& j, KeyBind& obj);
|
||||
|
||||
// TODO - per-game config
|
||||
struct Config {
|
||||
GameVersion game_version;
|
||||
Config(GameVersion _game_version) : game_version(_game_version){};
|
||||
|
||||
// this is the default REPL configuration
|
||||
int nrepl_port = 8181;
|
||||
int temp_nrepl_port = -1;
|
||||
std::string game_version_folder;
|
||||
int target_connect_attempts = 30;
|
||||
std::vector<std::string> asm_file_search_dirs = {};
|
||||
@@ -45,6 +48,14 @@ struct Config {
|
||||
{KeyBind::Modifier::CTRL, "B", "Displays the most recently caught backtrace", "(:di)"},
|
||||
{KeyBind::Modifier::CTRL, "N", "Full build of the game", "(mi)"}};
|
||||
bool per_game_history = true;
|
||||
bool permissive_redefinitions = false;
|
||||
|
||||
int get_nrepl_port() {
|
||||
if (temp_nrepl_port != -1) {
|
||||
return temp_nrepl_port;
|
||||
}
|
||||
return nrepl_port;
|
||||
}
|
||||
};
|
||||
void to_json(json& j, const Config& obj);
|
||||
void from_json(const json& j, Config& obj);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "util.h"
|
||||
#include "repl_wrapper.h"
|
||||
|
||||
#include "common/util/FileUtil.h"
|
||||
#include "common/util/json_util.h"
|
||||
@@ -8,36 +8,66 @@
|
||||
#include "fmt/color.h"
|
||||
#include "fmt/core.h"
|
||||
#include "third-party/replxx/include/replxx.hxx"
|
||||
// TODO - expand a list of hints (ie. a hint for defun to show at a glance how to write a function,
|
||||
// or perhaps, show the docstring for the current function being used?)
|
||||
|
||||
namespace REPL {
|
||||
void Wrapper::clear_screen() {
|
||||
repl.clear_screen();
|
||||
}
|
||||
|
||||
void Wrapper::print_welcome_message() {
|
||||
// TODO - dont print on std-out
|
||||
// Welcome message / brief intro for documentation
|
||||
std::string ascii;
|
||||
ascii += " _____ _____ _____ _____ __ \n";
|
||||
ascii += "| |___ ___ ___| __| | _ | | \n";
|
||||
ascii += "| | | . | -_| | | | | | | |__ \n";
|
||||
ascii += "|_____| _|___|_|_|_____|_____|__|__|_____|\n";
|
||||
ascii += " |_| \n";
|
||||
fmt::print(fmt::emphasis::bold | fg(fmt::color::orange), ascii);
|
||||
|
||||
fmt::print("Welcome to OpenGOAL {}.{}!\n", versions::GOAL_VERSION_MAJOR,
|
||||
versions::GOAL_VERSION_MINOR);
|
||||
fmt::print("Run {} or {} for help with common commands and REPL usage.\n",
|
||||
fmt::styled("(repl-help)", fmt::emphasis::bold | fg(fmt::color::cyan)),
|
||||
fmt::styled("(repl-keybinds)", fmt::emphasis::bold | fg(fmt::color::cyan)));
|
||||
fmt::print("Run ");
|
||||
fmt::print(fmt::emphasis::bold | fg(fmt::color::cyan), "(lt)");
|
||||
fmt::print(" to connect to the local target.\n");
|
||||
fmt::print("Run ");
|
||||
fmt::print(fmt::emphasis::bold | fg(fmt::color::cyan), "(mi)");
|
||||
fmt::print(" to rebuild the entire game.\n\n");
|
||||
void Wrapper::print_welcome_message(const std::vector<std::string> loaded_projects) {
|
||||
std::string message;
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " ..:::::..\n");
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .:-----------:.\n");
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-----.");
|
||||
message += fmt::format(fmt::emphasis::bold, " Welcome to OpenGOAL {}.{} [{}]",
|
||||
versions::GOAL_VERSION_MAJOR, versions::GOAL_VERSION_MINOR,
|
||||
fmt::format(fg(fmt::color::gray), "{}", build_revision()));
|
||||
if (!username.empty() && username != "#f" && username != "unknown") {
|
||||
message += fmt::format(fg(fmt::color::light_green), " {}", username);
|
||||
}
|
||||
message += "!\n";
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .---.");
|
||||
if (repl_config.game_version == GameVersion::Jak1) {
|
||||
message += fmt::format(" [{}]: ", fmt::format(fg(fmt::color::orange), "jak1"));
|
||||
} else if (repl_config.game_version == GameVersion::Jak2) {
|
||||
message += fmt::format(" [{}]: ", fmt::format(fg(fmt::color::purple), "jak2"));
|
||||
} else if (repl_config.game_version == GameVersion::Jak3) {
|
||||
message += fmt::format(" [{}]: ", fmt::format(fg(fmt::color::gold), "jak3"));
|
||||
} else {
|
||||
message += fmt::format(" [{}]: ", fmt::format(fg(fmt::color::magenta), "jakx"));
|
||||
}
|
||||
const auto loaded_projects_str = fmt::format("{}", fmt::join(loaded_projects, ","));
|
||||
message += fmt::format(fg(fmt::color::gray), "{}\n", loaded_projects_str);
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " . --- .");
|
||||
message +=
|
||||
fmt::format(" Project Path: {}\n",
|
||||
fmt::format(fg(fmt::color::gray), file_util::get_jak_project_dir().string()));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " - :===: -");
|
||||
message += " nREPL:";
|
||||
if (!nrepl_alive) {
|
||||
message += fmt::format(fg(fmt::color::red), "DISABLED\n");
|
||||
} else {
|
||||
message += fmt::format(fg(fmt::color::light_green), " Listening on {}\n",
|
||||
repl_config.get_nrepl_port());
|
||||
}
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " --. .--: :--. .--");
|
||||
message += " Source File Search Dirs: ";
|
||||
const auto search_dir_string =
|
||||
fmt::format("{}", fmt::join(repl_config.asm_file_search_dirs, ","));
|
||||
message += fmt::format("[{}]\n", fmt::format(fg(fmt::color::gray), search_dir_string));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .=======. =======.");
|
||||
message += fmt::format(" {} or {} for basic help and usage\n",
|
||||
fmt::format(fg(fmt::color::cyan), "(repl-help)"),
|
||||
fmt::format(fg(fmt::color::cyan), "(repl-keybinds)"));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-=====-. .-=====-");
|
||||
message +=
|
||||
fmt::format(" {} to connect to the game\n", fmt::format(fg(fmt::color::cyan), "(lt)"));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-===========-.");
|
||||
message += fmt::format(" {} to recompile the active project.\n",
|
||||
fmt::format(fg(fmt::color::cyan), "(mi)"));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-===-.\n");
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .\n");
|
||||
fmt::print("{}", message);
|
||||
}
|
||||
|
||||
void Wrapper::print_to_repl(const std::string& str) {
|
||||
@@ -242,20 +272,24 @@ StartupFile load_user_startup_file(const std::string& username, const GameVersio
|
||||
return startup_file;
|
||||
}
|
||||
|
||||
REPL::Config load_repl_config(const std::string& username, const GameVersion game_version) {
|
||||
REPL::Config load_repl_config(const std::string& username,
|
||||
const GameVersion game_version,
|
||||
const int nrepl_port) {
|
||||
auto repl_config_path =
|
||||
file_util::get_jak_project_dir() / "goal_src" / "user" / username / "repl-config.json";
|
||||
REPL::Config loaded_config(game_version);
|
||||
if (file_util::file_exists(repl_config_path.string())) {
|
||||
try {
|
||||
REPL::Config config(game_version);
|
||||
auto repl_config_data =
|
||||
parse_commented_json(file_util::read_text_file(repl_config_path), "repl-config.json");
|
||||
from_json(repl_config_data, config);
|
||||
return config;
|
||||
from_json(repl_config_data, loaded_config);
|
||||
loaded_config.temp_nrepl_port = nrepl_port;
|
||||
return loaded_config;
|
||||
} catch (std::exception& e) {
|
||||
REPL::Config config(game_version);
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
return REPL::Config(game_version);
|
||||
loaded_config.temp_nrepl_port = nrepl_port;
|
||||
return loaded_config;
|
||||
}
|
||||
} // namespace REPL
|
||||
@@ -17,18 +17,20 @@ struct StartupFile {
|
||||
};
|
||||
|
||||
class Wrapper {
|
||||
replxx::Replxx repl;
|
||||
|
||||
public:
|
||||
std::string username;
|
||||
Config repl_config;
|
||||
StartupFile startup_file;
|
||||
bool nrepl_alive = false;
|
||||
std::vector<std::string> examples{};
|
||||
std::vector<std::pair<std::string, replxx::Replxx::Color>> regex_colors{};
|
||||
|
||||
Wrapper(GameVersion version) : repl_config(version) {}
|
||||
Wrapper(const std::string& _username, const Config& config, const StartupFile& startup)
|
||||
: username(_username), repl_config(config), startup_file(startup) {}
|
||||
Wrapper(const std::string& _username,
|
||||
const Config& config,
|
||||
const StartupFile& startup,
|
||||
bool nrepl_alive)
|
||||
: username(_username), repl_config(config), startup_file(startup), nrepl_alive(nrepl_alive) {}
|
||||
replxx::Replxx& get_repl() { return repl; }
|
||||
void init_settings();
|
||||
void reload_startup_file();
|
||||
@@ -36,7 +38,7 @@ class Wrapper {
|
||||
// Functionality / Commands
|
||||
void clear_screen();
|
||||
void print_to_repl(const std::string& str);
|
||||
void print_welcome_message();
|
||||
void print_welcome_message(const std::vector<std::string> loaded_projects);
|
||||
void set_history_max_size(size_t len);
|
||||
const char* readline(const std::string& prompt);
|
||||
void add_to_history(const std::string& line);
|
||||
@@ -47,11 +49,14 @@ class Wrapper {
|
||||
std::pair<std::string, bool> get_current_repl_token(std::string const& context);
|
||||
|
||||
private:
|
||||
replxx::Replxx repl;
|
||||
replxx::Replxx::key_press_handler_t commit_text_action(std::string text_to_commit);
|
||||
std::vector<REPL::KeyBind> keybindings = {};
|
||||
};
|
||||
|
||||
std::string find_repl_username();
|
||||
StartupFile load_user_startup_file(const std::string& username, const GameVersion game_version);
|
||||
REPL::Config load_repl_config(const std::string& username, const GameVersion game_version);
|
||||
REPL::Config load_repl_config(const std::string& username,
|
||||
const GameVersion game_version,
|
||||
const int nrepl_port);
|
||||
} // namespace REPL
|
||||
@@ -65,7 +65,7 @@ Compiler::Compiler(GameVersion version,
|
||||
if (m_repl) {
|
||||
m_repl->load_history();
|
||||
// init repl
|
||||
m_repl->print_welcome_message();
|
||||
m_repl->print_welcome_message(m_make.get_loaded_projects());
|
||||
auto& examples = m_repl->examples;
|
||||
auto& regex_colors = m_repl->regex_colors;
|
||||
m_repl->init_settings();
|
||||
|
||||
Reference in New Issue
Block a user