diff options
| author | Jeremy Lainé <jeremy.laine@m4x.org> | 2010-08-28 23:00:49 +0000 |
|---|---|---|
| committer | Jeremy Lainé <jeremy.laine@m4x.org> | 2010-08-28 23:00:49 +0000 |
| commit | cd57c57ebd610f87b33701fd9513bbe173cf309d (patch) | |
| tree | f226d0457135a1c552f0466a04e0e3fbc77f9dd2 /src/server | |
| parent | 13b245f3bcc709b2a974b764bb209e1ea87768af (diff) | |
| download | qxmpp-cd57c57ebd610f87b33701fd9513bbe173cf309d.tar.gz | |
add module for statistics
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/mod_stats.cpp | 336 | ||||
| -rw-r--r-- | src/server/mod_stats.h | 66 |
2 files changed, 402 insertions, 0 deletions
diff --git a/src/server/mod_stats.cpp b/src/server/mod_stats.cpp new file mode 100644 index 00000000..4904e177 --- /dev/null +++ b/src/server/mod_stats.cpp @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2008-2010 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +#include <QCoreApplication> +#include <QDomElement> +#include <QSettings> +#include <QTimer> + +#include "QXmppConstants.h" +#include "QXmppDiscoveryIq.h" +#include "QXmppIncomingClient.h" +#include "QXmppIncomingServer.h" +#include "QXmppOutgoingServer.h" +#include "QXmppServer.h" +#include "QXmppServerPlugin.h" +#include "QXmppUtils.h" + +#include "mod_stats.h" + +static QXmppServerExtension *findExtension(QXmppServer *server, const QString &name) +{ + foreach (QXmppServerExtension *extension, server->loadedExtensions()) + if (extension->extensionName() == name) + return extension; + return 0; +} + +class QXmppServerStatsPrivate +{ +public: + QString jid; + + int incomingClients; + int incomingServers; + int outgoingServers; + + QSettings *statistics; + QString statisticsFile; + QTimer *statisticsTimer; +}; + +/// Read statistics from file. +/// +void QXmppServerStats::readStatistics() +{ + if (!d->statistics) + return; + + foreach (QXmppServerExtension *extension, server()->loadedExtensions()) + { + QVariantMap stats; + + // FIXME : remove hard-coded name + const QString group = (extension == this) ? "xmpp-server" : extension->extensionName(); + d->statistics->beginGroup(group); + foreach (const QString &key, d->statistics->childKeys()) + stats[key] = d->statistics->value(key); + d->statistics->endGroup(); + extension->setStatistics(stats); + } +} + +/// Write statistics to file. +/// +void QXmppServerStats::writeStatistics() +{ + if (!d->statistics) + return; + + foreach (QXmppServerExtension *extension, server()->loadedExtensions()) + { + const QVariantMap stats = extension->statistics(); + if (stats.isEmpty()) + continue; + + // FIXME : remove hard-coded name + const QString group = (extension == this) ? "xmpp-server" : extension->extensionName(); + d->statistics->beginGroup(group); + foreach (const QString &key, stats.keys()) + d->statistics->setValue(key, stats.value(key)); + d->statistics->endGroup(); + } +} + +QXmppServerStats::QXmppServerStats() + : d(new QXmppServerStatsPrivate) +{ + d->incomingClients = 0; + d->incomingServers = 0; + d->outgoingServers = 0; + d->statistics = 0; + d->statisticsTimer = new QTimer(this); + d->statisticsTimer->setInterval(30 * 1000); + + bool check = connect(d->statisticsTimer, SIGNAL(timeout()), + this, SLOT(writeStatistics())); + Q_ASSERT(check); + Q_UNUSED(check); +} + +QXmppServerStats::~QXmppServerStats() +{ + delete d; +} + +/// Returns the path of the file to which the statistics are written. +/// + +QString QXmppServerStats::statisticsFile() const +{ + return d->statisticsFile; +} + +/// Sets the path of the file to which the statistics are written. +/// +/// \param statisticsFile + +void QXmppServerStats::setStatisticsFile(const QString &statisticsFile) +{ + if (d->statistics) + { + delete d->statistics; + d->statistics = 0; + } + d->statisticsFile = statisticsFile; + if (!statisticsFile.isEmpty()) + { + d->statistics = new QSettings(statisticsFile, QSettings::IniFormat, this); + readStatistics(); + writeStatistics(); + } +} + +QStringList QXmppServerStats::discoveryItems() const +{ + return QStringList() << d->jid; +} + +QVariantMap QXmppServerStats::statistics() const +{ + QVariantMap stats; + stats["version"] = qApp->applicationVersion(); + stats["incoming-clients"] = d->incomingClients; + stats["incoming-servers"] = d->incomingServers; + stats["outgoing-servers"] = d->outgoingServers; + return stats; +} + +bool QXmppServerStats::handleStanza(QXmppStream *stream, const QDomElement &element) +{ + if (element.attribute("to") != d->jid) + return false; + + if (element.tagName() == "iq" && QXmppDiscoveryIq::isDiscoveryIq(element)) + { + QXmppDiscoveryIq discoIq; + discoIq.parse(element); + + if (discoIq.type() == QXmppIq::Get) + { + QXmppDiscoveryIq responseIq; + responseIq.setTo(discoIq.from()); + responseIq.setFrom(discoIq.to()); + responseIq.setId(discoIq.id()); + responseIq.setType(QXmppIq::Result); + responseIq.setQueryType(discoIq.queryType()); + responseIq.setQueryNode(discoIq.queryNode()); + + // check queried node + const QString queryNode = discoIq.queryNode(); + QXmppServerExtension *extension = 0; + QString key; + if (!queryNode.isEmpty()) + { + extension = findExtension(server(), queryNode.split("/").first()); + if (!extension || queryNode.count("/") > 1) + { + responseIq.setType(QXmppIq::Error); + const QXmppStanza::Error error(QXmppStanza::Error::Cancel, + QXmppStanza::Error::ServiceUnavailable); + responseIq.setError(error); + server()->sendPacket(responseIq); + return true; + } + if (queryNode.count("/")) + key = queryNode.split("/").last(); + } + + if (discoIq.queryType() == QXmppDiscoveryIq::InfoQuery) + { + // features + QStringList features = QStringList() << ns_disco_info << ns_disco_items; + responseIq.setFeatures(features); + + // identity + QList<QXmppDiscoveryIq::Identity> identities; + QXmppDiscoveryIq::Identity identity; + identity.setCategory("directory"); + identity.setType("statistics"); + if (!extension) + identity.setName("Server Statistics"); + else if (key.isEmpty()) + identity.setName(QString("%1 module").arg(extension->extensionName())); + else + identity.setName(QString("%1: %2").arg(key, extension->statistics().value(key).toString())); + identities.append(identity); + responseIq.setIdentities(identities); + } else { + QList<QXmppDiscoveryIq::Item> items; + if (!extension) + { + foreach (QXmppServerExtension *extension, server()->loadedExtensions()) + { + if (extension->statistics().isEmpty()) + continue; + QXmppDiscoveryIq::Item item; + item.setJid(d->jid); + item.setNode(extension->extensionName()); + items.append(item); + } + } else if (key.isEmpty()) { + QVariantMap stats = extension->statistics(); + foreach (const QString &key, stats.keys()) + { + QXmppDiscoveryIq::Item item; + item.setJid(d->jid); + item.setNode(extension->extensionName() + "/" + key); + items.append(item); + } + } + responseIq.setItems(items); + } + + server()->sendPacket(responseIq); + return true; + } + } + + return false; +} + +bool QXmppServerStats::start() +{ + // determine jid + if (d->jid.isEmpty()) + d->jid = "statistics." + server()->domain(); + + bool check = connect(server(), SIGNAL(streamAdded(QXmppStream*)), + this, SLOT(streamAdded(QXmppStream*))); + Q_ASSERT(check); + + check = connect(server(), SIGNAL(streamRemoved(QXmppStream*)), + this, SLOT(streamRemoved(QXmppStream*))); + Q_ASSERT(check); + + d->statisticsTimer->start(); + + return true; +} + +void QXmppServerStats::stop() +{ + d->statisticsTimer->stop(); + + disconnect(server(), SIGNAL(streamAdded(QXmppStream*)), + this, SLOT(streamAdded(QXmppStream*))); + + disconnect(server(), SIGNAL(streamRemoved(QXmppStream*)), + this, SLOT(streamRemoved(QXmppStream*))); +} + +void QXmppServerStats::streamAdded(QXmppStream *stream) +{ + if (qobject_cast<QXmppIncomingClient*>(stream)) + d->incomingClients++; + else if (qobject_cast<QXmppIncomingServer*>(stream)) + d->incomingServers++; + else if (qobject_cast<QXmppOutgoingServer*>(stream)) + d->outgoingServers++; + else + return; +} + +void QXmppServerStats::streamRemoved(QXmppStream *stream) +{ + if (qobject_cast<QXmppIncomingClient*>(stream)) + d->incomingClients--; + else if (qobject_cast<QXmppIncomingServer*>(stream)) + d->incomingServers--; + else if (qobject_cast<QXmppOutgoingServer*>(stream)) + d->outgoingServers--; + else + return; +} + +// PLUGIN + +class QXmppServerStatsPlugin : public QXmppServerPlugin +{ +public: + QXmppServerExtension *create(const QString &key) + { + if (key == QLatin1String("stats")) + return new QXmppServerStats; + else + return 0; + }; + + QStringList keys() const + { + return QStringList() << QLatin1String("stats"); + }; +}; + +Q_EXPORT_STATIC_PLUGIN2(mod_stats, QXmppServerStatsPlugin) + diff --git a/src/server/mod_stats.h b/src/server/mod_stats.h new file mode 100644 index 00000000..6f5a0146 --- /dev/null +++ b/src/server/mod_stats.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008-2010 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +#ifndef QXMPP_SERVER_STATS_H +#define QXMPP_SERVER_STATS_H + +#include "QXmppServerExtension.h" + +class QSettings; +class QXmppServerStatsPrivate; + +/// \brief QXmppServer extension for statistics. +/// + +class QXmppServerStats : public QXmppServerExtension +{ + Q_OBJECT + Q_CLASSINFO("ExtensionName", "stats"); + Q_PROPERTY(QString statisticsFile READ statisticsFile WRITE setStatisticsFile); + +public: + QXmppServerStats(); + ~QXmppServerStats(); + + QString statisticsFile() const; + void setStatisticsFile(const QString &statisticsFile); + + /// cond + QStringList discoveryItems() const; + bool handleStanza(QXmppStream *stream, const QDomElement &element); + QVariantMap statistics() const; + bool start(); + void stop(); + /// \endcond + +private slots: + void streamAdded(QXmppStream *stream); + void streamRemoved(QXmppStream *stream); + void writeStatistics(); + +private: + void readStatistics(); + QXmppServerStatsPrivate * const d; +}; + +#endif |
