mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
Prepare ntcore for merge into allwpilib.
This commit is contained in:
153
ntcore/src/main/native/cpp/DsClient.cpp
Normal file
153
ntcore/src/main/native/cpp/DsClient.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015-2018. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "DsClient.h"
|
||||
|
||||
#include <llvm/SmallString.h>
|
||||
#include <llvm/raw_ostream.h>
|
||||
#include <support/raw_socket_istream.h>
|
||||
|
||||
#include "Dispatcher.h"
|
||||
#include "Log.h"
|
||||
#include "tcpsockets/TCPConnector.h"
|
||||
|
||||
using namespace nt;
|
||||
|
||||
class DsClient::Thread : public wpi::SafeThread {
|
||||
public:
|
||||
Thread(Dispatcher& dispatcher, wpi::Logger& logger, unsigned int port)
|
||||
: m_dispatcher(dispatcher), m_logger(logger), m_port(port) {}
|
||||
|
||||
void Main();
|
||||
|
||||
Dispatcher& m_dispatcher;
|
||||
wpi::Logger& m_logger;
|
||||
unsigned int m_port;
|
||||
std::unique_ptr<wpi::NetworkStream> m_stream;
|
||||
};
|
||||
|
||||
DsClient::DsClient(Dispatcher& dispatcher, wpi::Logger& logger)
|
||||
: m_dispatcher(dispatcher), m_logger(logger) {}
|
||||
|
||||
void DsClient::Start(unsigned int port) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr)
|
||||
m_owner.Start(new Thread(m_dispatcher, m_logger, port));
|
||||
else
|
||||
thr->m_port = port;
|
||||
}
|
||||
|
||||
void DsClient::Stop() {
|
||||
{
|
||||
// Close the stream so the read (if any) terminates.
|
||||
auto thr = m_owner.GetThread();
|
||||
if (thr) {
|
||||
thr->m_active = false;
|
||||
if (thr->m_stream) thr->m_stream->close();
|
||||
}
|
||||
}
|
||||
m_owner.Stop();
|
||||
}
|
||||
|
||||
void DsClient::Thread::Main() {
|
||||
unsigned int oldip = 0;
|
||||
wpi::Logger nolog; // to silence log messages from TCPConnector
|
||||
|
||||
while (m_active) {
|
||||
// wait for periodic reconnect or termination
|
||||
auto timeout_time =
|
||||
std::chrono::steady_clock::now() + std::chrono::milliseconds(500);
|
||||
unsigned int port;
|
||||
{
|
||||
std::unique_lock<wpi::mutex> lock(m_mutex);
|
||||
m_cond.wait_until(lock, timeout_time, [&] { return !m_active; });
|
||||
port = m_port;
|
||||
}
|
||||
if (!m_active) goto done;
|
||||
|
||||
// Try to connect to DS on the local machine
|
||||
m_stream = wpi::TCPConnector::connect("127.0.0.1", 1742, nolog, 1);
|
||||
if (!m_active) goto done;
|
||||
if (!m_stream) continue;
|
||||
|
||||
DEBUG3("connected to DS");
|
||||
wpi::raw_socket_istream is(*m_stream);
|
||||
|
||||
while (m_active && !is.has_error()) {
|
||||
// Read JSON "{...}". This is very limited, does not handle quoted "}" or
|
||||
// nested {}, but is sufficient for this purpose.
|
||||
llvm::SmallString<128> json;
|
||||
char ch;
|
||||
|
||||
// Throw away characters until {
|
||||
do {
|
||||
is.read(ch);
|
||||
if (is.has_error()) break;
|
||||
if (!m_active) goto done;
|
||||
} while (ch != '{');
|
||||
json += '{';
|
||||
|
||||
if (is.has_error()) {
|
||||
m_stream = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
// Read characters until }
|
||||
do {
|
||||
is.read(ch);
|
||||
if (is.has_error()) break;
|
||||
if (!m_active) goto done;
|
||||
json += ch;
|
||||
} while (ch != '}');
|
||||
|
||||
if (is.has_error()) {
|
||||
m_stream = nullptr;
|
||||
break;
|
||||
}
|
||||
DEBUG3("json=" << json);
|
||||
|
||||
// Look for "robotIP":12345, and get 12345 portion
|
||||
size_t pos = json.find("\"robotIP\"");
|
||||
if (pos == llvm::StringRef::npos) continue; // could not find?
|
||||
pos += 9;
|
||||
pos = json.find(':', pos);
|
||||
if (pos == llvm::StringRef::npos) continue; // could not find?
|
||||
size_t endpos = json.find_first_not_of("0123456789", pos + 1);
|
||||
DEBUG3("found robotIP=" << json.slice(pos + 1, endpos));
|
||||
|
||||
// Parse into number
|
||||
unsigned int ip = 0;
|
||||
if (json.slice(pos + 1, endpos).getAsInteger(10, ip)) continue; // error
|
||||
|
||||
// If zero, clear the server override
|
||||
if (ip == 0) {
|
||||
m_dispatcher.ClearServerOverride();
|
||||
oldip = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If unchanged, don't reconnect
|
||||
if (ip == oldip) continue;
|
||||
oldip = ip;
|
||||
|
||||
// Convert number into dotted quad
|
||||
json.clear();
|
||||
llvm::raw_svector_ostream os{json};
|
||||
os << ((ip >> 24) & 0xff) << "." << ((ip >> 16) & 0xff) << "."
|
||||
<< ((ip >> 8) & 0xff) << "." << (ip & 0xff);
|
||||
INFO("client: DS overriding server IP to " << os.str());
|
||||
m_dispatcher.SetServerOverride(json.c_str(), port);
|
||||
}
|
||||
|
||||
// We disconnected from the DS, clear the server override
|
||||
m_dispatcher.ClearServerOverride();
|
||||
oldip = 0;
|
||||
}
|
||||
|
||||
done:
|
||||
m_dispatcher.ClearServerOverride();
|
||||
}
|
||||
Reference in New Issue
Block a user