diff options
author | Denis Dzyubenko <denis.dzyubenko@nokia.com> | 2011-10-25 11:31:53 +0200 |
---|---|---|
committer | Denis Dzyubenko <denis.dzyubenko@nokia.com> | 2011-10-25 11:31:53 +0200 |
commit | 79ab0a667e9d9d11cc1de0f3ed21a37f5c2909ee (patch) | |
tree | defc8568b03b974ec7b306f9e32dab38d97951e9 /tools |
Long live QtJsonDb!
Diffstat (limited to 'tools')
-rw-r--r-- | tools/adb-dump/adb-dump.pro | 19 | ||||
-rw-r--r-- | tools/adb-dump/main.cpp | 82 | ||||
-rw-r--r-- | tools/aodbread/aodbread.pro | 19 | ||||
-rw-r--r-- | tools/aodbread/main.cpp | 303 | ||||
-rw-r--r-- | tools/jsondb-client/client.cpp | 501 | ||||
-rw-r--r-- | tools/jsondb-client/client.h | 115 | ||||
-rw-r--r-- | tools/jsondb-client/jsondb-client.pro | 16 | ||||
-rw-r--r-- | tools/jsondb-client/main.cpp | 118 | ||||
-rw-r--r-- | tools/tools.pro | 3 |
9 files changed, 1176 insertions, 0 deletions
diff --git a/tools/adb-dump/adb-dump.pro b/tools/adb-dump/adb-dump.pro new file mode 100644 index 00000000..454f3a85 --- /dev/null +++ b/tools/adb-dump/adb-dump.pro @@ -0,0 +1,19 @@ +include($$PWD/../../src/3rdparty/btree/btree.pri) + +TARGET = adb-dump +DESTDIR = $$QT.jsondb.bins + +target.path = $$[QT_INSTALL_BINS] +INSTALLS += target + +QT = core + +mac:CONFIG -= app_bundle + +!mac:LIBS += -lcrypto + +INCLUDEPATH += ../../src/daemon + +HEADERS += ../../src/daemon/aodb.h + +SOURCES += main.cpp ../../src/daemon/aodb.cpp diff --git a/tools/adb-dump/main.cpp b/tools/adb-dump/main.cpp new file mode 100644 index 00000000..7978c829 --- /dev/null +++ b/tools/adb-dump/main.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010 Nokia Corporation + */ + +#include "aodb.h" +#include <iostream> +#include <QCoreApplication> +#include <QStringList> +#include <QDebug> + +QString progname; +bool gCompact = false; + +/***************************************************************************/ + +using namespace std; + +static void usage() +{ + cout << "Usage: " << qPrintable(progname) << " [OPTIONS] [<.db filename>]" << endl + << endl << "OPTIONS:" << endl + << "-compact\tcompacts the db file before dumping." << endl << endl; + exit(0); +} + + +int main(int argc, char * argv[]) +{ + QCoreApplication::setOrganizationName("Nokia"); + QCoreApplication::setOrganizationDomain("nrcc.noklab.com"); + QCoreApplication::setApplicationName("adb-dump"); + QCoreApplication::setApplicationVersion("1.0"); + + QCoreApplication app(argc, argv); + QStringList args = QCoreApplication::arguments(); + + progname = args.takeFirst(); + while (args.size()) { + QString arg = args.at(0); + if (!arg.startsWith("-")) + break; + args.removeFirst(); + if ( arg == "-help") + usage(); + else if ( arg == "-compact") + gCompact = true; + /*else if (arg == "-load") { + if (args.isEmpty()) { + cout << "Invalid argument " << qPrintable(arg) << endl; + usage(); + return 0; + } + loadFile = args.at(0); + args.removeFirst(); + }*/ else { + cout << "Unknown argument " << qPrintable(arg) << endl; + usage(); + return 0; + } + } + + AoDb aoDB; + while (args.size()) { + QString adbFileName = args.takeFirst(); + qDebug(); + if (gCompact) { + qDebug() << "Compacting..."; + aoDB.open(adbFileName, AoDb::NoSync); + aoDB.compact(); + } + else + aoDB.open(adbFileName, AoDb::ReadOnly|AoDb::NoSync); + + qDebug () << "Dumping file: " << adbFileName; + qDebug () << "============================================================="; + aoDB.dump(); + qDebug (); qDebug (); + aoDB.close(); + } + + return 0; +} diff --git a/tools/aodbread/aodbread.pro b/tools/aodbread/aodbread.pro new file mode 100644 index 00000000..f86af6f1 --- /dev/null +++ b/tools/aodbread/aodbread.pro @@ -0,0 +1,19 @@ +TARGET = aodbread + +QT = network declarative testlib +CONFIG -= app_bundle +CONFIG += debug + +include($$PWD/../../src/common/common.pri) + +INCLUDEPATH += $$PWD/../../src/daemon +LIBS += -L$$QT.jsondb.libs +!mac:LIBS += -lssl -lcrypto + +DEFINES += SRCDIR=\\\"$$PWD/\\\" + +include($$PWD/../../src/daemon/daemon.pri) + +SOURCES += \ + main.cpp \ + diff --git a/tools/aodbread/main.cpp b/tools/aodbread/main.cpp new file mode 100644 index 00000000..d45eb757 --- /dev/null +++ b/tools/aodbread/main.cpp @@ -0,0 +1,303 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore> + +#include "aodb.h" +#include "btree.h" + +#include "qson/qson.h" +#include "qson/qsonparser.h" + +#include "json.h" + +Q_USE_JSONDB_NAMESPACE + +QString printable(const QByteArray &ba) +{ + QByteArray array = ba; + + if (ba.startsWith("QSN")) { + QVariant obj = qsonToVariant(QsonParser::fromRawData(ba)); + JsonWriter writer; +// writer.setAutoFormatting(true); + return QString("QSN:") +writer.toString(obj); + } + + // check if it is a number + bool isNumber = true; + for (int i = 0; i < array.size(); ++i) { + if (array.at(i) < 0 || array.at(i) > 9) { + isNumber = false; + break; + } + } + if (isNumber) { + for (int i = 0; i < array.size(); ++i) { + array[i] = array.at(i)+'0'; + } + return QString("N:") +QString::fromLatin1(array); + } + + // check if utf-16 latin string + bool utf16 = true; + for (int i = 0; i < array.size(); ++i) { + if (i % 2 == 0) { + if (!isprint(array.at(i))) { + utf16 = false; + break; + } + } else { + if (array.at(i) != 0) { + utf16 = false; + break; + } + } + } + if (utf16) { + return QString("U:") + QString::fromUtf16((const ushort *)array.constData(), array.size()/2); + } + + for (int i = 0; i < array.size(); ++i) { + if (array.at(i) == 0) + array[i] = '_'; + } + + bool isprintable = true; + for (int i = 0; i < array.size(); ++i) { + if (!isprint(array.at(i))) { + isprintable = false; + break; + } + } + if (isprintable) { + return QString("S:") + QString::fromLatin1(array); + } + + if (ba.size() == 5 && ba.at(4) == 'S') { + // state change + quint32 state = qFromBigEndian<quint32>((const uchar *)ba.mid(0, 4).constData()); + return QString("State:") + QString::number(state); + } + array = ba.toHex(); + return QString("x:") + QString::fromLatin1(array); +} + +void makePrintable(const QByteArray &key, QString &keyString, const QByteArray &value, QString &valueString) +{ + if (key.size() == 5 && key.at(4) == 'S') { + // state change + quint32 state = qFromBigEndian<quint32>((const uchar *)key.mid(0, 4).constData()); + keyString = QString("State:") + QString::number(state); + + QStringList changes; + const uchar *data = (const uchar *)value.constData(); + for (int i = 0; i < value.size() / 16; ++i) { + quint32 startKey = qFromBigEndian<quint32>(&data[16 * i]); + quint32 startTypeNumber = qFromBigEndian<quint32>(&data[16 * i + 4]); + quint32 endKey = qFromBigEndian<quint32>(&data[16 * i + 8]); + quint32 endTypeNumber = qFromBigEndian<quint32>(&data[16 * i + 12]); + changes << QString("objectTypeKey %2->%4, objectKey %1->%3").arg(startKey).arg(startTypeNumber).arg(endKey).arg(endTypeNumber); + } + valueString = changes.join(","); + return; + } + + keyString = printable(key); + valueString = printable(value); +} + +bool gStat = false; +bool gDump = false; +bool gWantCompact = false; +bool gShowAll = false; +bool gShowAllReversed = false; +quint32 gShowState = 0; +qint64 gDumpPage = 0; + +void usage() +{ + qDebug() << QCoreApplication::arguments().at(0) + << "[--dump-page num] [--stat] [--dump] [--compact] [--all|--all-reversed] [--state num] database_file"; +} + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + QStringList args = app.arguments(); + args.pop_front(); + + if (args.isEmpty()) { + usage(); + return 0; + } + + for (; args.size() > 1; ) { + QString arg = args.takeFirst(); + if (arg == QLatin1String("--stat")) { + gStat = true; + } else if (arg == QLatin1String("--dump")) { + gDump = true; + } else if (arg == QLatin1String("--compact")) { + gWantCompact = true; + } else if (arg == QLatin1String("--all")) { + gShowAll = true; + } else if (arg == QLatin1String("--all-reversed")) { + gShowAllReversed = true; + } else if (arg == QLatin1String("--state")) { + bool ok = false; + gShowState = args.takeFirst().toInt(&ok); + if (!ok) { + usage(); + return 0; + } + } else if (arg == QLatin1String("--dump-page")) { + bool ok = false; + gDumpPage = args.takeFirst().toInt(&ok); + if (!ok) { + usage(); + return 0; + } + } else { + usage(); + return 0; + } + } + + if (args.isEmpty()) + return 0; + + QString filename = args.at(0); + + if (gDumpPage > 0) { + return btree_dump_page(filename.toLocal8Bit().constData(), gDumpPage); + } else if (gDumpPage < 0) { + uint32_t page = 1; + while (btree_dump_page(filename.toLocal8Bit().constData(), page)) + ++page; + return 1; + } + + AoDb db; + if (!db.open(filename, AoDb::ReadOnly)) { + qDebug() << "cannot open" << filename; + usage(); + return 0; + } + + if (gStat) { + const struct btree_stat *bs = db.stat(); + qDebug() << "stat:"; + qDebug() << "\thits:" << bs->hits; + qDebug() << "\treads:" << bs->reads; + qDebug() << "\tmax_cache:" << bs->max_cache; + qDebug() << "\tbranch_pages:" << bs->branch_pages; + qDebug() << "\tleaf_pages:" << bs->leaf_pages; + qDebug() << "\toverflow_pages:" << bs->overflow_pages; + qDebug() << "\trevisions:" << bs->revisions; + qDebug() << "\tdepth:" << bs->depth; + qDebug() << "\tentries:" << bs->entries; + qDebug() << "\tpsize:" << bs->psize; + qDebug() << "\tcreated_at:" << bs->created_at << "(" << QDateTime::fromTime_t(bs->created_at) << ")"; + qDebug() << "\ttag:" << bs->tag; + qDebug() << ""; + } + if (gDump) { + db.dump(); + } + + if (gShowState != 0) { +#if 0 + AoDb statedb; + QFileInfo fi(filename); + if (!statedb.open(QString("%1/%2-States.db").arg(fi.dir().path()).arg(fi.baseName()), AoDb::ReadOnly)) { + qDebug() << "cannot open" << filename; + usage(); + return 0; + } + ObjectCursor cursor(&statedb, &db); + bool ok = cursor.first(gShowState); + if (!ok) { + qDebug() << "Could not seek to" << gShowState; + return 0; + } + QByteArray key, value; + for (int i = 0; ok && cursor.current(key, value); ok = cursor.next(), ++i) { + QString keyString, valueString; + makePrintable(key, keyString, value, valueString); + qDebug() << i << ":" << keyString << ":" << valueString; + } +#endif + } + + if (gShowAllReversed) { + AoDbCursor cursor(&db); + QByteArray key, value; + int i = 0; + for (bool ok = cursor.last(); ok && cursor.current(key, value); ok = cursor.prev(), ++i) { + QString keyString, valueString; + makePrintable(key, keyString, value, valueString); + qDebug() << i << ":" << keyString << ":" << valueString; + } + } else if (gShowAll) { + AoDbCursor cursor(&db); + QByteArray key, value; + int i = 0; + for (bool ok = cursor.first(); ok && cursor.current(key, value); ok = cursor.next(), ++i) { + QString keyString, valueString; + makePrintable(key, keyString, value, valueString); + qDebug() << i << ":" << keyString << ":" << valueString; + } + } + + if (gWantCompact) { + db.close(); + db.open(filename); + if (db.compact()) { + qDebug() << "compacted."; + } else { + qDebug() << "failed to compact" << filename; + } + db.close(); + } + return 1; +} diff --git a/tools/jsondb-client/client.cpp b/tools/jsondb-client/client.cpp new file mode 100644 index 00000000..1e674bcb --- /dev/null +++ b/tools/jsondb-client/client.cpp @@ -0,0 +1,501 @@ +/**************************************************************************** +** +** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QSocketNotifier> +#include <QCoreApplication> +#include <QStringBuilder> +#include <QMetaObject> +#include <QThread> +#include <QVariant> +#include <QDir> +#include <iostream> +#include <sstream> +#include <iomanip> + +#include "json.h" + +#include "client.h" + +Q_USE_JSONDB_NAMESPACE + +extern bool gDebug; + +const char* InputThread::commands[] = { "changesSince", + "create {\"", + "find", + "help", + "notify create [?", + "notify remove [?", + "notify update [?", + "query [?", + "quit", + "remove", + "update", + 0 }; + +InputThread *InputThread::threadInstance = 0; + +InputThread *InputThread::instance() +{ + if (!threadInstance) + threadInstance = new InputThread; + return threadInstance; +} + +InputThread::~InputThread() +{ + if (hist && !historyFile.isEmpty()) + history(hist, 0, H_SAVE, historyFile.toLocal8Bit().constData()); + if (hist) { + history_end(hist); + hist = 0; + } +} + +char const* InputThread::prompt(EditLine *e) +{ + Q_UNUSED(e); + char const* string = "jclient> "; + return string; +} + +QString InputThread::longestCommonPrefix(const QStringList &list) +{ + if (list.size() > 1) { + QChar temp; + int pos = 0; + for (bool roundComplete = true; roundComplete; pos++) { + for (int i = 0; i < list.size(); i++) { + QString entry = list[i]; + if (entry.length() <= pos) { + roundComplete = false; + break; + } else if (i == 0) + temp = list[i][pos]; + else { + if (temp != list[i][pos]) { + roundComplete = false; + break; + } + } + } + } + return list[0].left(pos-1); + } else if (list.size() == 1) + return list[0]; + else + return QString(); +} + +unsigned char InputThread::console_tabkey(EditLine * el, int ch) +{ + Q_UNUSED(ch); + QStringList matches; + const LineInfo *lineInfo = el_line(el); + for (int i = 0; commands[i] != 0; i++) { + int compare = qstrncmp(commands[i], lineInfo->buffer, lineInfo->lastchar-lineInfo->buffer); + if (compare == 0) { + matches << QString::fromLocal8Bit(commands[i]); + } + } + + int m = matches.size(); + if (m == 1) { + QString missing = matches[0].remove(0,lineInfo->lastchar-lineInfo->buffer); + el_insertstr(el, qPrintable(missing)); + return CC_REFRESH; + } else if (m > 1) { + instance()->async_print("\n" % matches.join("\n")); + QString missing = longestCommonPrefix(matches).remove(0,lineInfo->lastchar-lineInfo->buffer); + el_insertstr(el, qPrintable(missing)); + return CC_REFRESH; + } + return CC_ARGHACK; +} + +void InputThread::run() +{ + int count; + const char *line; + HistEvent ev; + + el = el_init("jsondb-client", stdin, stdout, stderr); + el_set(el, EL_PROMPT, &prompt); + el_set(el, EL_EDITOR, "emacs"); + hist = history_init(); + el_set(el, EL_ADDFN, "tab-key", "TAB KEY PRESS", console_tabkey); + if (hist == 0) { + qDebug() << "initializing the history failed."; + exit(-1); + } + history(hist, &ev, H_SETSIZE, 800); + historyFile = QDir::homePath() + QDir::separator() + QLatin1String(".jsondb/history"); + history(hist, &ev, H_LOAD, historyFile.toLocal8Bit().constData()); + el_set(el, EL_HIST, history, hist); + el_set(el, EL_BIND, "\t", "tab-key", NULL); + + while (true) { + line = el_gets(el, &count); + + if (count > 0) { + QString cmd = QString(line).trimmed(); + if (cmd == "quit") + break; + else if (!cmd.isEmpty()) { + emit (commandReceived(cmd)); + history(hist, &ev, H_ENTER, line); + } + } + } + + history(hist, &ev, H_SAVE, historyFile.toLocal8Bit().constData()); + history_end(hist); + hist = 0; + el_end(el); + + exit(0); +} + +void InputThread::print(const QString &message) +{ + if (threadInstance) { + instance()->async_print(message); + } else { + std::cout << qPrintable(message) << std::endl; + } +} + +void InputThread::async_print(const QString &message) +{ + QString clear(strlen(prompt(0)), QChar('\b')); + std::cout << qPrintable(clear) << qPrintable(message) << std::endl; + el_set(el, EL_REFRESH); +} + +Client::Client( QObject *parent ) + : QObject(parent), mNotifier(NULL), mInputThread(NULL) +{ +} + +Client::~Client() +{ + if (mInputThread) { + mInputThread->terminate(); + mInputThread->wait(1000); + delete mInputThread; + mInputThread = 0; + } +} + +bool Client::connectToServer() +{ + QString socketName = ::getenv("JSONDB_SOCKET"); + if (socketName.isEmpty()) { + mConnection = new QtAddOn::JsonDb::JsonDbClient(this); + } else { + mConnection = new QtAddOn::JsonDb::JsonDbClient(socketName, this); + } + + connect(mConnection, SIGNAL(disconnected()), this, SLOT(disconnected())); + connect(mConnection, SIGNAL(response(int,QVariant)), + this, SLOT(response(int,QVariant))); + connect(mConnection, SIGNAL(error(int,int,QString)), + this, SLOT(error(int,int,QString))); + connect(mConnection, SIGNAL(notified(QString,QVariant,QString)), + this, SLOT(notified(QString,QVariant,QString))); + + if (!mConnection->isConnected()) { + qCritical() << "Unable to connect to server"; + return false; + } + return true; +} + +void Client::interactiveMode() +{ + mInputThread = InputThread::instance(); + connect(mInputThread, SIGNAL(commandReceived(QString)), this, SLOT(processCommand(QString))); + connect(mInputThread, SIGNAL(finished()), QCoreApplication::instance(), SLOT(quit())); + mInputThread->start(); +} + +void Client::disconnected() +{ + qCritical() << "Lost connection to the server"; + QCoreApplication::exit(0); +} + +void Client::notified(const QString ¬ify_uuid, const QVariant &object, const QString &action) +{ + JsonWriter writer; + writer.setAutoFormatting(true); + QString buf = writer.toString(object); + + QString message = "Received notification: type " % action + % " for " % notify_uuid % " object:\n" % buf; + InputThread::print(message); + + if (!mInputThread) + QCoreApplication::exit(0); // Non-interactive mode just stops +} + +void Client::response(int id, const QVariant &msg) +{ + Q_UNUSED(id); + JsonWriter writer; + writer.setAutoFormatting(true); + QString buf = writer.toString(msg); + + QString message = "Received message: " % buf; + InputThread::print(message); + + mRequests.remove(id); + if (mRequests.isEmpty()) + emit requestsProcessed(); + + if (!mInputThread) + QCoreApplication::exit(0); // Non-interactive mode just stops +} + +void Client::error(int, int code, const QString &msg) +{ + QString message = "Received error " % QString().setNum(code) % ":" % msg; + InputThread::print(message); + + if (!mInputThread) + QCoreApplication::exit(0); // Non-interactive mode just stops +} + +void Client::usage() +{ + std::stringstream out; + out << "Valid commands:" << std::endl + << std::endl + << "Direct database commands - these take an explict object" << std::endl + << " create OBJECT" << std::endl + << " update OBJECT" << std::endl + << " remove OBJECT" << std::endl + << " remove QUERY" << std::endl + << " find QUERY" << std::endl + << " changesSince STATENUMBER [type1 type2 ...]" << std::endl + << std::endl + << "Convenience functions" << std::endl + << " query STRING [offset [limit]]" << std::endl + << " find {\"query\": STRING}" << std::endl + << " notify ACTIONS QUERY" << std::endl + << " create { \"_type\": \"notification\"," << std::endl + << " \"query\": QUERY," << std::endl + << " \"actions\": ACTIONS }" << std::endl + << " help" << std::endl + << " quit" << std::endl + << std::endl + << "ACTIONS: comma separated list. Valid values: create, update, remove" << std::endl + << "OBJECT: Valid JSON object" << std::endl + << "QUERY: Valid JSONQuery command" << std::endl + << std::endl + << "Sample commands: " << std::endl + << " create {\"_type\": \"duck\", \"name\": \"Fred\"}" << std::endl + << " query [?_type=\"duck\"]" << std::endl + << " notify create,remove [?_type=\"duck\"]" << std::endl; + + QString usageInfo = QString::fromStdString(out.str()); + InputThread::print(usageInfo); +} + +bool Client::processCommand(const QString &command) +{ + QString cmd = command.trimmed(); + QString rest; + + int space = command.indexOf(' '); + if (space > 0) { + cmd = command.left(space); + rest = command.mid(space+1).trimmed(); + } + + gDebug = true; + + if (cmd == "quit") { + exit(0); + } else if (cmd == "help") { + usage(); + } else if (cmd == "query") { + int offset = 0, limit = -1; + int idx = rest.lastIndexOf(']'); + if (idx != -1) { + QStringList list = rest.mid(idx+1).split(' '); + int i = 0; + for (; i < list.size(); ++i) { + if (!list.at(i).trimmed().isEmpty()) { + offset = list.at(i).toInt(); + break; + } + } + for (++i; i < list.size(); ++i) { + if (!list.at(i).trimmed().isEmpty()) { + limit = list.at(i).toInt(); + break; + } + } + rest.truncate(idx+1); + } + if (gDebug) + qDebug() << "Sending query:" << QVariant(rest); + mRequests << mConnection->query(rest, offset, limit); + } else if (cmd == "notify") { + int s = rest.indexOf(' '); + if (s <= 0) + return false; + QStringList alist = rest.left(s).split(QRegExp(","), QString::SkipEmptyParts); + QtAddOn::JsonDb::JsonDbClient::NotifyTypes actions; + foreach (const QString &s, alist) { + JsonDbClient::NotifyType type = JsonDbClient::NotifyType(0); + if (s == QLatin1String("create")) + type = JsonDbClient::NotifyCreate; + if (s == QLatin1String("remove")) + type = JsonDbClient::NotifyRemove; + if (s == QLatin1String("update")) + type = JsonDbClient::NotifyUpdate; + if (type == JsonDbClient::NotifyType(0)) { + InputThread::print("uknown notification type" % s); + return false; + } + actions |= type; + } + QString query = rest.mid(s+1).trimmed(); + if (gDebug) + qDebug() << "Creating notification:" << alist << ":" << query; + mRequests << mConnection->notify(actions, query); + } else if (cmd == "remove") { + rest = rest.trimmed(); + bool isquery = false; + int i = 0; + const int len = rest.length(); + if (i < len) { + if (rest.at(i++) == QLatin1Char('[')) { + while (i < len && rest.at(i) == QLatin1Char(' ')) ++i; + if (i < len && rest.at(i) == QLatin1Char('?')) + isquery = true; + } + } + if (isquery) { + // if not json format, then it is a query + if (gDebug) + qDebug() << "Sending remove for:" << rest; + mRequests << mConnection->remove(rest); + } else { + JsonReader parser; + bool ok = parser.parse(rest); + if (!ok) { + InputThread::print("Unable to parse: " % rest); + usage(); + return false; + } + QVariant arg = parser.result(); + if (gDebug) + qDebug() << "Sending remove:" << arg; + mRequests << mConnection->remove(QVariant(arg)); + } + } else if (cmd == "create" || cmd == "update" || cmd == "find" ) { + JsonReader parser; + bool ok = parser.parse(rest); + if (!ok) { + InputThread::print("Unable to parse: " % rest); + usage(); + return false; + } + QVariant arg = parser.result(); + if (gDebug) + qDebug() << "Sending" << cmd << ":" << arg; + int id = 0; + QMetaObject::invokeMethod(mConnection, cmd.toLatin1(), Q_RETURN_ARG(int, id), Q_ARG(QVariant, arg)); + mRequests << id; + } else if (cmd == "changesSince") { + int stateNumber = 0; + QStringList types; + QStringList args = rest.split(" "); + + if (args.isEmpty()) { + InputThread::print("Must specify the state number"); + usage(); + return false; + } + + stateNumber = args.takeFirst().trimmed().toInt(); + + if (!args.isEmpty()) + types = args; + + if (gDebug) + qDebug() << "Sending changesSince: " << stateNumber << "types: " << types; + + mRequests << mConnection->changesSince(stateNumber, types); + } else if (!cmd.isEmpty()) { + InputThread::print("Unrecognized command: " % cmd); + usage(); + return false; + } else { + return false; + } + + return true; +} + +bool Client::loadJsonFile(const QString &fileName) +{ + QFile file(fileName); + if (!file.open(QFile::ReadOnly)) { + if (gDebug) + qDebug() << "Couldn't load file" << fileName; + return false; + } + JsonReader parser; + bool ok = parser.parse(file.readAll()); + file.close(); + if (!ok) { + std::cout << "Unable to parse the content of the file" << qPrintable(fileName) << ":" + << qPrintable(parser.errorString()) << std::endl; + return false; + } + QVariant arg = parser.result(); + mRequests << mConnection->create(arg); + return true; +} diff --git a/tools/jsondb-client/client.h b/tools/jsondb-client/client.h new file mode 100644 index 00000000..1c2f839d --- /dev/null +++ b/tools/jsondb-client/client.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CLIENT_H +#define CLIENT_H + +#include <QObject> +#include <QThread> +#include <QStringList> +#include <QLocalSocket> +#include <QSocketNotifier> +#include <QFile> + +#include <histedit.h> + +#include "jsondb-client.h" + + + +class InputThread : public QThread { + Q_OBJECT +public: + static InputThread *instance(); + ~InputThread(); + void run(); + void async_print(const QString &); + static void print(const QString &); + static char const* prompt(EditLine *e); + static unsigned char console_tabkey(EditLine * el, int ch); +signals: + void commandReceived(QString); +private: + EditLine *el; + History *hist; + QString historyFile; + InputThread(QObject *parent = 0) : QThread(parent), el(0), hist(0) {} + static QString longestCommonPrefix(const QStringList &list); + static InputThread *threadInstance; + static const char *commands[]; +}; + +class Client : public QObject +{ + Q_OBJECT +public: + Client(QObject *parent = 0); + ~Client(); + + bool connectToServer(); + void interactiveMode(); + +public slots: + bool processCommand(const QString &); // true if we're waiting for a response + bool loadJsonFile(const QString &fileName); + +protected slots: + void disconnected(); + + void response(int, const QVariant &map); + void error(int id, int code, const QString &message); + void notified(const QString ¬ify_uuid, const QVariant &object, const QString &action); + +signals: + void requestsProcessed(); + +private: + void usage(); + + QSocketNotifier *mNotifier; + QFile *mInput; + QtAddOn::JsonDb::JsonDbClient *mConnection; + QSet<int> mRequests; + InputThread *mInputThread; +}; + + +#endif // CLIENT_H diff --git a/tools/jsondb-client/jsondb-client.pro b/tools/jsondb-client/jsondb-client.pro new file mode 100644 index 00000000..a1b1ef9a --- /dev/null +++ b/tools/jsondb-client/jsondb-client.pro @@ -0,0 +1,16 @@ +TARGET = jsondb-client +DESTDIR = $$QT.jsondb.bins + +target.path = $$[QT_INSTALL_BINS] +INSTALLS += target + +QT = core network declarative jsondb + +LIBS += -ledit -lcurses + +include(../../src/3rdparty/qjson/qjson.pri) + +mac:CONFIG -= app_bundle + +HEADERS += client.h +SOURCES += main.cpp client.cpp diff --git a/tools/jsondb-client/main.cpp b/tools/jsondb-client/main.cpp new file mode 100644 index 00000000..a6cc6482 --- /dev/null +++ b/tools/jsondb-client/main.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore> +#include <iostream> +#include "client.h" + +QString progname; +bool gDebug; + +/***************************************************************************/ + +using namespace std; + +static void usage() +{ + cout << "Usage: " << qPrintable(progname) << " [OPTIONS] [command]" << endl + << endl + << " -debug" << endl + << " -load file.json Load objects from a json file" << endl + << endl + << " where command is valid JsonDb command object" << endl; + exit(0); +} + + +int main(int argc, char * argv[]) +{ + QCoreApplication::setOrganizationName("Nokia"); + QCoreApplication::setOrganizationDomain("nrcc.noklab.com"); + QCoreApplication::setApplicationName("jclient"); + QCoreApplication::setApplicationVersion("1.0"); + + QCoreApplication app(argc, argv); + QStringList args = QCoreApplication::arguments(); + QString loadFile; + + progname = args.takeFirst(); + while (args.size()) { + QString arg = args.at(0); + if (!arg.startsWith("-")) + break; + args.removeFirst(); + if ( arg == "-help") + usage(); + else if ( arg == "-debug") + gDebug = true; + else if (arg == "-load") { + if (args.isEmpty()) { + cout << "Invalid argument " << qPrintable(arg) << endl; + usage(); + return 0; + } + loadFile = args.at(0); + args.removeFirst(); + } else { + cout << "Unknown argument " << qPrintable(arg) << endl; + usage(); + return 0; + } + } + + Client client; + if (!client.connectToServer()) + return 0; + + bool interactive = !args.size(); + if (!interactive) + QObject::connect(&client, SIGNAL(requestsProcessed()), &app, SLOT(quit())); + + if (!loadFile.isEmpty()) { + client.loadJsonFile(loadFile); + } else if (!args.size()) { + client.interactiveMode(); + } else { + if (!client.processCommand(args.join(" "))) + return 0; + } + return app.exec(); +} diff --git a/tools/tools.pro b/tools/tools.pro new file mode 100644 index 00000000..d6211f9a --- /dev/null +++ b/tools/tools.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS += jsondb-client adb-dump + |