summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/CMakeLists.txt1
-rw-r--r--common/log.cpp70
-rw-r--r--common/log.h17
-rw-r--r--common/resourceaccess.cpp5
-rw-r--r--synchronizer/listener.cpp62
-rw-r--r--synchronizer/listener.h1
-rw-r--r--synchronizer/main.cpp14
7 files changed, 135 insertions, 35 deletions
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 429bad7..656f987 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -23,6 +23,7 @@ else (STORAGE_unqlite)
23endif (STORAGE_unqlite) 23endif (STORAGE_unqlite)
24 24
25set(command_SRCS 25set(command_SRCS
26 log.cpp
26 entitybuffer.cpp 27 entitybuffer.cpp
27 clientapi.cpp 28 clientapi.cpp
28 commands.cpp 29 commands.cpp
diff --git a/common/log.cpp b/common/log.cpp
new file mode 100644
index 0000000..1d93404
--- /dev/null
+++ b/common/log.cpp
@@ -0,0 +1,70 @@
1#include "log.h"
2
3#include <QString>
4#include <QIODevice>
5#include <QCoreApplication>
6#include <iostream>
7#include <unistd.h>
8
9class DebugStream: public QIODevice
10{
11public:
12 QString m_location;
13 DebugStream()
14 : QIODevice()
15 {
16 open(WriteOnly);
17 }
18 virtual ~DebugStream(){};
19
20 bool isSequential() const { return true; }
21 qint64 readData(char *, qint64) { return 0; /* eof */ }
22 qint64 readLineData(char *, qint64) { return 0; /* eof */ }
23 qint64 writeData(const char *data, qint64 len)
24 {
25 const QByteArray buf = QByteArray::fromRawData(data, len);
26 // if (!qgetenv("IMAP_TRACE").isEmpty()) {
27 // qt_message_output(QtDebugMsg, buf.trimmed().constData());
28 std::cout << buf.trimmed().constData() << std::endl;
29 // }
30 return len;
31 }
32private:
33 Q_DISABLE_COPY(DebugStream)
34};
35
36QDebug debugStream(DebugLevel debugLevel, int line, const char* file, const char* function)
37{
38 static DebugStream stream;
39 QDebug debug(&stream);
40
41 static QByteArray programName;
42 if (programName.isEmpty()) {
43 if (QCoreApplication::instance())
44 programName = QCoreApplication::instance()->applicationName().toLocal8Bit();
45 else
46 programName = "<unknown program name>";
47 }
48
49 QString prefix;
50 switch (debugLevel) {
51 case DebugLevel::Trace:
52 prefix = "Trace:";
53 break;
54 case DebugLevel::Log:
55 prefix = "Log:";
56 break;
57 case DebugLevel::Warning:
58 prefix = "Warning:";
59 break;
60 case DebugLevel::Error:
61 prefix = "Error:";
62 break;
63 default:
64 break;
65 };
66
67 debug << prefix + QString(" %1(%2) %3:").arg(QString::fromLatin1(programName)).arg(unsigned(getpid())).arg(function) /* << file << ":" << line */;
68
69 return debug;
70}
diff --git a/common/log.h b/common/log.h
new file mode 100644
index 0000000..8d3dc75
--- /dev/null
+++ b/common/log.h
@@ -0,0 +1,17 @@
1#pragma once
2
3#include <QDebug>
4
5enum DebugLevel {
6 Trace,
7 Log,
8 Warning,
9 Error
10};
11
12QDebug debugStream(DebugLevel debugLevel, int line, const char* file, const char* function);
13
14#define Trace() debugStream(DebugLevel::Trace, __LINE__, __FILE__, Q_FUNC_INFO)
15#define Log() debugStream(DebugLevel::Log, __LINE__, __FILE__, Q_FUNC_INFO)
16#define Warning() debugStream(DebugLevel::Warning, __LINE__, __FILE__, Q_FUNC_INFO)
17#define Error() debugStream(DebugLevel::Error, __LINE__, __FILE__, Q_FUNC_INFO)
diff --git a/common/resourceaccess.cpp b/common/resourceaccess.cpp
index ffe716b..59cbece 100644
--- a/common/resourceaccess.cpp
+++ b/common/resourceaccess.cpp
@@ -20,12 +20,12 @@
20 20
21#include "resourceaccess.h" 21#include "resourceaccess.h"
22 22
23#include "common/console.h"
24#include "common/commands.h" 23#include "common/commands.h"
25#include "common/commandcompletion_generated.h" 24#include "common/commandcompletion_generated.h"
26#include "common/handshake_generated.h" 25#include "common/handshake_generated.h"
27#include "common/revisionupdate_generated.h" 26#include "common/revisionupdate_generated.h"
28#include "common/synchronize_generated.h" 27#include "common/synchronize_generated.h"
28#include "log.h"
29 29
30#include <QCoreApplication> 30#include <QCoreApplication>
31#include <QDebug> 31#include <QDebug>
@@ -343,8 +343,7 @@ void ResourceAccess::callCallbacks(int id)
343 343
344void ResourceAccess::log(const QString &message) 344void ResourceAccess::log(const QString &message)
345{ 345{
346 qDebug() << d->resourceName + ": " + message; 346 Log() << d->resourceName + ": " + message;
347 // Console::main()->log(d->resourceName + ": " + message);
348} 347}
349 348
350} 349}
diff --git a/synchronizer/listener.cpp b/synchronizer/listener.cpp
index d191bb8..2bc6be0 100644
--- a/synchronizer/listener.cpp
+++ b/synchronizer/listener.cpp
@@ -23,6 +23,7 @@
23#include "common/console.h" 23#include "common/console.h"
24#include "common/commands.h" 24#include "common/commands.h"
25#include "common/resource.h" 25#include "common/resource.h"
26#include "common/log.h"
26 27
27// commands 28// commands
28#include "common/commandcompletion_generated.h" 29#include "common/commandcompletion_generated.h"
@@ -46,18 +47,18 @@ Listener::Listener(const QString &resourceName, QObject *parent)
46 this, &Listener::refreshRevision); 47 this, &Listener::refreshRevision);
47 connect(m_server, &QLocalServer::newConnection, 48 connect(m_server, &QLocalServer::newConnection,
48 this, &Listener::acceptConnection); 49 this, &Listener::acceptConnection);
49 log(QString("Trying to open %1").arg(resourceName)); 50 Log() << QString("Trying to open %1").arg(resourceName);
50 if (!m_server->listen(resourceName)) { 51 if (!m_server->listen(resourceName)) {
51 // FIXME: multiple starts need to be handled here 52 // FIXME: multiple starts need to be handled here
52 m_server->removeServer(resourceName); 53 m_server->removeServer(resourceName);
53 if (!m_server->listen(resourceName)) { 54 if (!m_server->listen(resourceName)) {
54 log("Utter failure to start server"); 55 Warning() << "Utter failure to start server";
55 exit(-1); 56 exit(-1);
56 } 57 }
57 } 58 }
58 59
59 if (m_server->isListening()) { 60 if (m_server->isListening()) {
60 log(QString("Listening on %1").arg(m_server->serverName())); 61 Log() << QString("Listening on %1").arg(m_server->serverName());
61 } 62 }
62 63
63 m_checkConnectionsTimer = new QTimer; 64 m_checkConnectionsTimer = new QTimer;
@@ -65,7 +66,7 @@ Listener::Listener(const QString &resourceName, QObject *parent)
65 m_checkConnectionsTimer->setInterval(1000); 66 m_checkConnectionsTimer->setInterval(1000);
66 connect(m_checkConnectionsTimer, &QTimer::timeout, [this]() { 67 connect(m_checkConnectionsTimer, &QTimer::timeout, [this]() {
67 if (m_connections.isEmpty()) { 68 if (m_connections.isEmpty()) {
68 log(QString("No connections, shutting down.")); 69 Log() << QString("No connections, shutting down.");
69 m_server->close(); 70 m_server->close();
70 emit noClients(); 71 emit noClients();
71 } 72 }
@@ -98,14 +99,14 @@ void Listener::closeAllConnections()
98 99
99void Listener::acceptConnection() 100void Listener::acceptConnection()
100{ 101{
101 log(QString("Accepting connection")); 102 Log() << QString("Accepting connection");
102 QLocalSocket *socket = m_server->nextPendingConnection(); 103 QLocalSocket *socket = m_server->nextPendingConnection();
103 104
104 if (!socket) { 105 if (!socket) {
105 return; 106 return;
106 } 107 }
107 108
108 log("Got a connection"); 109 Log() << "Got a connection";
109 Client client("Unknown Client", socket); 110 Client client("Unknown Client", socket);
110 connect(socket, &QIODevice::readyRead, 111 connect(socket, &QIODevice::readyRead,
111 this, &Listener::readFromSocket); 112 this, &Listener::readFromSocket);
@@ -123,16 +124,20 @@ void Listener::clientDropped()
123 return; 124 return;
124 } 125 }
125 126
126 log("Dropping connection..."); 127 bool dropped = false;
127 QMutableVectorIterator<Client> it(m_connections); 128 QMutableVectorIterator<Client> it(m_connections);
128 while (it.hasNext()) { 129 while (it.hasNext()) {
129 const Client &client = it.next(); 130 const Client &client = it.next();
130 if (client.socket == socket) { 131 if (client.socket == socket) {
131 log(QString(" dropped... %1").arg(client.name)); 132 dropped = true;
133 Log() << QString("Dropped connection: %1").arg(client.name) << socket;
132 it.remove(); 134 it.remove();
133 break; 135 break;
134 } 136 }
135 } 137 }
138 if (!dropped) {
139 Warning() << "Failed to find connection for disconnected socket: " << socket;
140 }
136 141
137 checkConnections(); 142 checkConnections();
138} 143}
@@ -149,7 +154,7 @@ void Listener::readFromSocket()
149 return; 154 return;
150 } 155 }
151 156
152 log("Reading from socket..."); 157 Log() << "Reading from socket...";
153 for (Client &client: m_connections) { 158 for (Client &client: m_connections) {
154 if (client.socket == socket) { 159 if (client.socket == socket) {
155 client.commandBuffer += socket->readAll(); 160 client.commandBuffer += socket->readAll();
@@ -193,7 +198,7 @@ void Listener::processCommand(int commandId, uint messageId, Client &client, uin
193 client.name = buffer->name()->c_str(); 198 client.name = buffer->name()->c_str();
194 sendCurrentRevision(client); 199 sendCurrentRevision(client);
195 } else { 200 } else {
196 qWarning() << "received invalid command"; 201 Warning() << "received invalid command";
197 } 202 }
198 break; 203 break;
199 } 204 }
@@ -201,10 +206,10 @@ void Listener::processCommand(int commandId, uint messageId, Client &client, uin
201 flatbuffers::Verifier verifier((const uint8_t *)client.commandBuffer.constData(), size); 206 flatbuffers::Verifier verifier((const uint8_t *)client.commandBuffer.constData(), size);
202 if (Akonadi2::VerifySynchronizeBuffer(verifier)) { 207 if (Akonadi2::VerifySynchronizeBuffer(verifier)) {
203 auto buffer = Akonadi2::GetSynchronize(client.commandBuffer.constData()); 208 auto buffer = Akonadi2::GetSynchronize(client.commandBuffer.constData());
204 log(QString("\tSynchronize request (id %1) from %2").arg(messageId).arg(client.name)); 209 Log() << QString("\tSynchronize request (id %1) from %2").arg(messageId).arg(client.name);
205 loadResource(); 210 loadResource();
206 if (!m_resource) { 211 if (!m_resource) {
207 qWarning() << "No resource loaded"; 212 Warning() << "No resource loaded";
208 break; 213 break;
209 } 214 }
210 //TODO a more elegant composition of jobs should be possible 215 //TODO a more elegant composition of jobs should be possible
@@ -229,7 +234,7 @@ void Listener::processCommand(int commandId, uint messageId, Client &client, uin
229 } 234 }
230 return; 235 return;
231 } else { 236 } else {
232 qWarning() << "received invalid command"; 237 Warning() << "received invalid command";
233 } 238 }
234 break; 239 break;
235 } 240 }
@@ -237,14 +242,14 @@ void Listener::processCommand(int commandId, uint messageId, Client &client, uin
237 case Akonadi2::Commands::DeleteEntityCommand: 242 case Akonadi2::Commands::DeleteEntityCommand:
238 case Akonadi2::Commands::ModifyEntityCommand: 243 case Akonadi2::Commands::ModifyEntityCommand:
239 case Akonadi2::Commands::CreateEntityCommand: 244 case Akonadi2::Commands::CreateEntityCommand:
240 log(QString("\tCommand id %1 of type %2 from %3").arg(messageId).arg(commandId).arg(client.name)); 245 Log() << QString("\tCommand id %1 of type %2 from %3").arg(messageId).arg(commandId).arg(client.name);
241 loadResource(); 246 loadResource();
242 if (m_resource) { 247 if (m_resource) {
243 m_resource->processCommand(commandId, client.commandBuffer, size, m_pipeline); 248 m_resource->processCommand(commandId, client.commandBuffer, size, m_pipeline);
244 } 249 }
245 break; 250 break;
246 case Akonadi2::Commands::ShutdownCommand: 251 case Akonadi2::Commands::ShutdownCommand:
247 log(QString("\tReceived shutdown command from %1").arg(client.name)); 252 Log() << QString("\tReceived shutdown command from %1").arg(client.name);
248 callback(); 253 callback();
249 m_server->close(); 254 m_server->close();
250 emit noClients(); 255 emit noClients();
@@ -279,10 +284,15 @@ bool Listener::processClientBuffer(Client &client)
279 if (size <= uint(client.commandBuffer.size() - headerSize)) { 284 if (size <= uint(client.commandBuffer.size() - headerSize)) {
280 client.commandBuffer.remove(0, headerSize); 285 client.commandBuffer.remove(0, headerSize);
281 286
282 processCommand(commandId, messageId, client, size, [this, messageId, commandId, &client]() { 287 auto socket = QPointer<QLocalSocket>(client.socket);
283 log(QString("\tCompleted command messageid %1 of type %2 from %3").arg(messageId).arg(commandId).arg(client.name)); 288 auto clientName = client.name;
284 //FIXME, client needs to become a shared pointer and not a reference, or we have to search through m_connections everytime. 289 processCommand(commandId, messageId, client, size, [this, messageId, commandId, socket, clientName]() {
285 sendCommandCompleted(client, messageId); 290 Log() << QString("\tCompleted command messageid %1 of type %2 from %3").arg(messageId).arg(commandId).arg(clientName);
291 if (socket) {
292 sendCommandCompleted(socket.data(), messageId);
293 } else {
294 Log() << QString("Socket became invalid before we could send a response. client: %1").arg(clientName);
295 }
286 }); 296 });
287 client.commandBuffer.remove(0, size); 297 client.commandBuffer.remove(0, size);
288 298
@@ -346,21 +356,15 @@ void Listener::loadResource()
346 Akonadi2::ResourceFactory *resourceFactory = Akonadi2::ResourceFactory::load(m_resourceName); 356 Akonadi2::ResourceFactory *resourceFactory = Akonadi2::ResourceFactory::load(m_resourceName);
347 if (resourceFactory) { 357 if (resourceFactory) {
348 m_resource = resourceFactory->createResource(); 358 m_resource = resourceFactory->createResource();
349 log(QString("Resource factory: %1").arg((qlonglong)resourceFactory)); 359 Log() << QString("Resource factory: %1").arg((qlonglong)resourceFactory);
350 log(QString("\tResource: %1").arg((qlonglong)m_resource)); 360 Log() << QString("\tResource: %1").arg((qlonglong)m_resource);
351 //TODO: this doesn't really list all the facades .. fix 361 //TODO: this doesn't really list all the facades .. fix
352 log(QString("\tFacades: %1").arg(Akonadi2::FacadeFactory::instance().getFacade<Akonadi2::Domain::Event>(m_resourceName)->type())); 362 Log() << QString("\tFacades: %1").arg(Akonadi2::FacadeFactory::instance().getFacade<Akonadi2::Domain::Event>(m_resourceName)->type());
353 m_resource->configurePipeline(m_pipeline); 363 m_resource->configurePipeline(m_pipeline);
354 } else { 364 } else {
355 log(QString("Failed to load resource %1").arg(m_resourceName)); 365 Warning() << QString("Failed to load resource %1").arg(m_resourceName);
356 } 366 }
357 //TODO: on failure ... what? 367 //TODO: on failure ... what?
358 //Enter broken state? 368 //Enter broken state?
359} 369}
360 370
361void Listener::log(const QString &message)
362{
363 qDebug() << "Listener: " << message;
364 // Akonadi2::Console::main()->log("Listener: " + message);
365}
366
diff --git a/synchronizer/listener.h b/synchronizer/listener.h
index f1241c7..ee73766 100644
--- a/synchronizer/listener.h
+++ b/synchronizer/listener.h
@@ -82,7 +82,6 @@ private:
82 void sendCommandCompleted(Client &client, uint messageId); 82 void sendCommandCompleted(Client &client, uint messageId);
83 void updateClientsWithRevision(); 83 void updateClientsWithRevision();
84 void loadResource(); 84 void loadResource();
85 void log(const QString &);
86 85
87 QLocalServer *m_server; 86 QLocalServer *m_server;
88 QVector<Client> m_connections; 87 QVector<Client> m_connections;
diff --git a/synchronizer/main.cpp b/synchronizer/main.cpp
index 86e1497..587f96a 100644
--- a/synchronizer/main.cpp
+++ b/synchronizer/main.cpp
@@ -19,15 +19,25 @@
19 19
20#include <QApplication> 20#include <QApplication>
21 21
22#include "common/console.h" 22#include <signal.h>
23
23#include "listener.h" 24#include "listener.h"
25#include "log.h"
26
27void crashHandler(int sig) {
28 std::fprintf(stderr, "Error: signal %d\n", sig);
29 std::system("exec xterm -e gdb -p \"$PPID\"");
30 std::abort();
31}
24 32
25int main(int argc, char *argv[]) 33int main(int argc, char *argv[])
26{ 34{
35 //For crashes
36 signal(SIGSEGV, crashHandler);
27 QApplication app(argc, argv); 37 QApplication app(argc, argv);
28 38
29 if (argc < 2) { 39 if (argc < 2) {
30 qWarning() << "Not enough args passed, no resource loaded."; 40 Warning() << "Not enough args passed, no resource loaded.";
31 return app.exec(); 41 return app.exec();
32 } 42 }
33 43