I'm trying to establish connection with github server via POCO library, my code:
Poco::Net::initializeSSL();
Poco::Net::Context context(Poco::Net::Context::CLIENT_USE, "", "", "", Poco::Net::Context::VERIFY_RELAXED, 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:#STRENGTH");
URI uri("https://api.github.com/zen");
std::string path(uri.getPathAndQuery());
HTTPSClientSession client(uri.getHost(), uri.getPort(), &context);
HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
if (!client.connected())
{
int a{ 0 };//<<==ALWAYS END UP HERE, MEANING THAT client isn't connected
}
Does anybody know how to connect to that server, i.e. what steps are required in order to achieve that?
It is not connected because you did not send the request. Try:
client.sendRequest(req);
UPDATE: GitHub API requires the user agent header, otherwise you'll get 403. So, here's a fully functional example (certificate handler and root cert optional in this particular case, but good to have):
#include "Poco/StreamCopier.h"
#include "Poco/URI.h"
#include "Poco/Exception.h"
#include "Poco/SharedPtr.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/KeyConsoleHandler.h"
#include "Poco/Net/ConsoleCertificateHandler.h"
#include "Poco/Net/HTTPSClientSession.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include <memory>
#include <iostream>
using namespace Poco;
using namespace Poco::Net;
class SSLInitializer {
public:
SSLInitializer() { Poco::Net::initializeSSL(); }
~SSLInitializer() { Poco::Net::uninitializeSSL(); }
};
int main(int argc, char** argv)
{
SSLInitializer sslInitializer;
SharedPtr<InvalidCertificateHandler> ptrCert = new ConsoleCertificateHandler(false);
Context::Ptr ptrContext = new Context(Context::CLIENT_USE, "", "", "rootcert.pem", Context::VERIFY_STRICT, 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:#STRENGTH");
SSLManager::instance().initializeClient(0, ptrCert, ptrContext);
try
{
URI uri("https://api.github.com/zen");
HTTPSClientSession s(uri.getHost(), uri.getPort());
HTTPRequest request(HTTPRequest::HTTP_GET, uri.getPath());
request.set("user-agent", "Poco HTTPSClientSession");
s.sendRequest(request);
HTTPResponse response;
std::istream& rs = s.receiveResponse(response);
StreamCopier::copyStream(rs, std::cout);
std::cout << std::endl;
}
catch (Exception& ex)
{
std::cout << ex.displayText() << std::endl;
return 1;
}
return 0;
}
And here is the execution thereof:
$ gitget
Avoid administrative distraction.
Related
i am writing client server application using gsoap lib. the problem is that a have a heavy process function in my server.i want to when special client call this function, the server send message for this special client that "your answer is ready" when this client answer is ready. and its possible that multiple client call this function in same time.
is there any tool like asynchronAnswer in qt? and if not how can i handle it with qt or gsoap tools?
whats the true architect of handle this problems? using multi thread in client calling and wait for response in other thread or exactly call client by its ip in server or something better?
thanks,
You can try to use QWebSocket for this task. You have connected client list, if client send a request for "heavy process function", you are puting in thread pool, and sending replay to the specific client after calculations are done. In code it will be something like this:
server.h
#ifndef SERVER_H
#define SERVER_H
#include <QObject>
#include <QtWebSockets>
class Server : public QObject
{
Q_OBJECT
public:
explicit Server(QObject *parent = 0);
~Server();
signals:
void closed();
public slots:
private slots:
void onNewConnection();
void onMessage(QString message);
void onDisconnected();
private:
QWebSocketServer* m_pWebSocketServer;
QList<QWebSocket*> m_clients;
};
#endif // SERVER_H
server.cpp
#include <QThreadPool>
#include "server.h"
#include "heavytask.h"
Server::Server(QObject *parent) :
QObject(parent),
m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Server"), QWebSocketServer::NonSecureMode, this))
{
if (m_pWebSocketServer->listen(QHostAddress::Any, 4000)) {
connect(m_pWebSocketServer, &QWebSocketServer::newConnection, this, &Server::onNewConnection);
connect(m_pWebSocketServer, &QWebSocketServer::closed, this, &Server::closed);
}
}
void Server::onNewConnection()
{
QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
connect(pSocket, &QWebSocket::textMessageReceived, this, &Server::onMessage);
connect(pSocket, &QWebSocket::disconnected, this, &Server::onDisconnected);
m_clients << pSocket;
}
void Server::onMessage(QString message)
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
if (message == "Start heavy process function in your server, please") {
HeavyTask* ht = new HeavyTask(pClient);
QThreadPool::globalInstance()->start(ht);
}
}
void Server::onDisconnected()
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
if (pClient) {
m_clients.removeAll(pClient);
pClient->deleteLater();
}
}
Server::~Server()
{
m_pWebSocketServer->close();
qDeleteAll(m_clients.begin(), m_clients.end());
}
heavytask.h
#ifndef HEAVYTASK_H
#define HEAVYTASK_H
#include <QThreadPool>
#include <QRunnable>
#include <QWebSocket>
class HeavyTask : public QRunnable
{
public:
explicit HeavyTask(QWebSocket* client);
void run();
private:
QWebSocket* m_client;
};
#endif // HEAVYTASK_H
heavytask.cpp
#include "heavytask.h"
HeavyTask::HeavyTask(QWebSocket* client) : m_client(client)
{
}
void HeavyTask::run()
{
/*
Do your havy task;
*/
if (m_client != nullptr) {
if (m_client->isValid()) {
m_client->sendTextMessage("Your answer is ready!");
}
}
}
and main.cpp
#include <QCoreApplication>
#include "server.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Server server(&a);
QObject::connect(&server, &Server::closed, &a, &QCoreApplication::quit);
return a.exec();
}
Hope it'll be useful. (Not tasted at all, but compiling)
I try to send a message via dbus-send to this small example program.
But it is not received:
dbus-send --session --type=method_call / dbustester.test.slot_foo
The return code is 0 and not message is printed to the console.
Below is the source code.
main.cpp
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtDBus/QtDBus>
#include <Example.h>
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
Example *e = new Example();
e->setupDBus();
return app.exec();
}
Example.h
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtDBus/QtDBus>
class Example : public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "dbustester.test")
public:
Example(QObject* parent = NULL) :
QObject(parent)
{
}
void setupDBus()
{
QDBusConnection session = QDBusConnection::sessionBus();
if (!session.isConnected())
{
qFatal("Cannot connect to the D-Bus session bus.");
return;
}
session.connect("", "/", "dbustester.test", "slot_foo", this, SLOT(slot_foo(void)));
if(!session.registerObject("/", this, QDBusConnection::ExportScriptableContents)) {
qFatal("Cannot registerObject.");
return;
}
if(!session.registerService("dbustester.test")) {
qFatal("Cannot registerObject.");
return;
}
}
public slots:
Q_SCRIPTABLE void slot_foo()
{
qDebug() << "request received";
}
};
Build:
qmake -project
echo "CONFIG += qdbus" >> *.pro
qmake
I've found the answer while writing the question, but I wrote the question anyway. Some people might find it useful.
dbus-send --session --dest=dbustester.test --type=method_call / dbustester.test.slot_foo
I forgot the --dest argument. :>
I'm trying to do a simple GET request (with modified User-Agent), return response to QML and do a JSON parsing.
Actually it only returns page content when loading is complete but it doesn't return it to QML.
Sorry for the noob question. I'm new to this language and I'm trying to learn it :)
Here's my code:
Home.qml
function getRequest() {
[...]
console.log('Request...')
var jsonResult = JSON.parse(connectNet.connectUrl("http://myURL.com/index.php").toString())
lbOutput.text = jsonResult.predictions[0].description.toString()
}
}
connectnet.cpp
#include "connectnet.h"
#include "stdio.h"
#include <QDebug>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QUrl>
connectNet::connectNet(QObject *parent) : QObject(parent)
{
}
void connectNet::connectUrl(QString url)
{
QNetworkAccessManager *manager = new QNetworkAccessManager();
QNetworkRequest request;
QNetworkReply *reply = NULL;
request.setUrl(QUrl(url));
request.setRawHeader( "User-Agent" , "FAKE USER AGENT HERE" );
reply = manager->get(request);
connect(manager, SIGNAL(finished(QNetworkReply*)), this,
SLOT(replyFinished(QNetworkReply*)));
}
QString connectNet::replyFinished(QNetworkReply *reply)
{
return reply->readAll();
}
appname.cpp
#ifdef QT_QML_DEBUG
#include <QtQuick>
#endif
#include <sailfishapp.h>
#include "connectnet.h"
int main(int argc, char *argv[])
{
//INIT SETTINGS
QGuiApplication *app = SailfishApp::application(argc, argv);
QQuickView *view = SailfishApp::createView();
connectNet ConnectNet;
view->rootContext()->setContextProperty("connectNet", &ConnectNet);
view->setSource(SailfishApp::pathTo("qml/APPNAME.qml"));
view->showFullScreen();
app->exec();
}
Hope I've well explained what I'm looking for. Thanks for your help.
====================================================
EDIT 20/08/2015: added updated connectnet.h
#ifndef CONNECTNET_H
#define CONNECTNET_H
#include <QObject>
#include <QNetworkReply>
#include <QDebug>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QUrl>
class ConnectNet : public QObject
{
Q_OBJECT
QNetworkAccessManager m_manager;
public:
ConnectNet(QObject * parent = 0) : QObject(parent) {
connect(&m_manager, &QNetworkAccessManager::finished,
[this](QNetworkReply * reply) {
if (reply->error() == QNetworkReply::NoError)
emit replyAvailable(QString::fromUtf8(reply->readAll()));
});
}
signals:
void replyAvailable(const QString & reply);
public slots:
void sendRequest(const QString url) {
QNetworkRequest request;
request.setUrl(QUrl(url));
request.setRawHeader("User-Agent", "MyLittleAgent");
m_manager.get(request);
}
};
#endif // CONNECTNET_H
this part of code gives a lot of errors :( (screenshot below)
connect(&m_manager, &QNetworkAccessManager::finished,
[this](QNetworkReply * reply) {
if (reply->error() == QNetworkReply::NoError)
emit replyAvailable(QString::fromUtf8(reply->readAll()));
});
compiling erros: http://i.stack.imgur.com/30vWn.jpg
Your problem is that you think synchronously. The connectUrl cannot return a value (and it doesn't), since when it runs the result is not available. What you must do, instead, is for the ConnectNet class to emit a signal when the data is available.
It'd be a horrible idea if you tried to make a synchronous wrapper that did return the value: the QML engine would be stuck as long as it took for the result to be received. You could freeze your application by pulling the network cable at the right moment, or if the server was down. Users hate that, and it's a horrible antipattern that must be expediently eliminated and discouraged.
Here's how your ConnectNet (please, not connectNet, lowercase names are for members!) class could look. Note that the QNetworkAccessManager instance doesn't need to be a pointer.
class ConnectNet : public QObject {
Q_OBJECT
QNetworkAccessManager m_manager;
public:
ConnectNet(QObject * parent = 0) : QObject(parent) {
connect(&m_manager, &QNetworkAccessManager::finished,
[this](QNetworkReply * reply) {
if (reply->error() == QNetworkReply::NoError)
emit replyAvailable(QString::fromUtf8(reply->readAll()));
});
}
Q_SLOT void sendRequest(const QString & url) {
auto request = QNetworkRequest(QUrl(url));
request.setRawHeader("User-Agent", "MyLittleAgent");
m_manager.get(request);
}
Q_SIGNAL void replyAvailable(const QString & reply);
};
Since connectNet instance instance is exposed as a property in the global QML context, you can connect to its signals as follows:
function getRequest() {
connectNet.sendRequest("http://myURL.com/index.php")
}
function resultHandler(result) {
var jsonResult = JSON.parse(result.toString())
lbOutput.text = jsonResult.predictions[0].description.toString()
}
Rectangle { // or any other item
Component.onCompleted: {
connectNet.replyAvailable.connect(resultHandler)
}
...
}
I am working on building a GUI around a console application. I would like to be able to click a button to run the console app and show the console output inside of the GUI itself. How might I accomplish this? I am working in Linux.
You could also try QProcess. It provides a Qt interface to launching external processes, reading their I/O and waiting, or not, on their completion.
For your purpose, it sounds like you want the process to run asynchronously, so code might look like :
myprocessstarter.h :
#include <QObject>
#include <QProcess>
#include <QDebug>
class MyProcessStarter : public QObject
{
Q_OBJECT
public:
MyProcessStarter() : QObject() {};
void StartProcess();
private slots:
void readStandardOutput();
private:
QProcess *myProcess;
};
main.cpp:
#include "myprocessstarter.h"
void MyProcessStarter::StartProcess()
{
QString program = "dir";
QStringList arguments;
// Add any arguments you want to be passed
myProcess = new QProcess(this);
connect(myProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput()));
myProcess->start(program, arguments);
}
void MyProcessStarter::readStandardOutput()
{
QByteArray processOutput;
processOutput = myProcess->readAllStandardOutput();
qDebug() << "Output was " << QString(processOutput);
}
void main(int argc, char** argv)
{
MyProcessStarter s;
s.StartProcess();
}
I wanted to do something similar in one of my applications. I redirected all output from the standard stream (cout) to my console window. To periodically read out the stream contents I use a timer loop. Works fine for me.
StdRedirector.cpp
#include "StdRedirector.h"
QMutex coutMutex;
void outcallback(const char* ptr, std::streamsize count, void* bufferString)
{
string *b = (string *) bufferString;
string t;
for (int i=0; i < count; i++)
{
if (ptr[i] == '\n')
{
t = t + "\n";
} else {
t = t + ptr[i];
}
}
coutMutex.lock();
*b = *b + t;
coutMutex.unlock();
}
void ConsoleWindow::updateTimer(void)
{
coutMutex.lock();
if (bufferString.size() > 0)
{
consoleBox->insertPlainText(QString(bufferString.c_str()));
bufferString.clear();
QScrollBar *sb = consoleBox->verticalScrollBar();
sb->setValue(sb->maximum());
}
coutMutex.unlock();
}
ConsoleWindow::ConsoleWindow(QWidget *parent) : QWidget(parent)
{
consoleBox = new QTextEdit(this);
consoleBox->setReadOnly(true);
stdRedirector = new StdRedirector<>(std::cout, outcallback, &bufferString);
QVBoxLayout *vb = new QVBoxLayout();
vb->addWidget(consoleBox);
vb->setMargin(0);
vb->setSpacing(0);
setLayout(vb);
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(updateTimer()));
timer->start(100);
}
ConsoleWindow::~ConsoleWindow()
{
delete stdRedirector;
}
StdRedirector.h
#ifndef STD_REDIRECTOR
#define STD_REDIRECTOR
#include <QWidget>
#include <QTextEdit>
#include <QString>
#include <QVBoxLayout>
#include <QTimer.h>
#include <QMutex>
#include <QScrollBar>
#include <iostream>
#include <string>
using namespace std;
template<class Elem = char, class Tr = std::char_traits<Elem>>
class StdRedirector : public std::basic_streambuf<Elem, Tr>
{
typedef void (*pfncb) ( const Elem*, std::streamsize _Count, void* pUsrData );
public:
StdRedirector(std::ostream& a_Stream, pfncb a_Cb, void* a_pUsrData) :
m_Stream(a_Stream),
m_pCbFunc(a_Cb),
m_pUserData(a_pUsrData)
{
m_pBuf = m_Stream.rdbuf(this);
}
~StdRedirector()
{
m_Stream.rdbuf(m_pBuf);
}
std::streamsize xsputn(const Elem* _Ptr, std::streamsize _Count)
{
m_pCbFunc(_Ptr, _Count, m_pUserData);
return _Count;
}
typename Tr::int_type overflow(typename Tr::int_type v)
{
Elem ch = Tr::to_char_type(v);
m_pCbFunc(&ch, 1, m_pUserData);
return Tr::not_eof(v);
}
protected:
std::basic_ostream<Elem, Tr>& m_Stream;
std::streambuf* m_pBuf;
pfncb m_pCbFunc;
void* m_pUserData;
};
class ConsoleWindow : public QWidget
{
Q_OBJECT
public:
ConsoleWindow(QWidget *parent = 0);
~ConsoleWindow();
public slots:
void updateTimer(void);
public:
QTextEdit *consoleBox;
StdRedirector<> *stdRedirector;
string bufferString;
};
#endif
The StdRedirector class is based on code from this forum post: http://www.qtforum.org/article/24554/displaying-std-cout-in-a-text-box.html
Take a look at the popen() function, it might do what you need.
Then you could pass the FILE * to a QTextStream and work in Qt style with it.
I suggest, rather than showing stdout in GUI, having own console output, which essentially means all messages you want to show to users you are sending to your own output.
This way you can have debug messages and such still available from console, wtih potential errors with connections and whatever that can happen and have fully controlled console output in GUI application. Of course this output can also be outputted to stdout so it is visible in console, but it also allows you to append a prefixs like WARNING LOG NOTICE NO_THIS_WENT_WRONG or whatever you want to show to users as your console entry.
Newbie having trouble creating a database here.
Following code compiles ok, but no database is created and I can't find any sqlite file.
#include "makeDB.h"
#include <iostream>
#include <QString>
#include <QtSql>
void makeDB(QString dbName) {
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setHostName("localHost");
db.setDatabaseName(dbName);
db.setUserName("logger");
db.setPassword("logger");
}
#include <QtGui/QApplication>
#include <QString>
#include <QtSql>
#include "mainwindow.h"
#include "makeDB.h"
#include "createTable.h"
#include "ui_mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
makeDB("log1");
createTable();
return a.exec();
}
What am I doing wrong here? Thanks!
Waynew
Edit/Delete Message
We can't see what you createTable() does, the code that you have never calls db.open() most of the QT database and SQL calls return bool for success and there is a lastError() function for both the QSqlDatabase and the QSqlQuery calls. Check those if appropriate calls, i.e. db.open() and query.exec() return false.
e.g.
bool makeDB(QString dbName) {
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setHostName("localHost");
db.setDatabaseName(dbName);
bool result = db.open();
if (result)
{
//do more processing
}
else
{
qDebug() << db.lastError().text()
}
return result;
}
Also I don't think that SqlLite supports any kind of authentication this seems to indicate that you can secure your db by licensing an extension from the creators of SqlLite.
As to the actual table creation there should be some SQL that is executed that looks like this:
CREATE TABLE (x int, y varchar);
depending on the columns that you actually want.
This is the respective documentation.