6#include "application.h"
10#include "controller.h"
11#include "dispatcher.h"
18#include <QCoreApplication>
30 : d_ptr(new ContextPrivate(app, app->engine(), app->dispatcher(), app->plugins()))
32 auto req =
new DummyRequest(
this);
33 req->
body =
new QBuffer(
this);
34 req->
body->open(QBuffer::ReadWrite);
38 d_ptr->request =
new Request(req);
39 d_ptr->request->d_ptr->engine = d_ptr->engine;
44 delete d_ptr->request;
45 delete d_ptr->response;
52 return !d->error.isEmpty();
58 if (
error.isEmpty()) {
62 qCCritical(CUTELYST_CORE) <<
error;
72bool Context::state() const noexcept
114QString Context::actionName() const noexcept
117 return d->action->name();
120QString Context::ns() const noexcept
123 return d->action->ns();
141 return d->dispatcher;
144QString Cutelyst::Context::controllerName() const noexcept
147 return d->action->className();
153 return d->action->controller();
159 return d->dispatcher->controller(name);
171 return d->app->view(name);
177 d->view = d->app->view(name);
190 return d->stash.value(key);
196 return d->stash.value(key, defaultValue);
202 return d->stash.take(key);
208 return d->stash.remove(key);
214 d->stash.insert(key, value);
220 d->stash.insert(key, QVariant::fromValue(map));
230 const QStringList &args,
235 QUrl uri = d->request->uri();
238 if (path.isEmpty()) {
240 const QString controllerNS = d->action->controller()->ns();
241 if (!controllerNS.isEmpty()) {
242 _path.prepend(controllerNS);
248 if (!args.isEmpty()) {
249 if (_path.compare(u
"/") == 0) {
250 _path += args.join(u
'/');
252 _path = _path + u
'/' + args.join(u
'/');
256 if (!_path.startsWith(u
'/')) {
259 uri.setPath(_path, QUrl::DecodedMode);
262 if (!queryValues.isEmpty()) {
264 if (queryValues.size()) {
265 auto it = queryValues.constEnd();
266 while (it != queryValues.constBegin()) {
268 query.addQueryItem(it.key(), it.value());
278 const QStringList &captures,
279 const QStringList &args,
285 if (action ==
nullptr) {
289 QStringList localArgs = args;
290 QStringList localCaptures = captures;
292 Action *expandedAction = d->dispatcher->expandAction(
this, action);
294 while (localCaptures.size() < expandedAction->
numberOfCaptures() && localArgs.size()) {
295 localCaptures.append(localArgs.takeFirst());
298 QStringList localCapturesAux = localCaptures;
299 localCapturesAux.append(localArgs);
300 localArgs = localCapturesAux;
301 localCaptures = QStringList();
304 const QString path = d->dispatcher->uriForAction(action, localCaptures);
305 if (path.isEmpty()) {
306 qCWarning(CUTELYST_CORE) <<
"Can not find action for" << action << localCaptures;
310 uri =
uriFor(path, localArgs, queryValues);
315 const QStringList &captures,
316 const QStringList &args,
322 Action *action = d->dispatcher->getActionByPath(path);
324 qCWarning(CUTELYST_CORE) <<
"Can not find action for" << path;
328 uri =
uriFor(action, captures, args, queryValues);
342 d->dispatcher->forward(
this, action);
357 if (--d->actionRefCount) {
361 if (Q_UNLIKELY(d->engineRequest->status & EngineRequest::Finalized)) {
362 qCWarning(CUTELYST_ASYNC) <<
"Trying to async attach to a finalized request! Skipping...";
366 if (d->engineRequest->status & EngineRequest::Async) {
367 while (d->asyncAction < d->pendingAsync.size()) {
368 Component *action = d->pendingAsync[d->asyncAction++];
369 const bool ret =
execute(action);
371 if (d->actionRefCount) {
380 Q_EMIT d->app->afterDispatch(
this);
389 return d->dispatcher->forward(
this, action);
395 return d->dispatcher->forward(
this, action);
401 return d->dispatcher->getAction(action, ns);
407 return d->dispatcher->getActions(action, ns);
419 Q_ASSERT_X(code,
"Context::execute",
"trying to execute a null Cutelyst::Component");
421 static int recursion =
422 qEnvironmentVariableIsSet(
"RECURSION") ? qEnvironmentVariableIntValue(
"RECURSION") : 1000;
423 if (d->stack.size() >= recursion) {
424 QString msg = QStringLiteral(
"Deep recursion detected (stack size %1) calling %2, %3")
425 .arg(QString::number(d->stack.size()), code->
reverse(), code->
name());
435 const QString statsInfo = d->statsStartExecute(code);
441 if (d->stats && !statsInfo.isEmpty()) {
442 d->statsFinishExecute(statsInfo);
465QVariant Context::config(
const QString &key,
const QVariant &defaultValue)
const
468 return d->app->config(key, defaultValue);
471QVariantMap Context::config() const noexcept
474 return d->app->config();
478 const char *sourceText,
479 const char *disambiguation,
483 return d->app->translate(d->locale, context, sourceText, disambiguation, n);
490 if (Q_UNLIKELY(d->engineRequest->status & EngineRequest::Finalized)) {
491 qCWarning(CUTELYST_CORE) <<
"Trying to finalize a finalized request! Skipping...";
496 qCDebug(CUTELYST_STATS,
497 "Response Code: %d; Content-Type: %s; Content-Length: %s",
498 d->response->status(),
499 d->response->headers().header(
"Content-Type"_qba,
"unknown"_qba).constData(),
500 d->response->headers().header(
"Content-Length"_qba,
"unknown"_qba).constData());
502 const std::chrono::duration<double> duration =
503 std::chrono::steady_clock::now() - d->engineRequest->startOfRequest;
506 if (duration.count() == 0.0) {
507 average = QStringLiteral(
"??");
509 average = QString::number(1.0 / duration.count(),
'f');
510 average.truncate(average.size() - 3);
512 qCInfo(CUTELYST_STATS) << qPrintable(QStringLiteral(
"Request took: %1s (%2/s)\n%3")
513 .arg(QString::number(duration.count(),
'f'),
515 QString::fromLatin1(d->stats->report())));
520 d->engineRequest->finalize();
523QString ContextPrivate::statsStartExecute(
Component *code)
527 if (code->
name().startsWith(u
'_')) {
533 if (qobject_cast<Action *>(code)) {
534 actionName.prepend(u
'/');
537 if (stack.size() > 2) {
538 actionName = u
"-> " + actionName;
540 actionName.rightJustified(actionName.size() + stack.size() - 2, QLatin1Char(
' '));
543 stats->profileStart(actionName);
548void ContextPrivate::statsFinishExecute(
const QString &statsInfo)
550 stats->profileEnd(statsInfo);
556 auto it = unite.constBegin();
557 while (it != unite.constEnd()) {
558 d->stash.insert(it.key(), it.value());
563#include "moc_context.cpp"
564#include "moc_context_p.cpp"
This class represents a Cutelyst Action.
virtual qint8 numberOfCaptures() const
The Cutelyst Application.
Headers & defaultHeaders() noexcept
The Cutelyst Component base class.
QString reverse() const noexcept
QString name() const noexcept
QStringList errors() const noexcept
Returns a list of errors that were defined.
bool forward(Component *component)
QVector< Plugin * > plugins() const
Context(Application *app)
Constructs a new DUMMY Context object that is child of Application This currently is experimental to ...
void detach(Action *action=nullptr)
QStack< Component * > stack() const noexcept
QLocale locale() const noexcept
void setState(bool state) noexcept
Sets the state of the current executed action, setting to false will make the dispatcher skip non pro...
QUrl uriFor(const QString &path={}, const QStringList &args={}, const ParamsMultiMap &queryValues={}) const
Response * res() const noexcept
QString translate(const char *context, const char *sourceText, const char *disambiguation=nullptr, int n=-1) const
void setStash(const QString &key, const QVariant &value)
void finalize()
finalize the request right away this is automatically called at the end of the actions chain
bool stashRemove(const QString &key)
QVariant stashTake(const QString &key)
void attachAsync()
attachAsync
bool setCustomView(QStringView name)
void setLocale(const QLocale &locale)
View * customView() const noexcept
QVector< Action * > getActions(QStringView action, QStringView ns={}) const
bool detached() const noexcept
Action * getAction(QStringView action, QStringView ns={}) const
Dispatcher * dispatcher() const noexcept
Application * app() const noexcept
View * view(QStringView name={}) const
QUrl uriForAction(QStringView path, const QStringList &captures={}, const QStringList &args={}, const ParamsMultiMap &queryValues={}) const
void detachAsync() noexcept
bool execute(Component *code)
void appendError(const QString &error)
Sets an error string and try to stop.
Engine * engine() const noexcept
bool error() const noexcept
Returns true if an error was set.
Response * response() const noexcept
Cutelyst Controller base class
QIODevice * body() const noexcept
Cutelyst View abstract view component
The Cutelyst namespace holds all public Cutelyst API.
QMultiMap< QString, QString > ParamsMultiMap