PICout::withExternalBufferAnd decomposed to PICout::withExternalBufferAndID and PICout::withExternalBufferAnd
PIString::toPercentageEncoding/fromPercentageEncoding piStringify() PIHTTPClient support arguments some doc
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
#include "pip.h"
|
||||
|
||||
//! [own]
|
||||
inline PICout operator <<(PICout s, const PIByteArray & ba) {
|
||||
s.space(); // insert space after previous output
|
||||
s.quote(); // ONLY if you want to quoted your type
|
||||
inline PICout operator<<(PICout s, const PIByteArray & ba) {
|
||||
s.space(); // insert space after previous output
|
||||
s.quote(); // ONLY if you want to quoted your type
|
||||
s.saveAndSetControls(0); // clear all features and
|
||||
// save them to stack,
|
||||
// now it`s behavior similar to std::cout
|
||||
@@ -13,42 +13,45 @@ inline PICout operator <<(PICout s, const PIByteArray & ba) {
|
||||
s << ba[i];
|
||||
|
||||
s.restoreControls(); // restore features from stack
|
||||
s.quote(); // ONLY if you want to quoted your type
|
||||
s.quote(); // ONLY if you want to quoted your type
|
||||
return s;
|
||||
}
|
||||
//! [own]
|
||||
|
||||
// clang-format off
|
||||
void _() {
|
||||
|
||||
//! [0]
|
||||
using namespace PICoutManipulators;
|
||||
int a = 10, b = 32, c = 11;
|
||||
piCout << a << Hex << b << Bin << c;
|
||||
// 10 20 1011
|
||||
|
||||
piCout << "this" << "is" << Green << "green" << Default << "word";
|
||||
piCout << "this"
|
||||
<< "is" << Green << "green" << Default << "word";
|
||||
// this is green word
|
||||
|
||||
PICout(AddSpaces | AddNewLine | AddQuotes) << Tab << "tab and" << "quotes";
|
||||
PICout(AddSpaces | AddNewLine | AddQuotes) << Tab << "tab and"
|
||||
<< "quotes";
|
||||
// "tab and" "quotes"
|
||||
//! [0]
|
||||
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
|
||||
//! [notifier]
|
||||
class A: public PIObject {
|
||||
PIOBJECT(A)
|
||||
|
||||
public:
|
||||
A() {}
|
||||
EVENT_HANDLER2(void, pcf, int, id, PIString*, buff) {
|
||||
piCout << "PICout(" << id << ") finished:" << (*buff);
|
||||
}
|
||||
EVENT_HANDLER2(void, pcf, int, id, PIString *, buff) { piCout << "PICout(" << id << ") finished:" << (*buff); }
|
||||
};
|
||||
int main() {
|
||||
A a;
|
||||
CONNECTU(PICout::Notifier::object(), finished, &a, pcf);
|
||||
PIString buffer = "my buff:";
|
||||
PICout(&buffer, 1) << "int 10 ->" << 10 << ", time ->" << PITime::current();
|
||||
int my_id = PICout::registerExternalBufferID();
|
||||
PICout::withExternalBufferAndID(&buffer, my_id) << "int 10 ->" << 10 << ", time ->" << PITime::current();
|
||||
return 0;
|
||||
}
|
||||
// PICout( 1 ) finished: my buff:int 10 -> 10 , time -> PITime(14:07:09:000)
|
||||
|
||||
@@ -36,6 +36,16 @@ bool PIHTTPClient::init() {
|
||||
if (is_cancel) return false;
|
||||
PRIVATE->handle = curl_easy_init();
|
||||
if (!PRIVATE->handle) return false;
|
||||
auto ait = request.arguments().makeIterator();
|
||||
while (ait.next()) {
|
||||
if (!url.contains('?'))
|
||||
url.append('?');
|
||||
else
|
||||
url.append('&');
|
||||
url.append(ait.key().toPercentageEncoding());
|
||||
url.append('=');
|
||||
url.append(ait.value().toPercentageEncoding());
|
||||
}
|
||||
curl_easy_setopt(PRIVATE->handle, CURLOPT_WRITEDATA, this);
|
||||
curl_easy_setopt(PRIVATE->handle, CURLOPT_READDATA, this);
|
||||
curl_easy_setopt(PRIVATE->handle, CURLOPT_XFERINFODATA, this);
|
||||
@@ -156,6 +166,7 @@ PIHTTPClient * PIHTTPClient::create(const PIString & url_, PIHTTP::Method method
|
||||
PIHTTPClient * ret = new PIHTTPClient();
|
||||
static_cast<PIHTTP::MessageConst &>(ret->request) = req;
|
||||
ret->request.setMethod(method);
|
||||
ret->reply.setMethod(method);
|
||||
ret->url = url_;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ PICout PILog::makePICout(PIObject * context, Level cat) {
|
||||
if (context->name().isNotEmpty()) *buffer += " \"" + context->name() + "\"";
|
||||
*buffer += "] ";
|
||||
}
|
||||
return PICout::withExternalBuffer(buffer, id_by_cat.value(cat), PICoutManipulators::AddSpaces);
|
||||
return PICout::withExternalBufferAndID(buffer, id_by_cat.value(cat), PICoutManipulators::AddSpaces);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ PICout::~PICout() {
|
||||
PICout::__mutex__().unlock();
|
||||
}
|
||||
if (buffer_) {
|
||||
((NotifierObject *)Notifier::object())->finished(id_, buffer_);
|
||||
if (id_ >= 0) ((NotifierObject *)Notifier::object())->finished(id_, buffer_);
|
||||
} else {
|
||||
getStdStream(stream_).flush();
|
||||
}
|
||||
@@ -748,7 +748,12 @@ bool PICout::isOutputDeviceActive(PICout::OutputDevice d) {
|
||||
}
|
||||
|
||||
|
||||
PICout PICout::withExternalBuffer(PIString * buffer, int id, PIFlags<PICoutManipulators::PICoutControl> controls) {
|
||||
PICout PICout::withExternalBuffer(PIString * buffer, PIFlags<PICoutManipulators::PICoutControl> controls) {
|
||||
return withExternalBufferAndID(buffer, -1, controls);
|
||||
}
|
||||
|
||||
|
||||
PICout PICout::withExternalBufferAndID(PIString * buffer, int id, PIFlags<PICoutManipulators::PICoutControl> controls) {
|
||||
PICout c(controls);
|
||||
c.buffer_ = buffer;
|
||||
c.id_ = id;
|
||||
|
||||
@@ -30,15 +30,24 @@
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
//! \~english Macro used for conditional (piDebug) output to PICout
|
||||
//! \~russian Макрос для условного (piDebug) вывода в PICout
|
||||
//! \~english Macro used for conditional (piDebug) output to PICout(StdOut)
|
||||
//! \~russian Макрос для условного (piDebug) вывода в PICout(StdOut)
|
||||
# define piCout
|
||||
|
||||
//! \~english Macro used for conditional (piDebug) output to PICout(StdErr)
|
||||
//! \~russian Макрос для условного (piDebug) вывода в PICout(StdErr)
|
||||
# define piCerr
|
||||
|
||||
//! \relatesalso PIObject
|
||||
//! \~english Macro used for conditional (piDebug && PIObject::debug()) output to PICout for subclasses of PIObject
|
||||
//! \~russian Макрос для условного (piDebug && PIObject::debug()) вывода в PICout для наследников PIObject
|
||||
//! \~english Macro used for conditional (piDebug && PIObject::debug()) output to PICout(StdOut) for subclasses of PIObject
|
||||
//! \~russian Макрос для условного (piDebug && PIObject::debug()) вывода в PICout(StdOut) для наследников PIObject
|
||||
# define piCoutObj
|
||||
|
||||
//! \relatesalso PIObject
|
||||
//! \~english Macro used for conditional (piDebug && PIObject::debug()) output to PICout(StdErr) for subclasses of PIObject
|
||||
//! \~russian Макрос для условного (piDebug && PIObject::debug()) вывода в PICout(StdErr) для наследников PIObject
|
||||
# define piCerrObj
|
||||
|
||||
#else
|
||||
# define piCout PICout(piDebug, PICoutStdStream::StdOut)
|
||||
# define piCoutObj \
|
||||
@@ -375,15 +384,19 @@ public:
|
||||
static bool isOutputDeviceActive(OutputDevice d);
|
||||
|
||||
|
||||
//! \~english Construct with external buffer.
|
||||
//! \~russian Конструктор с внешним буфером.
|
||||
static PICout withExternalBuffer(PIString * buffer,
|
||||
PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces);
|
||||
|
||||
//! \~english Construct with external buffer and ID "id". See \a Notifier for details
|
||||
//! \~russian Конструктор с внешним буфером и ID "id". Подробнее \a Notifier
|
||||
static PICout withExternalBuffer(PIString * buffer,
|
||||
int id = 0,
|
||||
PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces |
|
||||
PICoutManipulators::AddNewLine);
|
||||
static PICout withExternalBufferAndID(PIString * buffer,
|
||||
int id,
|
||||
PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::DefaultControls);
|
||||
|
||||
//! \~english Returns unique external buffer ID for later use in \a withExternalBuffer()
|
||||
//! \~russian Возвращает уникальный ID для внешнего буфера для дальнейшего использования в \a withExternalBuffer()
|
||||
//! \~english Returns unique external buffer ID for later use in \a withExternalBufferAndID()
|
||||
//! \~russian Возвращает уникальный ID для внешнего буфера для дальнейшего использования в \a withExternalBufferAndID()
|
||||
static int registerExternalBufferID();
|
||||
|
||||
static PIMutex & __mutex__();
|
||||
@@ -397,7 +410,7 @@ private:
|
||||
static OutputDevices devs;
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
bool first_out_ = true, is_copy_ = false, format_changed_ = false, actve_ = true;
|
||||
int int_base_ = 10, win_attr_ = 0, id_ = 0;
|
||||
int int_base_ = 10, win_attr_ = 0, id_ = -1;
|
||||
PIString * buffer_ = nullptr;
|
||||
PICoutManipulators::PICoutControls ctrl_ = PICoutManipulators::DefaultControls;
|
||||
PICoutStdStream stream_ = PICoutStdStream::StdOut;
|
||||
|
||||
@@ -24,6 +24,24 @@ PIHTTP::MessageMutable & PIHTTP::MessageMutable::addHeader(const PIString & head
|
||||
}
|
||||
|
||||
|
||||
PIHTTP::MessageMutable & PIHTTP::MessageMutable::removeHeader(const PIString & header) {
|
||||
m_headers.remove(header);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIHTTP::MessageMutable & PIHTTP::MessageMutable::addArgument(const PIString & arg, const PIString & value) {
|
||||
m_arguments[arg] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIHTTP::MessageMutable & PIHTTP::MessageMutable::removeArgument(const PIString & arg) {
|
||||
m_arguments.remove(arg);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIHTTP::MessageMutable & PIHTTP::MessageMutable::setMethod(Method m) {
|
||||
m_method = m;
|
||||
return *this;
|
||||
|
||||
@@ -37,9 +37,11 @@ public:
|
||||
const PIMap<PIString, PIString> & headers() const { return m_headers; }
|
||||
const PIMap<PIString, PIString> & arguments() const { return m_arguments; }
|
||||
PIMap<PIString, PIString> & headers() { return m_headers; }
|
||||
PIMap<PIString, PIString> & arguments() { return m_arguments; }
|
||||
MessageMutable & addHeader(const PIString & header, const PIString & value);
|
||||
void removeHeader(const PIString & header) { m_headers.remove(header); }
|
||||
MessageMutable & removeHeader(const PIString & header);
|
||||
PIMap<PIString, PIString> & arguments() { return m_arguments; }
|
||||
MessageMutable & addArgument(const PIString & arg, const PIString & value);
|
||||
MessageMutable & removeArgument(const PIString & arg);
|
||||
static MessageMutable fromCode(PIHTTP::Code c);
|
||||
static MessageMutable fromMethod(PIHTTP::Method m);
|
||||
};
|
||||
|
||||
@@ -1810,6 +1810,46 @@ PIString & PIString::setReadableSize(llong bytes) {
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::toPercentageEncoding() const {
|
||||
static const PIString valid = "-._~"_a;
|
||||
PIString ret;
|
||||
PIByteArray utf8;
|
||||
bool ok = false;
|
||||
for (const auto & c: *this) {
|
||||
ok = false;
|
||||
if (c.isAscii()) {
|
||||
if (c.isAlpha() || c.isDigit())
|
||||
ok = true;
|
||||
else if (valid.contains(c))
|
||||
ok = true;
|
||||
}
|
||||
if (ok) {
|
||||
ret.append(c);
|
||||
} else {
|
||||
utf8 = PIString(c).toUTF8();
|
||||
for (auto u: utf8)
|
||||
ret.append('%').append(PIString::fromNumber(u, 16).expandLeftTo(2, '0'));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::fromPercentageEncoding(const PIString & in) {
|
||||
PIByteArray utf8;
|
||||
PIChar c;
|
||||
for (int i = 0; i < in.size_s(); ++i) {
|
||||
c = in[i];
|
||||
if (c == '%') {
|
||||
utf8 << static_cast<uchar>(in.mid(i + 1, 2).toInt(16));
|
||||
i += 2;
|
||||
} else
|
||||
utf8 << static_cast<uchar>(c.toAscii());
|
||||
}
|
||||
return PIString::fromUTF8(utf8);
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::arg(const PIString & v) {
|
||||
auto ph = minArgPlaceholder();
|
||||
if (!ph.isEmpty()) replaceAll(ph, v);
|
||||
|
||||
@@ -1687,6 +1687,10 @@ public:
|
||||
PIString & setReadableSize(llong bytes);
|
||||
|
||||
|
||||
//! \~english Returns [percentage-encoded](https://en.wikipedia.org/wiki/Percent-encoding) string.
|
||||
//! \~russian Возвращает [URL-кодированную](https://ru.wikipedia.org/wiki/URL) строку.
|
||||
PIString toPercentageEncoding() const;
|
||||
|
||||
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
|
||||
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
|
||||
//! \~\details
|
||||
@@ -1906,6 +1910,10 @@ public:
|
||||
//! \~\sa PIString::setReadableSize()
|
||||
static PIString readableSize(llong bytes);
|
||||
|
||||
//! \~english Returns string from [percentage-encoded](https://en.wikipedia.org/wiki/Percent-encoding) "in".
|
||||
//! \~russian Возвращает строку из [URL-кодированной](https://ru.wikipedia.org/wiki/URL)"in".
|
||||
static PIString fromPercentageEncoding(const PIString & in);
|
||||
|
||||
//! \~english Swaps string `str` other with this string.
|
||||
//! \~russian Меняет строку `str` с этой строкой.
|
||||
//! \~\details
|
||||
@@ -2020,4 +2028,15 @@ inline void piSwap(PIString & f, PIString & s) {
|
||||
f.swap(s);
|
||||
}
|
||||
|
||||
|
||||
//! \~english Returns string representation of \"v\", using PICout operator<<(T)
|
||||
//! \~russian Возвращает строковое представление \"v\", используя PICout operator<<(T)
|
||||
template<typename T>
|
||||
inline PIString piStringify(const T & v) {
|
||||
PIString ret;
|
||||
PICout::withExternalBuffer(&ret) << v;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#endif // PISTRING_H
|
||||
|
||||
33
main.cpp
33
main.cpp
@@ -11,13 +11,6 @@ const char * pageTitle = "<!DOCTYPE html>"
|
||||
"</body>"
|
||||
"</html>";
|
||||
|
||||
template<typename T>
|
||||
PIString stringify(const T & v) {
|
||||
PIString ret;
|
||||
PICout::withExternalBuffer(&ret, 0, PICoutManipulators::AddSpaces) << v;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
PIHTTPServer server;
|
||||
server.listen({"127.0.0.1:7777"});
|
||||
@@ -30,9 +23,9 @@ int main(int argc, char * argv[]) {
|
||||
server.registerUnhandled([](const PIHTTP::MessageConst & msg) -> PIHTTP::MessageMutable {
|
||||
PIHTTP::MessageMutable ret;
|
||||
piCout << "server rec:\n\tpath: %1\n\tmethod: %2\n\targs: %3\n\theaders: %4\n\tbody: %5\n"_a.arg(msg.path())
|
||||
.arg((int)msg.method())
|
||||
.arg(stringify(msg.arguments()))
|
||||
.arg(PIStringList(msg.headers().map<PIString>([](PIString k, PIString v) { return k + " = " + v; })).join("\n\t\t"))
|
||||
.arg(PIHTTP::methodName(msg.method()))
|
||||
.arg(piStringify(msg.arguments()))
|
||||
.arg(PIStringList(msg.headers().map<PIString>([](PIString k, PIString v) { return k + " = " + v; })).join("\n\t\t "))
|
||||
.arg(PIString::fromUTF8(msg.body()));
|
||||
ret.setCode(PIHTTP::Code::BadRequest);
|
||||
ret.setBody(PIByteArray::fromAscii("hello client! 0123456789"));
|
||||
@@ -40,14 +33,15 @@ int main(int argc, char * argv[]) {
|
||||
});
|
||||
|
||||
PIHTTP::MessageMutable req;
|
||||
req.setBody(PIByteArray::fromAscii("hello server!"));
|
||||
req.setBody(PIByteArray::fromAscii("hello server!")).addArgument("a0", "val.0").addArgument("a~r1", "знач,1"_u8);
|
||||
auto * c = PIHTTPClient::create("http://u:p@127.0.0.1:7777/api", PIHTTP::Method::Get, req);
|
||||
c->onFinish([](PIHTTP::MessageConst msg) {
|
||||
piCout << "client rec:\n\tcode: %5\n\tpath: %1\n\tmethod: %2\n\targs: %3\n\tbody: %4\n"_a.arg(msg.path())
|
||||
.arg((int)msg.method())
|
||||
.arg(stringify(msg.arguments()))
|
||||
.arg(PIString::fromUTF8(msg.body()))
|
||||
.arg((int)msg.code());
|
||||
piCout << "client rec:\n\tpath: %1\n\tmethod: %2\n\targs: %3\n\theaders: %4\n\tbody: %5\n"_a.arg(msg.path())
|
||||
.arg(PIHTTP::methodName(msg.method()))
|
||||
.arg(piStringify(msg.arguments()))
|
||||
.arg(
|
||||
PIStringList(msg.headers().map<PIString>([](PIString k, PIString v) { return k + " = " + v; })).join("\n\t\t "))
|
||||
.arg(PIString::fromUTF8(msg.body()));
|
||||
})
|
||||
->onError([c](PIHTTP::MessageConst r) {
|
||||
piCout << "error" << (int)r.code();
|
||||
@@ -59,9 +53,10 @@ int main(int argc, char * argv[]) {
|
||||
})
|
||||
->start();
|
||||
|
||||
// piMSleep(500);
|
||||
kbd.enableExitCapture();
|
||||
WAIT_FOR_EXIT
|
||||
piMSleep(500);
|
||||
// kbd.enableExitCapture();
|
||||
// WAIT_FOR_EXIT
|
||||
kbd.stopAndWait();
|
||||
|
||||
server.stop();
|
||||
// c->abort();
|
||||
|
||||
Reference in New Issue
Block a user