Use std::string_view and fmtlib across all libraries (#3402)

- Twine, StringRef, Format, and NativeFormatting have been removed
- Logging now uses fmtlib style formatting
- Nearly all uses of wpi::outs/errs have been replaced with fmt::print() or
std::puts()/std::fputs() (for unformatted strings).
- A wpi/fmt/raw_ostream.h header has been added to enable
fmt::print() with wpi::raw_ostream
This commit is contained in:
Peter Johnson
2021-06-06 16:13:58 -07:00
committed by GitHub
parent 4f1cecb8e7
commit b2c3b2dd8e
441 changed files with 5061 additions and 9749 deletions

View File

@@ -6,9 +6,12 @@
#include <chrono>
#include <fmt/format.h>
#include <wpi/HttpUtil.h>
#include <wpi/SmallString.h>
#include <wpi/StringExtras.h>
#include <wpi/TCPAcceptor.h>
#include <wpi/fmt/raw_ostream.h>
#include <wpi/raw_socket_istream.h>
#include <wpi/raw_socket_ostream.h>
@@ -72,13 +75,13 @@ static const char* endRootPage = "</div></body></html>";
class MjpegServerImpl::ConnThread : public wpi::SafeThread {
public:
explicit ConnThread(const wpi::Twine& name, wpi::Logger& logger)
: m_name(name.str()), m_logger(logger) {}
explicit ConnThread(std::string_view name, wpi::Logger& logger)
: m_name(name), m_logger(logger) {}
void Main() override;
bool ProcessCommand(wpi::raw_ostream& os, SourceImpl& source,
wpi::StringRef parameters, bool respond);
std::string_view parameters, bool respond);
void SendJSON(wpi::raw_ostream& os, SourceImpl& source, bool header);
void SendHTMLHeadTitle(wpi::raw_ostream& os) const;
void SendHTML(wpi::raw_ostream& os, SourceImpl& source, bool header);
@@ -99,7 +102,7 @@ class MjpegServerImpl::ConnThread : public wpi::SafeThread {
std::string m_name;
wpi::Logger& m_logger;
wpi::StringRef GetName() { return m_name; }
std::string_view GetName() { return m_name; }
std::shared_ptr<SourceImpl> GetSource() {
std::scoped_lock lock(m_mutex);
@@ -130,10 +133,9 @@ class MjpegServerImpl::ConnThread : public wpi::SafeThread {
// Using cached pictures would lead to showing old/outdated pictures.
// Many browsers seem to ignore, or at least not always obey, those headers.
static void SendHeader(wpi::raw_ostream& os, int code,
const wpi::Twine& codeText,
const wpi::Twine& contentType,
const wpi::Twine& extra = wpi::Twine{}) {
os << "HTTP/1.0 " << code << ' ' << codeText << "\r\n";
std::string_view codeText, std::string_view contentType,
std::string_view extra = {}) {
fmt::print(os, "HTTP/1.0 {} {}\r\n", code, codeText);
os << "Connection: close\r\n"
"Server: CameraServer/1.0\r\n"
"Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, "
@@ -142,10 +144,8 @@ static void SendHeader(wpi::raw_ostream& os, int code,
"Expires: Mon, 3 Jan 2000 12:34:56 GMT\r\n";
os << "Content-Type: " << contentType << "\r\n";
os << "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Methods: *\r\n";
wpi::SmallString<128> extraBuf;
wpi::StringRef extraStr = extra.toStringRef(extraBuf);
if (!extraStr.empty()) {
os << extraStr << "\r\n";
if (!extra.empty()) {
os << extra << "\r\n";
}
os << "\r\n"; // header ends with a blank line
}
@@ -154,8 +154,8 @@ static void SendHeader(wpi::raw_ostream& os, int code,
// @param code HTTP error code (e.g. 404)
// @param message Additional message text
static void SendError(wpi::raw_ostream& os, int code,
const wpi::Twine& message) {
wpi::StringRef codeText, extra, baseMessage;
std::string_view message) {
std::string_view codeText, extra, baseMessage;
switch (code) {
case 401:
codeText = "Unauthorized";
@@ -195,66 +195,61 @@ static void SendError(wpi::raw_ostream& os, int code,
// Perform a command specified by HTTP GET parameters.
bool MjpegServerImpl::ConnThread::ProcessCommand(wpi::raw_ostream& os,
SourceImpl& source,
wpi::StringRef parameters,
std::string_view parameters,
bool respond) {
wpi::SmallString<256> responseBuf;
wpi::raw_svector_ostream response{responseBuf};
// command format: param1=value1&param2=value2...
while (!parameters.empty()) {
// split out next param and value
wpi::StringRef rawParam, rawValue;
std::tie(rawParam, parameters) = parameters.split('&');
std::string_view rawParam, rawValue;
std::tie(rawParam, parameters) = wpi::split(parameters, '&');
if (rawParam.empty()) {
continue; // ignore "&&"
}
std::tie(rawParam, rawValue) = rawParam.split('=');
std::tie(rawParam, rawValue) = wpi::split(rawParam, '=');
if (rawParam.empty() || rawValue.empty()) {
continue; // ignore "param="
}
SDEBUG4("HTTP parameter \"" << rawParam << "\" value \"" << rawValue
<< "\"");
SDEBUG4("HTTP parameter \"{}\" value \"{}\"", rawParam, rawValue);
// unescape param
bool error = false;
wpi::SmallString<64> paramBuf;
wpi::StringRef param = wpi::UnescapeURI(rawParam, paramBuf, &error);
std::string_view param = wpi::UnescapeURI(rawParam, paramBuf, &error);
if (error) {
wpi::SmallString<128> error;
wpi::raw_svector_ostream oss{error};
oss << "could not unescape parameter \"" << rawParam << "\"";
SendError(os, 500, error.str());
SDEBUG(error.str());
auto estr = fmt::format("could not unescape parameter \"{}\"", rawParam);
SendError(os, 500, estr);
SDEBUG("{}", estr);
return false;
}
// unescape value
wpi::SmallString<64> valueBuf;
wpi::StringRef value = wpi::UnescapeURI(rawValue, valueBuf, &error);
std::string_view value = wpi::UnescapeURI(rawValue, valueBuf, &error);
if (error) {
wpi::SmallString<128> error;
wpi::raw_svector_ostream oss{error};
oss << "could not unescape value \"" << rawValue << "\"";
SendError(os, 500, error.str());
SDEBUG(error.str());
auto estr = fmt::format("could not unescape value \"{}\"", rawValue);
SendError(os, 500, estr);
SDEBUG("{}", estr);
return false;
}
// Handle resolution, compression, and FPS. These are handled locally
// rather than passed to the source.
if (param == "resolution") {
wpi::StringRef widthStr, heightStr;
std::tie(widthStr, heightStr) = value.split('x');
int width, height;
if (widthStr.getAsInteger(10, width)) {
auto [widthStr, heightStr] = wpi::split(value, 'x');
int width = wpi::parse_integer<int>(widthStr, 10).value_or(-1);
int height = wpi::parse_integer<int>(heightStr, 10).value_or(-1);
if (width < 0) {
response << param << ": \"width is not an integer\"\r\n";
SWARNING("HTTP parameter \"" << param << "\" width \"" << widthStr
<< "\" is not an integer");
SWARNING("HTTP parameter \"{}\" width \"{}\" is not an integer", param,
widthStr);
continue;
}
if (heightStr.getAsInteger(10, height)) {
if (height < 0) {
response << param << ": \"height is not an integer\"\r\n";
SWARNING("HTTP parameter \"" << param << "\" height \"" << heightStr
<< "\" is not an integer");
SWARNING("HTTP parameter \"{}\" height \"{}\" is not an integer", param,
heightStr);
continue;
}
m_width = width;
@@ -264,29 +259,25 @@ bool MjpegServerImpl::ConnThread::ProcessCommand(wpi::raw_ostream& os,
}
if (param == "fps") {
int fps;
if (value.getAsInteger(10, fps)) {
response << param << ": \"invalid integer\"\r\n";
SWARNING("HTTP parameter \"" << param << "\" value \"" << value
<< "\" is not an integer");
continue;
} else {
m_fps = fps;
if (auto v = wpi::parse_integer<int>(value, 10)) {
m_fps = v.value();
response << param << ": \"ok\"\r\n";
} else {
response << param << ": \"invalid integer\"\r\n";
SWARNING("HTTP parameter \"{}\" value \"{}\" is not an integer", param,
value);
}
continue;
}
if (param == "compression") {
int compression;
if (value.getAsInteger(10, compression)) {
response << param << ": \"invalid integer\"\r\n";
SWARNING("HTTP parameter \"" << param << "\" value \"" << value
<< "\" is not an integer");
continue;
} else {
m_compression = compression;
if (auto v = wpi::parse_integer<int>(value, 10)) {
m_compression = v.value();
response << param << ": \"ok\"\r\n";
} else {
response << param << ": \"invalid integer\"\r\n";
SWARNING("HTTP parameter \"{}\" value \"{}\" is not an integer", param,
value);
}
continue;
}
@@ -300,7 +291,7 @@ bool MjpegServerImpl::ConnThread::ProcessCommand(wpi::raw_ostream& os,
auto prop = source.GetPropertyIndex(param);
if (!prop) {
response << param << ": \"ignored\"\r\n";
SWARNING("ignoring HTTP parameter \"" << param << "\"");
SWARNING("ignoring HTTP parameter \"{}\"", param);
continue;
}
@@ -310,21 +301,20 @@ bool MjpegServerImpl::ConnThread::ProcessCommand(wpi::raw_ostream& os,
case CS_PROP_BOOLEAN:
case CS_PROP_INTEGER:
case CS_PROP_ENUM: {
int val = 0;
if (value.getAsInteger(10, val)) {
response << param << ": \"invalid integer\"\r\n";
SWARNING("HTTP parameter \"" << param << "\" value \"" << value
<< "\" is not an integer");
if (auto v = wpi::parse_integer<int>(value, 10)) {
fmt::print(response, "{}: {}\r\n", param, v.value());
SDEBUG4("HTTP parameter \"{}\" value {}", param, value);
source.SetProperty(prop, v.value(), &status);
} else {
response << param << ": " << val << "\r\n";
SDEBUG4("HTTP parameter \"" << param << "\" value " << value);
source.SetProperty(prop, val, &status);
response << param << ": \"invalid integer\"\r\n";
SWARNING("HTTP parameter \"{}\" value \"{}\" is not an integer",
param, value);
}
break;
}
case CS_PROP_STRING: {
response << param << ": \"ok\"\r\n";
SDEBUG4("HTTP parameter \"" << param << "\" value \"" << value << "\"");
SDEBUG4("HTTP parameter \"{}\" value \"{}\"", param, value);
source.SetStringProperty(prop, value, &status);
break;
}
@@ -362,17 +352,17 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
for (auto prop : source.EnumerateProperties(properties_vec, &status)) {
wpi::SmallString<128> name_buf;
auto name = source.GetPropertyName(prop, name_buf, &status);
if (name.startswith("raw_")) {
if (wpi::starts_with(name, "raw_")) {
continue;
}
auto kind = source.GetPropertyKind(prop);
os << "<p />"
<< "<label for=\"" << name << "\">" << name << "</label>\n";
fmt::print(os, "<p /><label for=\"{0}\">{0}</label>\n", name);
switch (kind) {
case CS_PROP_BOOLEAN:
os << "<input id=\"" << name
<< "\" type=\"checkbox\" onclick=\"update('" << name
<< "', this.checked ? 1 : 0)\" ";
fmt::print(os,
"<input id=\"{0}\" type=\"checkbox\" "
"onclick=\"update('{0}', this.checked ? 1 : 0)\" ",
name);
if (source.GetProperty(prop, &status) != 0) {
os << "checked />\n";
} else {
@@ -384,12 +374,13 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
auto min = source.GetPropertyMin(prop, &status);
auto max = source.GetPropertyMax(prop, &status);
auto step = source.GetPropertyStep(prop, &status);
os << "<input type=\"range\" min=\"" << min << "\" max=\"" << max
<< "\" value=\"" << valI << "\" id=\"" << name << "\" step=\""
<< step << "\" oninput=\"updateInt('#" << name << "op', '" << name
<< "', value)\" />\n";
os << "<output for=\"" << name << "\" id=\"" << name << "op\">" << valI
<< "</output>\n";
fmt::print(os,
"<input type=\"range\" min=\"{1}\" max=\"{2}\" "
"value=\"{3}\" id=\"{0}\" step=\"{4}\" "
"oninput=\"updateInt('#{0}op', '{0}', value)\" />\n",
name, min, max, valI, step);
fmt::print(os, "<output for=\"{0}\" id=\"{0}op\">{1}</output>\n", name,
valI);
break;
}
case CS_PROP_ENUM: {
@@ -404,26 +395,30 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
// replace any non-printable characters in name with spaces
wpi::SmallString<128> ch_name;
for (char ch : *choice) {
ch_name.push_back(std::isprint(ch) ? ch : ' ');
ch_name.push_back(wpi::isPrint(ch) ? ch : ' ');
}
os << "<input id=\"" << name << j << "\" type=\"radio\" name=\""
<< name << "\" value=\"" << ch_name << "\" onclick=\"update('"
<< name << "', " << j << ")\"";
fmt::print(os,
"<input id=\"{0}{1}\" type=\"radio\" name=\"{0}\" "
"value=\"{2}\" onclick=\"update('{0}', {1})\"",
name, j, ch_name);
if (j == valE) {
os << " checked";
}
os << " /><label for=\"" << name << j << "\">" << ch_name
<< "</label>\n";
fmt::print(os, " /><label for=\"{}{}\">{}</label>\n", name, j,
ch_name);
}
break;
}
case CS_PROP_STRING: {
wpi::SmallString<128> strval_buf;
os << "<input type=\"text\" id=\"" << name << "box\" name=\"" << name
<< "\" value=\""
<< source.GetStringProperty(prop, strval_buf, &status) << "\" />\n";
os << "<input type=\"button\" value =\"Submit\" onclick=\"update('"
<< name << "', " << name << "box.value)\" />\n";
fmt::print(os,
"<input type=\"text\" id=\"{0}box\" name=\"{0}\" "
"value=\"{1}\" />\n",
name, source.GetStringProperty(prop, strval_buf, &status));
fmt::print(os,
"<input type=\"button\" value =\"Submit\" "
"onclick=\"update('{0}', {0}box.value)\" />\n",
name);
break;
}
default:
@@ -469,10 +464,8 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
os << "unknown";
break;
}
os << "</td><td>" << mode.width;
os << "</td><td>" << mode.height;
os << "</td><td>" << mode.fps;
os << "</td></tr>";
fmt::print(os, "</td><td>{}</td><td>{}</td><td>{}</td></tr>", mode.width,
mode.height, mode.fps);
}
os << "</table>\n";
os << endRootPage << "\r\n";
@@ -500,20 +493,21 @@ void MjpegServerImpl::ConnThread::SendJSON(wpi::raw_ostream& os,
wpi::SmallString<128> name_buf;
auto name = source.GetPropertyName(prop, name_buf, &status);
auto kind = source.GetPropertyKind(prop);
os << "\n\"name\": \"" << name << '"';
os << ",\n\"id\": \"" << prop << '"';
os << ",\n\"type\": \"" << kind << '"';
os << ",\n\"min\": \"" << source.GetPropertyMin(prop, &status) << '"';
os << ",\n\"max\": \"" << source.GetPropertyMax(prop, &status) << '"';
os << ",\n\"step\": \"" << source.GetPropertyStep(prop, &status) << '"';
os << ",\n\"default\": \"" << source.GetPropertyDefault(prop, &status)
<< '"';
fmt::print(os, "\n\"name\": \"{}\"", name);
fmt::print(os, ",\n\"id\": \"{}\"", prop);
fmt::print(os, ",\n\"type\": \"{}\"", kind);
fmt::print(os, ",\n\"min\": \"{}\"", source.GetPropertyMin(prop, &status));
fmt::print(os, ",\n\"max\": \"{}\"", source.GetPropertyMax(prop, &status));
fmt::print(os, ",\n\"step\": \"{}\"",
source.GetPropertyStep(prop, &status));
fmt::print(os, ",\n\"default\": \"{}\"",
source.GetPropertyDefault(prop, &status));
os << ",\n\"value\": \"";
switch (kind) {
case CS_PROP_BOOLEAN:
case CS_PROP_INTEGER:
case CS_PROP_ENUM:
os << source.GetProperty(prop, &status);
fmt::print(os, "{}", source.GetProperty(prop, &status));
break;
case CS_PROP_STRING: {
wpi::SmallString<128> strval_buf;
@@ -543,7 +537,7 @@ void MjpegServerImpl::ConnThread::SendJSON(wpi::raw_ostream& os,
for (char ch : *choice) {
ch_name.push_back(std::isprint(ch) ? ch : ' ');
}
os << '"' << j << "\": \"" << ch_name << '"';
fmt::print(os, "\"{}\": \"{}\"", j, ch_name);
}
os << "}\n";
}
@@ -579,29 +573,26 @@ void MjpegServerImpl::ConnThread::SendJSON(wpi::raw_ostream& os,
os << "unknown";
break;
}
os << "\",\n\"width\": \"" << mode.width << '"';
os << ",\n\"height\": \"" << mode.height << '"';
os << ",\n\"fps\": \"" << mode.fps << '"';
fmt::print(os, "\",\n\"width\": \"{}\"", mode.width);
fmt::print(os, ",\n\"height\": \"{}\"", mode.height);
fmt::print(os, ",\n\"fps\": \"{}\"", mode.fps);
os << '}';
}
os << "\n]\n}\n";
os.flush();
}
MjpegServerImpl::MjpegServerImpl(const wpi::Twine& name, wpi::Logger& logger,
MjpegServerImpl::MjpegServerImpl(std::string_view name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry,
const wpi::Twine& listenAddress, int port,
std::string_view listenAddress, int port,
std::unique_ptr<wpi::NetworkAcceptor> acceptor)
: SinkImpl{name, logger, notifier, telemetry},
m_listenAddress(listenAddress.str()),
m_listenAddress(listenAddress),
m_port(port),
m_acceptor{std::move(acceptor)} {
m_active = true;
wpi::SmallString<128> descBuf;
wpi::raw_svector_ostream desc{descBuf};
desc << "HTTP Server on port " << port;
SetDescription(desc.str());
SetDescription(fmt::format("HTTP Server on port {}", port));
// Create properties
m_widthProp = CreateProperty("width", [] {
@@ -659,7 +650,7 @@ void MjpegServerImpl::Stop() {
// Send HTTP response and a stream of JPG-frames
void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) {
if (m_noStreaming) {
SERROR("Too many simultaneous client streams");
SERROR("{}", "Too many simultaneous client streams");
SendError(os, 503, "Too many simultaneous streams");
return;
}
@@ -672,7 +663,7 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) {
SendHeader(oss, 200, "OK", "multipart/x-mixed-replace;boundary=" BOUNDARY);
os << oss.str();
SDEBUG("Headers send, sending stream now");
SDEBUG("{}", "Headers send, sending stream now");
Frame::Time lastFrameTime = 0;
Frame::Time timePerFrame = 0;
@@ -694,7 +685,7 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
continue;
}
SDEBUG4("waiting for frame");
SDEBUG4("{}", "waiting for frame");
Frame frame = source->GetNextFrame(0.225); // blocks
if (!m_active) {
break;
@@ -757,7 +748,7 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) {
continue;
}
SDEBUG4("sending frame size=" << size << " addDHT=" << addDHT);
SDEBUG4("sending frame size={} addDHT={}", size, addDHT);
// print the individual mimetype and the length
// sending the content-length fixes random stream disruption observed
@@ -766,18 +757,18 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) {
double timestamp = lastFrameTime / 1000000.0;
header.clear();
oss << "\r\n--" BOUNDARY "\r\n"
<< "Content-Type: image/jpeg\r\n"
<< "Content-Length: " << size << "\r\n"
<< "X-Timestamp: " << timestamp << "\r\n"
<< "\r\n";
<< "Content-Type: image/jpeg\r\n";
fmt::print(oss, "Content-Length: {}\r\n", size);
fmt::print(oss, "X-Timestamp: {}\r\n", timestamp);
oss << "\r\n";
os << oss.str();
if (addDHT) {
// Insert DHT data immediately before SOF
os << wpi::StringRef(data, locSOF);
os << std::string_view(data, locSOF);
os << JpegGetDHT();
os << wpi::StringRef(data + locSOF, image->size() - locSOF);
os << std::string_view(data + locSOF, image->size() - locSOF);
} else {
os << wpi::StringRef(data, size);
os << std::string_view(data, size);
}
// os.flush();
}
@@ -790,48 +781,50 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
// Read the request string from the stream
wpi::SmallString<128> reqBuf;
wpi::StringRef req = is.getline(reqBuf, 4096);
std::string_view req = is.getline(reqBuf, 4096);
if (is.has_error()) {
SDEBUG("error getting request string");
SDEBUG("{}", "error getting request string");
return;
}
enum { kCommand, kStream, kGetSettings, kGetSourceConfig, kRootPage } kind;
wpi::StringRef parameters;
std::string_view parameters;
size_t pos;
SDEBUG("HTTP request: '" << req << "'\n");
SDEBUG("HTTP request: '{}'\n", req);
// Determine request kind. Most of these are for mjpgstreamer
// compatibility, others are for Axis camera compatibility.
if ((pos = req.find("POST /stream")) != wpi::StringRef::npos) {
if ((pos = req.find("POST /stream")) != std::string_view::npos) {
kind = kStream;
parameters = req.substr(req.find('?', pos + 12)).substr(1);
} else if ((pos = req.find("GET /?action=stream")) != wpi::StringRef::npos) {
} else if ((pos = req.find("GET /?action=stream")) !=
std::string_view::npos) {
kind = kStream;
parameters = req.substr(req.find('&', pos + 19)).substr(1);
} else if ((pos = req.find("GET /stream.mjpg")) != wpi::StringRef::npos) {
} else if ((pos = req.find("GET /stream.mjpg")) != std::string_view::npos) {
kind = kStream;
parameters = req.substr(req.find('?', pos + 16)).substr(1);
} else if (req.find("GET /settings") != wpi::StringRef::npos &&
req.find(".json") != wpi::StringRef::npos) {
} else if (req.find("GET /settings") != std::string_view::npos &&
req.find(".json") != std::string_view::npos) {
kind = kGetSettings;
} else if (req.find("GET /config") != wpi::StringRef::npos &&
req.find(".json") != wpi::StringRef::npos) {
} else if (req.find("GET /config") != std::string_view::npos &&
req.find(".json") != std::string_view::npos) {
kind = kGetSourceConfig;
} else if (req.find("GET /input") != wpi::StringRef::npos &&
req.find(".json") != wpi::StringRef::npos) {
} else if (req.find("GET /input") != std::string_view::npos &&
req.find(".json") != std::string_view::npos) {
kind = kGetSettings;
} else if (req.find("GET /output") != wpi::StringRef::npos &&
req.find(".json") != wpi::StringRef::npos) {
} else if (req.find("GET /output") != std::string_view::npos &&
req.find(".json") != std::string_view::npos) {
kind = kGetSettings;
} else if ((pos = req.find("GET /?action=command")) != wpi::StringRef::npos) {
} else if ((pos = req.find("GET /?action=command")) !=
std::string_view::npos) {
kind = kCommand;
parameters = req.substr(req.find('&', pos + 20)).substr(1);
} else if (req.find("GET / ") != wpi::StringRef::npos || req == "GET /\n") {
} else if (req.find("GET / ") != std::string_view::npos || req == "GET /\n") {
kind = kRootPage;
} else {
SDEBUG("HTTP request resource not found");
SDEBUG("{}", "HTTP request resource not found");
SendError(os, 404, "Resource not found");
return;
}
@@ -841,13 +834,13 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
"-=&1234567890%./");
parameters = parameters.substr(0, pos);
SDEBUG("command parameters: \"" << parameters << "\"");
SDEBUG("command parameters: \"{}\"", parameters);
// Read the rest of the HTTP request.
// The end of the request is marked by a single, empty line
wpi::SmallString<128> lineBuf;
for (;;) {
if (is.getline(lineBuf, 4096).startswith("\n")) {
if (wpi::starts_with(is.getline(lineBuf, 4096), "\n")) {
break;
}
if (is.has_error()) {
@@ -859,7 +852,7 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
switch (kind) {
case kStream:
if (auto source = GetSource()) {
SDEBUG("request for stream " << source->GetName());
SDEBUG("request for stream {}", source->GetName());
if (!ProcessCommand(os, *source, parameters, false)) {
return;
}
@@ -873,11 +866,11 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
SendHeader(os, 200, "OK", "text/plain");
os << "Ignored due to no connected source."
<< "\r\n";
SDEBUG("Ignored due to no connected source.");
SDEBUG("{}", "Ignored due to no connected source.");
}
break;
case kGetSettings:
SDEBUG("request for JSON file");
SDEBUG("{}", "request for JSON file");
if (auto source = GetSource()) {
SendJSON(os, *source, true);
} else {
@@ -885,7 +878,7 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
}
break;
case kGetSourceConfig:
SDEBUG("request for JSON file");
SDEBUG("{}", "request for JSON file");
if (auto source = GetSource()) {
SendHeader(os, 200, "OK", "application/json");
CS_Status status = CS_OK;
@@ -896,7 +889,7 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
}
break;
case kRootPage:
SDEBUG("request for root page");
SDEBUG("{}", "request for root page");
SendHeader(os, 200, "OK", "text/html");
if (auto source = GetSource()) {
SendHTML(os, *source, false);
@@ -907,7 +900,7 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
break;
}
SDEBUG("leaving HTTP client thread");
SDEBUG("{}", "leaving HTTP client thread");
}
// worker thread for clients that connected to this server
@@ -934,7 +927,7 @@ void MjpegServerImpl::ServerThreadMain() {
return;
}
SDEBUG("waiting for clients to connect");
SDEBUG("{}", "waiting for clients to connect");
while (m_active) {
auto stream = m_acceptor->accept();
if (!stream) {
@@ -945,7 +938,7 @@ void MjpegServerImpl::ServerThreadMain() {
return;
}
SDEBUG("client connection from " << stream->getPeerIP());
SDEBUG("client connection from {}", stream->getPeerIP());
auto source = GetSource();
@@ -984,7 +977,7 @@ void MjpegServerImpl::ServerThreadMain() {
thr->m_cond.notify_one();
}
SDEBUG("leaving server thread");
SDEBUG("{}", "leaving server thread");
}
void MjpegServerImpl::SetSourceImpl(std::shared_ptr<SourceImpl> source) {
@@ -1007,19 +1000,15 @@ void MjpegServerImpl::SetSourceImpl(std::shared_ptr<SourceImpl> source) {
namespace cs {
CS_Sink CreateMjpegServer(const wpi::Twine& name,
const wpi::Twine& listenAddress, int port,
CS_Status* status) {
CS_Sink CreateMjpegServer(std::string_view name, std::string_view listenAddress,
int port, CS_Status* status) {
auto& inst = Instance::GetInstance();
wpi::SmallString<128> listenAddressBuf;
return inst.CreateSink(
CS_SINK_MJPEG,
std::make_shared<MjpegServerImpl>(
name, inst.logger, inst.notifier, inst.telemetry, listenAddress, port,
std::unique_ptr<wpi::NetworkAcceptor>(new wpi::TCPAcceptor(
port,
listenAddress.toNullTerminatedStringRef(listenAddressBuf).data(),
inst.logger))));
std::unique_ptr<wpi::NetworkAcceptor>(
new wpi::TCPAcceptor(port, listenAddress, inst.logger))));
}
std::string GetMjpegServerListenAddress(CS_Sink sink, CS_Status* status) {