void TApplicationServer::incomingConnection(int socketDescriptor) { T_TRACEFUNC("socketDescriptor: %d", socketDescriptor); switch ( Tf::app()->multiProcessingModule() ) { case TWebApplication::Thread: for (;;) { if (actionContextCount() < maxServers) { TActionThread *thread = new TActionThread(socketDescriptor); connect(thread, SIGNAL(finished()), this, SLOT(deleteActionContext())); insertPointer(thread); thread->start(); break; } Tf::msleep(1); qApp->processEvents(QEventLoop::ExcludeSocketNotifiers); } break; case TWebApplication::Prefork: { close(); // Closes the listening port TActionForkProcess *process = new TActionForkProcess(socketDescriptor); connect(process, SIGNAL(finished()), this, SLOT(deleteActionContext())); insertPointer(process); process->start(); break; } default: break; } }
void TApplicationServer::deleteActionContext() { T_TRACEFUNC(); QMutexLocker locker(&setMutex); actionContexts.remove(reinterpret_cast<TActionThread *>(sender())); sender()->deleteLater(); }
/*! \~english Returns the rendering data of the partial template given by \a templateName. \~japanese 部分テンプレート \a templateName に変数 \a vars を設定した描画データを返す */ QString TActionController::getRenderingData(const QString &templateName, const QVariantHash &vars) { T_TRACEFUNC("templateName: %s", qPrintable(templateName)); // Creates view-object QStringList names = templateName.split("/"); if (names.count() != 2) { tError("Invalid patameter: %s", qPrintable(templateName)); return QString(); } TDispatcher<TActionView> viewDispatcher(viewClassName(names[0], names[1])); TActionView *view = viewDispatcher.object(); if (!view) { return QString(); } QVariantHash hash = allVariants(); for (QHashIterator<QString, QVariant> i(vars); i.hasNext(); ) { i.next(); hash.insert(i.key(), i.value()); // item's value of same key is replaced } view->setController(this); view->setVariantHash(hash); return view->toString(); }
void TSmtpMailer::sendAndDeleteLater() { T_TRACEFUNC(""); send(); mailMessage.clear(); deleteLater(); }
TSendmailMailer::~TSendmailMailer() { T_TRACEFUNC(""); if (!mailMessage.isEmpty()) { tSystemWarn("Mail not sent. Deleted it."); } }
void TSmtpMailer::sendLater(const TMailMessage &message) { T_TRACEFUNC(""); mailMessage = message; QTimer::singleShot(0, this, SLOT(sendAndDeleteLater())); }
void TSendmailMailer::sendLater(const TMailMessage &message) { T_TRACEFUNC(""); mailMessage = message; QMetaObject::invokeMethod(this, "sendAndDeleteLater", Qt::QueuedConnection); }
/*! Creates and returns a TSessionStore object that matches the given key, or returns 0 if no matching session store is found. */ TSessionStore *TSessionStoreFactory::create(const QString &key) { T_TRACEFUNC("key: %s", qPrintable(key)); static const QString COOKIE_KEY = TSessionCookieStore().key().toLower(); static const QString SQLOBJECT_KEY = TSessionSqlObjectStore().key().toLower(); static const QString FILE_KEY = TSessionFileStore().key().toLower(); static const QString REDIS_KEY = TSessionRedisStore().key().toLower(); QMutexLocker locker(&mutex); loadPlugins(); TSessionStore *ret = 0; QString k = key.toLower(); if (k == COOKIE_KEY) { ret = new TSessionCookieStore; } else if (k == SQLOBJECT_KEY) { ret = new TSessionSqlObjectStore; } else if (k == FILE_KEY) { ret = new TSessionFileStore; } else if (k == REDIS_KEY) { ret = new TSessionRedisStore; } else { TSessionStoreInterface *ssif = sessIfMap->value(k); if (ssif) { ret = ssif->create(key); } } return ret; }
/*! Returns a QUrl to \a action of \a controller with arguments \a args. The current controller name is used, if the \a controller is a empty string. The current action name is used, if the \a action is a empty string. If \a query is not empty, sets the query string to an encoded version of \a query. */ QUrl TActionHelper::url(const QString &controller, const QString &action, const QStringList &args, const QVariantMap &query) const { T_TRACEFUNC("%s : %s", qPrintable(controller), qPrintable(action)); Q_ASSERT(this->controller()); QString path; QString ctrl = (controller.isEmpty()) ? this->controller()->name() : controller; QString act = (action.isEmpty()) ? this->controller()->activeAction() : action; path.append('/').append(ctrl).append('/').append(act); for (QStringListIterator i(args); i.hasNext(); ) { path.append('/').append(THttpUtility::toUrlEncoding(i.next())); } // appends query items QString querystr; for (QMapIterator<QString, QVariant> it(query); it.hasNext(); ) { it.next(); if (!it.key().isEmpty()) { querystr += it.key(); querystr += QLatin1Char('='); querystr += it.value().toString(); querystr += QLatin1Char('&'); } } querystr.chop(1); if (!querystr.isEmpty()) { path += QLatin1Char('?'); path += querystr; } return QUrl(path); }
bool TSendmailMailer::send(const TMailMessage &message) { T_TRACEFUNC(""); mailMessage = message; bool res = send(); mailMessage.clear(); return res; }
bool TApplicationServer::open() { T_TRACEFUNC(); if (!isListening()) { quint16 port = Tf::app()->treefrogSettings().value("ListenPort").toUInt(); if (!nativeListen(QHostAddress::Any, port)) { tSystemError("listen failed. port:%d", port); return false; } else { tSystemDebug("listen successfully. port:%d", port); } } // Loads libraries if (!libLoaded) { // Sets work directory QString libPath = Tf::app()->libPath(); if (QDir(libPath).exists()) { // To resolve the symbols in the app libraries QDir::setCurrent(libPath); } else { tSystemError("lib directory not found"); return false; } QStringList filter; #if defined(Q_OS_WIN) filter << "controller.dll" << "view.dll"; #elif defined(Q_OS_DARWIN) filter << "libcontroller.dylib" << "libview.dylib"; #elif defined(Q_OS_UNIX) filter << "libcontroller.so" << "libview.so"; #else filter << "libcontroller.*" << "libview.*"; #endif QDir controllerDir("."); QStringList list = controllerDir.entryList(filter, QDir::Files); for (QStringListIterator i(list); i.hasNext(); ) { QString path = controllerDir.absoluteFilePath(i.next()); QLibrary lib(path); if (lib.load()) { tSystemDebug("Library loaded: %s", qPrintable(path)); libLoaded = true; } else { tSystemDebug("%s", qPrintable(lib.errorString())); } } } TUrlRoute::initialize(); TSqlDatabasePool::initialize(); return true; }
TKvsDatabase &TActionContext::getKvsDatabase(TKvsDatabase::Type type) { T_TRACEFUNC("type:%d", (int)type); TKvsDatabase &db = kvsDatabases[(int)type]; if (!db.isValid()) { db = TKvsDatabasePool2::instance()->database(type); } return db; }
qint64 TActionContext::writeResponse(int statusCode, THttpResponseHeader &header, const QByteArray &contentType, QIODevice *body, qint64 length) { T_TRACEFUNC("statusCode:%d contentType:%s length:%s", statusCode, contentType.data(), qPrintable(QString::number(length))); header.setStatusLine(statusCode, THttpUtility::getResponseReasonPhrase(statusCode)); if (!contentType.isEmpty()) header.setContentType(contentType); return writeResponse(header, body, length); }
qint64 TActionContext::writeResponse(THttpResponseHeader &header, QIODevice *body, qint64 length) { T_TRACEFUNC("length:%s", qPrintable(QString::number(length))); header.setContentLength(length); header.setRawHeader("Server", "TreeFrog server"); header.setCurrentDate(); // Write data return writeResponse(header, body); }
TSmtpMailer::~TSmtpMailer() { T_TRACEFUNC(""); if (!mailMessage.isEmpty()) { // tSystemWarn("Mail not sent. Deleted it."); } if (pop) { delete pop; } delete socket; }
bool TApplicationServerBase::loadLibraries() { T_TRACEFUNC(""); // Loads libraries if (libsLoaded.isEmpty()) { // Sets work directory QString libPath = Tf::app()->libPath(); if (QDir(libPath).exists()) { // To resolve the symbols in the app libraries QDir::setCurrent(libPath); } else { tSystemError("lib directory not found"); return false; } loadedTimestamp = latestLibraryTimestamp(); #if defined(Q_OS_WIN) QStringList libs = { "controller", "view" }; #elif defined(Q_OS_LINUX) QStringList libs = { "libcontroller.so", "libview.so" }; #elif defined(Q_OS_DARWIN) QStringList libs = { "libcontroller.dylib", "libview.dylib" }; #else QStringList libs = { "libcontroller.so", "libview.so" }; #endif for (const auto &libname : libs) { auto lib = new QLibrary(libname); if (lib->load()) { tSystemDebug("Library loaded: %s", qPrintable(lib->fileName())); libsLoaded << lib; } else { tSystemWarn("%s", qPrintable(lib->errorString())); } } QStringList controllers = TActionController::availableControllers(); tSystemDebug("Available controllers: %s", qPrintable(controllers.join(" "))); } QDir::setCurrent(Tf::app()->webRootPath()); TSystemBus::instantiate(); TPublisher::instantiate(); TUrlRoute::instantiate(); TSqlDatabasePool::instantiate(); TKvsDatabasePool::instantiate(); return true; }
qint64 TActionContext::writeResponse(THttpResponseHeader& header, QIODevice *body, qint64 length) { T_TRACEFUNC("length:%s", qPrintable(QString::number(length))); qint64 res = -1; if (httpSocket) { header.setContentLength(length); header.setRawHeader("Server", "TreeFrog server"); header.setRawHeader("Date", QLocale::c().toString(QDateTime::currentDateTime().toUTC(), QLatin1String("ddd, dd MMM yyyy hh:mm:ss 'GMT'")).toLatin1()); header.setRawHeader("Connection", "close"); res = httpSocket->write(static_cast<THttpHeader*>(&header), body); } return res; }
QSqlDatabase &TActionContext::getDatabase(int id) { T_TRACEFUNC("id:%d", id); if (id < 0 || id >= Tf::app()->databaseSettingsCount()) return sqlDatabases[Tf::app()->databaseSettingsCount()]; // invalid db QSqlDatabase &db = sqlDatabases[id]; if (!db.isValid()) { db = TSqlDatabasePool::instance()->pop(id); beginTransaction(db); } return db; }
THttpSocket::THttpSocket(QObject *parent) : QTcpSocket(parent), lengthToRead(-1) { T_TRACEFUNC(""); do { sid = point.fetch_add(1); } while (!socketManager[sid].compareExchange(nullptr, this)); // store a socket tSystemDebug("THttpSocket sid:%d", sid); connect(this, SIGNAL(readyRead()), this, SLOT(readRequest())); connect(this, SIGNAL(requestWrite(const QByteArray&)), this, SLOT(writeRawData(const QByteArray&)), Qt::QueuedConnection); idleElapsed = std::time(nullptr); }
qint64 TActionContext::writeResponse(THttpResponseHeader &header, QIODevice *body, qint64 length) { T_TRACEFUNC("length:%s", qPrintable(QString::number(length))); header.setContentLength(length); header.setRawHeader("Server", "TreeFrog server"); # if QT_VERSION >= 0x040700 QDateTime utc = QDateTime::currentDateTimeUtc(); #else QDateTime utc = QDateTime::currentDateTime().toUTC(); #endif header.setRawHeader("Date", QLocale(QLocale::C).toString(utc, QLatin1String("ddd, dd MMM yyyy hh:mm:ss 'GMT'")).toLatin1()); // Write data return writeResponse(header, body); }
TKvsDatabase &TDatabaseContext::getKvsDatabase(TKvsDatabase::Type type) { T_TRACEFUNC("type:%d", (int)type); TKvsDatabase &db = kvsDatabases[(int)type]; if (!db.isValid()) { db = TKvsDatabasePool::instance()->database(type); } if (db.driver()) { db.driver()->moveToThread(QThread::currentThread()); } idleElapsed = (uint)std::time(nullptr); return db; }
/*! \~english Renders the template of the action \a action with the layout \a layout. \~japanese レイアウト \a layout を適用し、アクション \a action のテンプレートを描画する */ bool TActionController::render(const QString &action, const QString &layout) { T_TRACEFUNC(""); if (rendered) { tWarn("Has rendered already: %s", qPrintable(className() + '#' + activeAction())); return false; } rendered = true; // Creates view-object and displays it TDispatcher<TActionView> viewDispatcher(viewClassName(action)); setLayout(layout); response.setBody(renderView(viewDispatcher.object())); return !response.isBodyNull(); }
bool TSessionManager::store(TSession &session) { T_TRACEFUNC(""); if (session.id().isEmpty()) { tSystemError("Internal Error [%s:%d]", __FILE__, __LINE__); return false; } bool res = false; TSessionStore *store = TSessionStoreFactory::create(storeType()); if (store) { res = store->store(session); delete store; } return res; }
TSession TSessionManager::findSession(const QByteArray &id) { T_TRACEFUNC(""); QDateTime now = QDateTime::currentDateTime(); QDateTime validCreated = (sessionLifeTime() > 0) ? now.addSecs(-sessionLifeTime()) : now.addYears(-20); TSession session; if (!id.isEmpty()) { TSessionStore *store = TSessionStoreFactory::create(storeType()); if (store) { session = store->find(id, validCreated); delete store; } } return session; }
/*! \~english Renders the text \a text with the layout \a layout. \~japanese レイアウト \a layout を適用し、テキストを描画する */ bool TActionController::renderText(const QString &text, bool layoutEnable, const QString &layout) { T_TRACEFUNC(""); if (rendered) { tWarn("Has rendered already: %s", qPrintable(className() + '#' + activeAction())); return false; } rendered = true; // Creates TTextView object and displays it setLayout(layout); setLayoutEnabled(layoutEnable); TTextView *view = new TTextView(text); response.setBody(renderView(view)); delete view; return (!response.isBodyNull()); }
QSqlDatabase &TActionContext::getSqlDatabase(int id) { T_TRACEFUNC("id:%d", id); if (!Tf::app()->isSqlDatabaseAvailable()) { return sqlDatabases[0]; // invalid database } if (id < 0 || id >= Tf::app()->sqlDatabaseSettingsCount()) { throw RuntimeException("error database id", __FILE__, __LINE__); } QSqlDatabase &db = sqlDatabases[id]; if (!db.isValid()) { db = TSqlDatabasePool2::instance()->database(id); beginTransaction(db); } return db; }
QList<THttpRequest> THttpSocket::read() { T_TRACEFUNC(""); QList<THttpRequest> reqList; if (canReadRequest()) { if (fileBuffer.isOpen()) { fileBuffer.close(); THttpRequest req(readBuffer, fileBuffer.fileName(), peerAddress()); reqList << req; } else { reqList = THttpRequest::generate(readBuffer, peerAddress()); } readBuffer.clear(); lengthToRead = -1; } return reqList; }
THttpRequest THttpSocket::read() { T_TRACEFUNC(""); THttpRequest req; if (canReadRequest()) { int idx = readBuffer.indexOf("\r\n\r\n"); if (idx > 0) { if (fileBuffer.isOpen()) { fileBuffer.close(); req.setRequest(readBuffer.left(idx + 4), fileBuffer.fileName()); } else { req.setRequest(readBuffer.left(idx + 4), readBuffer.mid(idx + 4)); } readBuffer.clear(); req.setClientAddress(peerAddress()); } } return req; }
/*! \~english Renders the \a view view. \~japanese ビューを描画する */ QByteArray TActionController::renderView(TActionView *view) { T_TRACEFUNC("view: %p layout: %s", view, qPrintable(layout())); if (!view) { tSystemError("view null pointer. action:%s", qPrintable(activeAction())); return QByteArray(); } view->setController(this); view->setVariantHash(allVariants()); if (!layoutEnabled()) { // Renders without layout tSystemDebug("Renders without layout"); return Tf::app()->codecForHttpOutput()->fromUnicode(view->toString()); } // Displays with layout QString lay = (layout().isNull()) ? name().toLower() : layout().toLower(); TDispatcher<TActionView> layoutDispatcher(layoutClassName(lay)); TActionView *layoutView = layoutDispatcher.object(); TDispatcher<TActionView> defLayoutDispatcher(layoutClassName("application")); if (!layoutView) { if (!layout().isNull()) { tSystemDebug("Not found layout: %s", qPrintable(layout())); return QByteArray(); } else { // Use default layout layoutView = defLayoutDispatcher.object(); if (!layoutView) { tSystemDebug("Not found default layout. Renders without layout."); return Tf::app()->codecForHttpOutput()->fromUnicode(view->toString()); } } } // Renders layout layoutView->setVariantHash(allVariants()); layoutView->setController(this); layoutView->setSubActionView(view); return Tf::app()->codecForHttpOutput()->fromUnicode(layoutView->toString()); }
/*! \~english Renders the template given by \a templateName with the layout \a layout. \~japanese レイアウト \a layout を適用し、テンプレート \a templateName を描画する */ bool TActionController::renderTemplate(const QString &templateName, const QString &layout) { T_TRACEFUNC(""); if (rendered) { tWarn("Has rendered already: %s", qPrintable(className() + '#' + activeAction())); return false; } rendered = true; // Creates view-object and displays it QStringList names = templateName.split("/"); if (names.count() != 2) { tError("Invalid patameter: %s", qPrintable(templateName)); return false; } TDispatcher<TActionView> viewDispatcher(viewClassName(names[0], names[1])); setLayout(layout); response.setBody(renderView(viewDispatcher.object())); return (!response.isBodyNull()); }