PICout::withExternalBufferAnd decomposed to PICout::withExternalBufferAndID and PICout::withExternalBufferAnd

PIString::toPercentageEncoding/fromPercentageEncoding
piStringify()
PIHTTPClient support arguments
some doc
This commit is contained in:
2024-11-26 18:26:02 +03:00
parent 12114b3e77
commit 65d3168eb5
10 changed files with 156 additions and 50 deletions

View File

@@ -18,37 +18,40 @@ inline PICout operator <<(PICout s, const PIByteArray & ba) {
}
//! [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)

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
};

View File

@@ -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);

View File

@@ -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

View File

@@ -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,8 +23,8 @@ 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(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);
@@ -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();