ZeroMQ sockets block - c++

I just can't understand what i did. How it works? It works just by half, but there is identical pieces of code(almost).
I have client-server application. It sends any requests, and getting response, either list, that i will transform to vector, or string that contains HTML code. So, I will try to explain, but you are welcome to ask as much questions as you want.
1) I request file from server, by sending command "2" and path. Here is code
void Connection::requestFile(string path)
{
//string cookedPath = "./" + path;
string reply = this->sendCommand("2\n" + path);
vector<string> response = this->divideString(reply);
// set as files list we got. First is a helper, so we will not add it to files list.
if (response[0] == "directories") {
// remove "directories" entry so it will not be listed then
response.erase(response.begin());
this->files = response;
this->displayHtml = false;
} else {
//else server sent string with html
this->html = reply;
this->displayHtml = true;
}
}
displayHtml here is kinda switch that will help to determine what to do.
So in this method i've used sendCommand() method, which by my opinion is origin of all troubles.
Here it comes
string Connection::sendCommand(std::string command)
{
// send command
zmq::message_t request(command.length());
memcpy (request.data(), command.c_str(), command.length());
Connection::socket.send(request);
// get reply
zmq::message_t reply;
Connection::socket.recv(&reply);
// make string out of reply
std::string rpl = std::string(static_cast<char*>(reply.data()), reply.size());
return rpl;
}
Sorry about this formatting.
Then i use these methods here
void MainWindow::on_listWidget_itemDoubleClicked(QListWidgetItem *item)
{
// set our current folder to ./folder/ + selected file
connection->currentPath = connection->currentPath + item->text().toStdString();
// update file list. as argument we give path we just got
// std::cout << connection->currentPath << endl;
ui->listWidget->clear();
connection->requestFile(connection->currentPath);
if (connection->displayHtml == true) {
// webview->updateHtml(connection->html);
cout << "html";
} else {
this->updateFilesList(connection->files);
cout << "fileslist";
}
}
This method will be called when i double click on item in Qt widget list.
Say i've double clicked on item. It partially works fine, but it isnt prints it.
But if i close application, it prints.
So i guess problem is in blocking on 'recv' zmq function, but why it works for a half then? Maybe rewrite it anyhow? Thanks.

Related

Multiple key presses detected on SFML, can't solve it in any other way and works differently on different machines

this is my first post here.
I am trying to solve a problem I am having with my SFML project where I am using multiple clients, that communicate through texts that can be typed in the rendered window and then sent to the other sockets using a selector.
My problem is that everytime i press one button of the keyboard, the window detects like 3 or 4, and if I try it on another machine, the behaviour changes.
I tried almost every solution, including the setKeyRepeatEnabled(false);
This is the update function
void Client::Update(Input* input,sf::Event& Ev, sf::Font& font, sf::RenderWindow& window)
{
if (input->isKeyDown(sf::Keyboard::Return))
{
sf::Packet packet;
packet << id + ": " + text;
socket.send(packet);
sf::Text displayText(text, font, 20);
displayText.setFillColor(sf::Color::Red);
chat.push_back(displayText);
text = "";
input->setKeyUp(sf::Keyboard::Return);
}
else if (input->isKeyDown(sf::Keyboard::Backspace))
{
if (text.size() > 0)
text.pop_back();
}
else if (input->isKeyDown(sf::Keyboard::Space))
{
text += ' ';
}
else if (Ev.type == sf::Event::TextEntered)
{
text += Ev.text.unicode;
return;
}
//sf::Event::TextEntered
//text += Ev.text.unicode;
}
This is the render one.
void Client::Render(sf::Font& font, sf::RenderWindow& window)
{
sf::Packet packet;
socket.receive(packet);
std::string temptext;
if (packet >> temptext)
{
sf::Text displayText(temptext, font, 20);
displayText.setFillColor(sf::Color::Blue);
chat.push_back(displayText);
}
int i = 0;
for (i; i < chat.size(); i++)
{
chat[i].setPosition(0, i * 20);
window.draw(chat[i]);
}
sf::Text drawText(text, font, 20);
drawText.setFillColor(sf::Color::Red);
drawText.setPosition(0, i * 20);
window.draw(drawText);
}
I don't recognize the isKeyDown function as part of SFML, so I assume you either is something you implemented or is part of a previous version of SFML (being the current 2.5.1).
There are three ways to detect input from keyboard in SFML.
sf::Keyboard::isKeyPressed: looks like this is the one you are using. It will be true every cycle that the key is pressed. You definetly don't want this. The window.setKeyRepeatEnabled(false) will obviously not work because you don't get the input through the window, but directly from the keyboard.
sf::Event::KeyPressed and sf::Event::KeyReleased events: for this, window.setKeyRepeatEnabled(false) will work, but still it's not the recommended way to deal with text input, as it would require a lot of juggling by your side to handle key combinations (accents, uppa.
sf::Event::TextEntered event: now, this is the best and recommended way to handle typing. Check the tutorial to see how to use it.

Getting the file clicked on in a window or desktop window

I'm new to shell programming and having trouble getting the filepath (or really, any information) about which item is being clicked on in a window (desktop or otherwise). I'm following the general path laid out by the answer to Can i use Global System Hooks to capture which file was clicked on? but I'm not having any luck.
The clicking is the smaller issue here, so I've just substituted random values (where I know the desktop is and where a file should be located) for the mouse position. (Regardless, it doesn't work even when I'm trying this out on my mouse's current position).
LVHITTESTINFO hitTest = { 0 };
hitTest.pt.x = 55;
hitTest.pt.y = 230;
hitTest.flags = LVHT_ONITEM;
currWindow = WindowFromPoint(pt);
int index = ListView_HitTest(currWindow, &hitTest);
//cout << index + " index";
//cout << hitTest.iItem + " iltem ";
if (index != -1) {
//char* itemText = new char[256];
std::vector<wchar_t> itemText(1024);
ListView_GetItemText(window, index, 0, &itemText[0], 256);
PIDLIST_ABSOLUTE filepidl;
SFGAOF out;
std::wstring strtext = std::wstring(itemText.begin(), itemText.end());
//cout << " ";
//cout << *(strtext.c_str()) + " ";
HRESULT parse = SHParseDisplayName(strtext.c_str(), NULL, &filepidl, SFGAO_CANDELETE, &out);
if (filepidl != NULL) {
LPTSTR filePath = new TCHAR[MAX_PATH];
BOOL getPath = SHGetPathFromIDList(filepidl, filePath);
cout << *filePath ;
}
}
This is part of my code. I think there's something wrong with how I'm getting the index of the file because it keeps returning 0 but I've been hacking at this for days and am stuck. The MSDN documentation is confusing to me at best.
Any help or insight would be appreciated! I can't find any example code of this online. Thanks!
Using the listview directly like this is not a good idea because Explorer is free to implement the shell view in any way it wants and in Windows 7 and later a Explorer window no longer uses a listview, it uses a custom control by default!
If you only care about the display name and invoking the default action you can use UI Automation, it should work on other types of windows/controls as well, not just a shell file list.
If you need to know the full path and other details you can use the IShellWindows interface. Examples can be found on Raymond Chens blog here and here...

Qt pass additional argument to slot AND keep emitted signal data

I have searched the web on this issue and I've repeatedly got answers referring to the use of QSignalMapper. But my problem is pretty clear, QSignalMapper automatically gets rid of whatever is originally emitted and replaces it with basically nothing, plus the new data that is set via setMapping().
The problem here is simple.
I have a QNetworkAccessManager that parses html and updates a vector containing text data:
void DataManager::startHttpRequest(QString url, int index)
{
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
//QSignalMapper* signalMapper = new QSignalMapper(this);
//connect(manager,SIGNAL(finished(QNetworkReply*)), signalMapper,SLOT(map()));
//signalMapper->setMapping(manager, index);
//connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(insertUpdate(int)));
connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(finishHttpRequest(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl(url)));
qDebug() << index;
}
and here is what happens when the request is finished, the normal way:
void DataManager::finishHttpRequest(QNetworkReply *reply)
{
QString html = QString(reply->readAll()).simplified();
QString info;
int start = html.indexOf("<span id=\"SalePrice\" >");
if(start != -1)
{
QString price = html.mid(start + 23, 30);
int end = price.indexOf("</span>");
info = price.mid(0, end - 1);
qWarning() << price.mid(0, end - 1);
}
else
{
info = "NA";
}
// Do more stuff
}
Using the normal way of signals and slots, I would not be able to know the index of the vector I am updating,
Or,
If I am using QSignalMapper, I know the index, but not the data that comes with it.
How do I get BOTH working (index + data)?
(something like mySlot(QNetworkReply *reply, int *index), but we all know that won't work)
Many thanks in advance.
While it's probably not the best,
sender()->setObjectName(const QString & name) allows the sender to name itself.
The sender's name can be accessed from the receiving slot via sender()->ObjectName()
As documented on http://qt-project.org/doc/qt-5/qobject.html#objectName-prop.

Check if two consts are empty

I'm kind of new to the C++ scene so I'm wondering how I'd verify both fields have some text entered, here's the current code which is only verifying one field
void App::requestLogin(const QString &email, const QString &password) {
if (m_active)
return;
//how can I do both password and email here????
const QStringList list = email.split(QRegExp("\\s+"), QString::SkipEmptyParts);
if (list.isEmpty()) {
m_errorMessage = "please complete both fields";
m_error = true;
emit statusChanged();
return;
}
}
It is hard to understand what you mean, but this is my wild guess based on your error message. You do not even need a regex for this. Even if you needed, you should use QRegularExpression rather than the much slower QRegExp.
void App::requestLogin(const QString &email, const QString &password) {
if (m_active)
return;
...
if (email.isEmpty() || password.isEmpty()) {
m_errorMessage = "please complete both fields";
m_error = true;
emit statusChanged();
return;
}
}
This operation is also more logical than && as you wrote in your comment because usually you need to supply both email and password. Basically the condition will meet if either of those meets. That means if any of the input fields kept empty, you will raise the error which seems a reasonable behavior.
Something along these lines:
if (list.isEmpty() && password.isEmpty())
I'm not sure why you are "splitting" the email. If it's just an email address used for login purposes, you should be able to do email.isEmpty() rather than using the regexp splitting.

Save QNetworkReply

I would like to be able to save the QNetworkReply to a QString/QByteArray. In the examples I've seen they always saves the stream to another file.
At the moment my code looks something like this, where I get a string from the host and all I want to do is to parse it to look for the specified error code.
if(_reply->error() == QNetworkReply::UnknownContentError) {
qDebug() << _reply->readAll(); // prints out the xml message
QString test = QString(_reply->readAll());
qDebug() << test; // ""
QByteArray test2 = QByteArray(_reply->readAll());
qDebug() << test2; // ""
QRegExp rxlen("(<code>)(.*(?=</code>))");
rxlen.setMinimal(true);
int pos = rxlen.indexIn(test); // pos == -1
if(pos > -1) {
qDebug() << rxlen.cap(2); // never hit
}
}
The message is pretty small and looks something like this:
<?xml version="1.0" encoding="utf-8"?>
<error>
<code>string-value</code>
<message>string-value</message>
</error>
So how can I load this small stream into memory, or just look for the error code?
QNetworkReply inherits from QIODevice which is a stream. After you have read something from a stream it's not there anymore. After your debug line (one with // prints out the xml message comment) there's nothing to read anymore.