UCIEndpoint.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. * Copyright (c) 2023, Tim Ledbetter <timledbetter@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include "UCIEndpoint.h"
  8. #include <AK/ByteBuffer.h>
  9. #include <AK/Debug.h>
  10. #include <LibCore/EventLoop.h>
  11. namespace Chess::UCI {
  12. void Endpoint::send_command(Command const& command)
  13. {
  14. auto command_string = command.to_string().release_value_but_fixme_should_propagate_errors();
  15. dbgln_if(UCI_DEBUG, "{} Sent UCI Command: {}", class_name(), command_string);
  16. m_out->write_until_depleted(command_string.bytes()).release_value_but_fixme_should_propagate_errors();
  17. }
  18. void Endpoint::event(Core::Event& event)
  19. {
  20. switch (static_cast<Command::Type>(event.type())) {
  21. case Command::Type::UCI:
  22. return handle_uci();
  23. case Command::Type::Debug:
  24. return handle_debug(static_cast<DebugCommand const&>(event));
  25. case Command::Type::IsReady:
  26. return handle_uci();
  27. case Command::Type::SetOption:
  28. return handle_setoption(static_cast<SetOptionCommand const&>(event));
  29. case Command::Type::Position:
  30. return handle_position(static_cast<PositionCommand const&>(event));
  31. case Command::Type::Go:
  32. return handle_go(static_cast<GoCommand const&>(event));
  33. case Command::Type::Stop:
  34. return handle_stop();
  35. case Command::Type::Id:
  36. return handle_id(static_cast<IdCommand const&>(event));
  37. case Command::Type::UCIOk:
  38. return handle_uciok();
  39. case Command::Type::ReadyOk:
  40. return handle_readyok();
  41. case Command::Type::BestMove:
  42. return handle_bestmove(static_cast<BestMoveCommand const&>(event));
  43. case Command::Type::Info:
  44. return handle_info(static_cast<InfoCommand const&>(event));
  45. case Command::Type::Quit:
  46. return handle_quit();
  47. case Command::Type::UCINewGame:
  48. return handle_ucinewgame();
  49. default:
  50. EventReceiver::event(event);
  51. break;
  52. }
  53. }
  54. void Endpoint::custom_event(Core::CustomEvent& custom_event)
  55. {
  56. if (custom_event.custom_type() == EndpointEventType::UnexpectedEof)
  57. handle_unexpected_eof();
  58. }
  59. void Endpoint::set_in_notifier()
  60. {
  61. m_in_notifier = Core::Notifier::construct(m_in_fd.value(), Core::Notifier::Type::Read);
  62. m_in_notifier->on_activation = [this] {
  63. if (!m_in->can_read_line().release_value_but_fixme_should_propagate_errors()) {
  64. Core::EventLoop::current().post_event(*this, make<Core::CustomEvent>(EndpointEventType::UnexpectedEof));
  65. m_in_notifier->set_enabled(false);
  66. return;
  67. }
  68. auto buffer = ByteBuffer::create_zeroed(4096).release_value_but_fixme_should_propagate_errors();
  69. while (m_in->can_read_line().release_value_but_fixme_should_propagate_errors()) {
  70. auto line = m_in->read_line(buffer).release_value_but_fixme_should_propagate_errors().trim_whitespace();
  71. if (line.is_empty())
  72. continue;
  73. auto maybe_command = read_command(line);
  74. if (maybe_command.is_error()) {
  75. dbgln_if(UCI_DEBUG, "{} Error while parsing UCI command: {}, error: {}", class_name(), maybe_command.error(), line);
  76. if (on_command_read_error)
  77. on_command_read_error(move(line), maybe_command.release_error());
  78. continue;
  79. }
  80. Core::EventLoop::current().post_event(*this, maybe_command.release_value());
  81. }
  82. };
  83. }
  84. ErrorOr<NonnullOwnPtr<Command>> Endpoint::read_command(StringView line) const
  85. {
  86. dbgln_if(UCI_DEBUG, "{} Received UCI Command: {}", class_name(), line);
  87. if (line == "uci") {
  88. return UCICommand::from_string(line);
  89. } else if (line.starts_with("debug"sv)) {
  90. return DebugCommand::from_string(line);
  91. } else if (line.starts_with("isready"sv)) {
  92. return IsReadyCommand::from_string(line);
  93. } else if (line.starts_with("setoption"sv)) {
  94. return SetOptionCommand::from_string(line);
  95. } else if (line.starts_with("position"sv)) {
  96. return PositionCommand::from_string(line);
  97. } else if (line.starts_with("go"sv)) {
  98. return GoCommand::from_string(line);
  99. } else if (line.starts_with("stop"sv)) {
  100. return StopCommand::from_string(line);
  101. } else if (line.starts_with("id"sv)) {
  102. return IdCommand::from_string(line);
  103. } else if (line.starts_with("uciok"sv)) {
  104. return UCIOkCommand::from_string(line);
  105. } else if (line.starts_with("readyok"sv)) {
  106. return ReadyOkCommand::from_string(line);
  107. } else if (line.starts_with("bestmove"sv)) {
  108. return BestMoveCommand::from_string(line);
  109. } else if (line.starts_with("info"sv)) {
  110. return InfoCommand::from_string(line);
  111. } else if (line.starts_with("quit"sv)) {
  112. return QuitCommand::from_string(line);
  113. } else if (line.starts_with("ucinewgame"sv)) {
  114. return UCINewGameCommand::from_string(line);
  115. }
  116. return Error::from_string_literal("Unknown command");
  117. }
  118. };