UCIEndpoint.cpp 5.0 KB

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