hiredis messages not arriving in subscribed handler - c++

I have been working with hiredis as a client, everything e.g set, publish, etc works except for subscribe. I'm able to subscribe but can't get any message when I try to publish to the channel I've subscribed to. Here is the code I'm using:
int main() {
signal(SIGPIPE, sigHandler);
struct event_base *base = event_base_new();
assert(base != nullptr);
auto redis = redisAsyncConnect(IP, PORT);
if (redis != nullptr && redis->err) {
std::cerr << redis->err;
delete redis;
exit(1);
}
std::cout << "Connected" << END;
int flag;
std::cout << "Calling redisLibeventAttach" << END;
redisLibeventAttach(redis, base);
flag = redisAsyncCommand(redis, onMessage, (char *) "sub", "SUBSCRIBE test");
std::cout << "Command ret: " << flag << END;
flag = event_base_dispatch(base);
std::cout << " Event base flag " << flag << END;
return 0;
}
And the on message function:
void onMessage(redisAsyncContext *context, void *r, void *data) {
assert(r != nullptr);
auto *reply = static_cast<redisReply *>(r);
assert(reply != nullptr);
std::cout << "Reply " << reply->type << END;
switch (reply->type) {
case REDIS_REPLY_ARRAY:
for (int i = 0; i < reply->elements; ++i) {
std::cout << i << " -- " << reply->element[i]->str << END;
}
break;
case REDIS_REPLY_STRING:
std::cout << reply->str << END;
break;
}
}
Is there anything else I'm supposed to do?

Related

Google Pub/Sub C++ C++ Pub/Sub stops receiving

Using the online documentation and the code in the sample repo, I've implemented PubSub for a single incoming and multiple outgoing. The pull PubSub is an ordering subscription (would much prefer an ordered and deliever once, but that doesn't seem allowed). I have dead letter configured for each PubSub. Repeatably, the code will stop pulling messages. Sometimes in 5 minutes, sometimes after a couple of days. This morning, there were 55k messages waiting to be pulled. No messages in the dead letter. Based on the website, I expected something from the then() handler in the subscription, but there is no error messages. Here is the relevant parts my code.
/* These are based on https://github.com/googleapis/google-cloud-cpp/blob/HEAD/google/cloud/pubsub/samples/samples.cc */
/* https://cloud.google.com/pubsub/docs/handling-failures#dead-letter_topic */
/* https://cloud.google.com/blog/products/application-development/running-cplusplus-apps-with-the-help-of-pubsub-and-gke */
/* https://cloud.google.com/pubsub/docs/samples/pubsub-subscriber-error-listener#code-sample */
#include <google/cloud/pubsub/publisher.h>
#include <google/cloud/storage/client.h>
#include <google/cloud/pubsub/subscriber.h>
#include <google/cloud/pubsub/subscription_admin_client.h>
#include <google/cloud/pubsub/topic_admin_client.h>
#include <nlohmann/json.hpp>
void createTopic(const std::string& topicId, const std::string& dlTopicId, google::cloud::pubsub::TopicAdminClient& client)
{
namespace pubsub = ::google::cloud::pubsub;
[](pubsub::TopicAdminClient client, std::string project_id, std::string topic_id, std::string dl_topic_id)
{
auto topic = client.CreateTopic(pubsub::TopicBuilder(pubsub::Topic(project_id, topic_id)));
// Note that kAlreadyExists is a possible error when the library retries.
if (topic.status().code() == google::cloud::StatusCode::kAlreadyExists)
{
;
}
else if (!topic)
{
throw std::runtime_error(topic.status().message());
}
else
{
LOGn << "The topic " << topic_id << " was successfully created: " << topic->DebugString();
}
auto dl_topic = client.CreateTopic(pubsub::TopicBuilder(pubsub::Topic(project_id, dl_topic_id)));
// Note that kAlreadyExists is a possible error when the library retries.
if (dl_topic.status().code() == google::cloud::StatusCode::kAlreadyExists)
{
;
}
else if (!dl_topic)
{
throw std::runtime_error(dl_topic.status().message());
}
else
{
LOGn << "The deadletter topic " << dl_topic_id << " was successfully created: " << dl_topic->DebugString();
}
}
(client, pubSubProjectId, topicId, dlTopicId);
}
void createOrderingSubscription(const std::string& topicId, const std::string& subscriptionId, const std::string& dlTopicId, const std::string& dlSubscriptionId, google::cloud::pubsub::SubscriptionAdminClient& client)
{
namespace pubsub = ::google::cloud::pubsub;
return [](pubsub::SubscriptionAdminClient client, std::string const& project_id, std::string const& topic_id, std::string const& subscription_id, std::string const& dl_topic_id, std::string const& dl_subscription_id)
{
static const constexpr int DEAD_LETTER_DELIVERY_ATTEMPTS = 5;
auto sub = client.CreateSubscription(
pubsub::Topic(project_id, std::move(topic_id)),
pubsub::Subscription(project_id, subscription_id),
pubsub::SubscriptionBuilder{}
.enable_message_ordering(true)
.set_ack_deadline(std::chrono::seconds(60))
.set_dead_letter_policy(
pubsub::SubscriptionBuilder::MakeDeadLetterPolicy(
pubsub::Topic(project_id, dl_topic_id),
DEAD_LETTER_DELIVERY_ATTEMPTS))
);
if (sub.status().code() == google::cloud::StatusCode::kAlreadyExists)
{
;
}
else if (!sub)
{
throw std::runtime_error(sub.status().message());
}
else
{
LOGd << "The subscription " << subscription_id << " was successfully created: " << sub->DebugString();
}
auto dl_sub = client.CreateSubscription(
pubsub::Topic(project_id, std::move(dl_topic_id)),
pubsub::Subscription(project_id, dl_subscription_id)
);
if (dl_sub.status().code() == google::cloud::StatusCode::kAlreadyExists)
{
;
}
else if (! dl_sub)
{
throw std::runtime_error(sub.status().message());
}
else
{
LOGd << "The deadletter subscription " << dl_subscription_id << " was successfully created: " << dl_sub->DebugString();
}
return;
}
(client, pubSubProjectId, topicId, subscriptionId, dlTopicId, dlSubscriptionId);
}
void run()
{
while (running)
{
try
{
namespace pubsub = ::google::cloud::pubsub;;
int concurrency = 1;
pubsub::TopicAdminClient topicClient(pubsub::MakeTopicAdminConnection());
pubsub::SubscriptionAdminClient subscriptionClient(pubsub::MakeSubscriptionAdminConnection());
createTopicSubscriptionId(eId, fId, "", fTopicId, fSubscriptionId, fDLTopicId, fDLSubscriptionId);
createTopic(fTopicId, fDLTopicId, topicClient);
createOrderingSubscription(fTopicId, fSubscriptionId, fDLTopicId, fDLSubscriptionId, subscriptionClient);
fSubscriptionProblem = false;
auto const subscription = pubsub::Subscription(pubSubProjectId, fSubscriptionId);
auto subscriber = pubsub::Subscriber(pubsub::MakeSubscriberConnection(
subscription,
pubsub::SubscriberOptions{}
.set_max_outstanding_messages(concurrency)
.set_max_outstanding_bytes(concurrency * 1024)
.set_max_concurrency(concurrency),
pubsub::ConnectionOptions{}.set_background_thread_pool_size(concurrency))
);
auto session = subscriber.Subscribe([](pubsub::Message const& m, pubsub::AckHandler h) {
ProcessMsg::CommTopic topic = static_cast<ProcessMsg::CommTopic>(std::stoi(m.attributes()["topic"]));
bool g = true;
std::string msg = m.data();
LOGi << "Received message, id " << m.message_id() << ", attempt " << h.delivery_attempt() <<", ordering key '" << m.ordering_key() << "', topic " << ProcessMsg::commTopic(topic) << " (" << topic << ")";
messageCallback(msg);
std::move(h).ack();
})
.then([](::google::cloud::future<google::cloud::Status> f) {
LOGe << "Subscription problem : " << f.get();
fSubscriptionProblem = true;
});
if (! session.valid())
{
LOGe << "Subscribe session invalid";
break;
}
while (running && ! fSubscriptionProblem)
{
if (outgoingQueue.empty())
{
std::this_thread::sleep_for(std::chrono::milliseconds(500));
continue;
}
std::string gTopicId = "";
std::string gSubscriptionId = "";
std::string gDLTopicId = "";
std::string gDLSubscriptionId = "";
const OutgoingMsg omsg = outgoingQueue.front();
createTopicSubscriptionId(0, 0, omsg.identifier, gTopicId, gSubscriptionId, gDLTopicId, gDLSubscriptionId);
createTopic(gTopicId, gDLTopicId, topicClient);
createOrderingSubscription(gTopicId, gSubscriptionId, gDLTopicId, gDLSubscriptionId, subscriptionClient);
try
{
auto publisher = pubsub::Publisher(pubsub::MakePublisherConnection(pubsub::Topic(pubSubProjectId, gTopicId)));
auto id = publisher.Publish(pubsub::MessageBuilder{}
.SetData(omsg.msg)
.SetAttribute("timestamp", std::to_string(time(NULL)))
.Build()).get();
if (! id)
{
LOGe << "Failed to publish message " << id.status().message();
}
else
{
LOGd << "Published message, id : " << *id << " (" << omsg.msg << ") to " << pubSubProjectId << "/" << gTopicId;
outgoingQueue.pop_front();
}
}
catch (std::exception const& e)
{
LOGe << "Failed to publish message " << e.what();
}
}
if (running)
{
LOGn << "GCP problem, cancelling session";
session.cancel();
LOGd << "Waiting 15 seconds";
std::this_thread::sleep_for(std::chrono::seconds(15));
}
}
catch (std::runtime_error &e)
{
LOGe << "RuntimeError exception : " << e.what();
}
catch(std::exception& e)
{
LOGe << "Exception : " << e.what();
}
}
}

How can I send socket id through pthread?

I have a server in a raspberry pi, and want to allow multithreading. The server is working. The client is in windows.
I believe I need to send the socket id through the pthread_create, but haven't found how. Is there anything else I need to send?
What is the best way to do it?
I've searched the internet, stackoverflow included, and tryed some resolutions, but they didn't work.
const int PORT = 12000;
TCPServer tcp;
pthread_t my_thread[MAXCLIENTQUEUE];
int clientID = 0;
int main()
{
tcp.setup(PORT);
int clientQueueSize = 0, threadJoin = 0;
void *res;
do {
socklen_t sosize = sizeof(tcp.clientAddress);
//realizar o accept
tcp.newsockfd[clientQueueSize] = accept(tcp.sockfd, (struct sockaddr*) & tcp.clientAddress, &sosize);
if (tcp.newsockfd[clientQueueSize] == -1)
{
cout << "Error accepting -> " << tcp.newsockfd[clientQueueSize] << endl;
tcp.detach();
}
cout << ">- accept: " << strerror(errno) << " / codigo: " << tcp.newsockfd[clientQueueSize] << " - Endereco: " << inet_ntoa(tcp.clientAddress.sin_addr) << endl;
clientID++;
cout << ">>> client accepted" << " | Client ID: " << clientID << endl;
// criar threads
int ret = pthread_create(&my_thread[clientQueueSize], NULL, messenger, &tcp.newsockfd[clientQueueSize]);
cout << ">- pthread: " << strerror(errno) << " / codigo: " << ret << endl;
if (ret != 0) {
cout << "Error: pthread_create() failed\n" << "thread_n " << my_thread[clientQueueSize] << endl;
exit(EXIT_FAILURE);
}
cout << "thread n " << my_thread[clientQueueSize] << endl;
clientQueueSize++;
}
while (clientQueueSize < MAXCLIENTQUEUE);
pthread_exit(NULL);
return 0;
}
The server accepts multiple connections but only sends messages to the first client, the others connected successfully, but never receive messages.
I want for the server to be able to send messages to all the clients.
You have to create threads for all sockets.
Or, use Windows-depended async select methods.
P.S. Forget pthreads and use the standard std::thread.
map<SOCKET,std::string> clients;
void newclient(SOCKET x)
{
for(;;)
{
int r = recv(x,...);
if (r == 0 || r == -1)
break;
}
// remove it from clients, ensure proper synchronization
}
void server()
{
SOCKET x = socket(...);
bind(x,...);
listen(x,...);
for(;;)
{
auto s = accept(x,...);
if (s == INVALID_SOCKET)
break;
// save to a map, for example, after ensuring sync with a mutex and a lock guard
m[s] = "some_id";
std::thread t(newclient,s);
s.detach();
}
}
int main() //
{
// WSAStartup and other init
std::thread t(server);
t.detach();
// Message Loop or other GUI
}

server freezes when handling large messages in simple server c++

I have a client and server running, and it seems to run great, until I either a really large message, or a partial message. In either of those events it freezes. The buffer is set to 1024, but changing it doesn't seem to affect the message at all. I've copied the getRequest function where it freezes below.
If anyone knows why it freezes or how to deal with large and partial messages, that would be great, thanks.
It freezes on the line int nread = (client, buf_,1024,0); Any solutions?
cout << "entered get request while loop" << endl;
int nread = recv(client,buf_,1024,0);
cout << "number read: " << nread << endl;
string
Server::get_request(int client) {
cout << "getting request" << endl;
string request = "";
// read until we get a newline
while (cache.find("\n") == string::npos) {
cout << "entered get request while loop" << endl;
int nread = recv(client,buf_,1024,0);
if (nread < 0) {
if (errno == EINTR)
// the socket call was interrupted -- try again
continue;
else
// an error occurred, so break out
return "";
} else if (nread == 0) {
// the socket is closed
return "";
}
// be sure to use append in case we have binary data
cache.append(buf_,nread);
cout << "cache: " << cache << " : " << endl;
}
int position = cache.find("\n");
if (position == -1){
request = cache;
cache = "";
}
else{
cout << "Cache position: " << position << endl;
request = cache.substr(0,position+1);
cache.erase(0,position+1);
}
cout << "request: " << request << " : " << endl;
return request;
}
This is the full server.cc file
#include "server.h"
#include <vector>
#include <map>
#include <sstream>
#include <iostream>
Server::Server(int port) {
// setup variables
port_ = port;
buflen_ = 1024;
buf_ = new char[buflen_+1];
// cache = "";
}
Server::~Server() {
delete[] buf_;
users.clear();
}
void
Server::run() {
// create and run the server
create();
serve();
}
void
Server::create() {
struct sockaddr_in server_addr;
// setup socket address structure
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port_);
server_addr.sin_addr.s_addr = INADDR_ANY;
// create socket
server_ = socket(PF_INET,SOCK_STREAM,0);
if (!server_) {
perror("socket");
exit(-1);
}
// set socket to immediately reuse port when the application closes
int reuse = 1;
if (setsockopt(server_, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
perror("setsockopt");
exit(-1);
}
// call bind to associate the socket with our local address and
// port
if (bind(server_,(const struct sockaddr *)&server_addr,sizeof(server_addr)) < 0) {
perror("bind");
exit(-1);
}
// convert the socket to listen for incoming connections
if (listen(server_,SOMAXCONN) < 0) {
perror("listen");
exit(-1);
}
}
void
Server::close_socket() {
close(server_);
}
void
Server::serve() {
// setup client
int client;
struct sockaddr_in client_addr;
socklen_t clientlen = sizeof(client_addr);
// accept clients
while ((client = accept(server_,(struct sockaddr *)&client_addr,&clientlen)) > 0) {
handle(client);
}
close_socket();
}
Server::Message Server::parse_request(string request){
stringstream ss;
istringstream istr(request);
Message message;
message.needed = false;
message.valid = true;
message.user = "";
message.index = -1;
// istream_iterator<string> be
istr >> message.command;
//message.command = ss.str();
cout << "got command:" << message.command << ":" << endl;
if(message.command == "put")
{
istr >> message.user;
//ss << istr;
istr >> message.subject;
istr >> message.length;
cout << "message.length = " << message.length <<endl;
message.needed = false;
}
else if (message.command == "list"){
istr >> message.user;
message.needed = false;
message.length = 0;
}
else if (message.command == "get"){
istr >> message.user;
istr >> message.index;
message.needed = false;
message.length = 0;
}
else if (message.command == "reset"){
message.needed = false;
message.length = 0;
}
else{
cout << "I don't recognize that request.";
message.valid = false;
}
return message;
}
void Server::get_value(int client, Message message){
//call recv until all bytes needed are recieved
while(message.needed){
int nread = recv(client,buf_,1024,0);
if (nread < 0) {
if (errno == EINTR)
// the socket call was interrupted -- try again
continue;
else
// an error occurred, so break out
return;
} else if (nread == 0) {
// the socket is closed
return;
}
cache.append(buf_,nread);
cout << "cache length " << cache.size();
if(message.length <= cache.size()){
cout << "Message value " << message.value;
cout << "cache length " << cache.size();
message.needed = false;
message.value = cache.substr(0,message.length);
cache.erase(0,message.length);
cout << "Message value " << message.value;
cout << "cache length " << cache.size();
}
}
}
string
Server::get_request(int client) {
cout << "getting request" << endl;
string request = "";
// read until we get a newline
while (cache.find("\n") == string::npos) {
cout << "entered get request while loop" << endl;
int nread = recv(client,buf_,1024,0);
if (nread < 0) {
if (errno == EINTR)
// the socket call was interrupted -- try again
continue;
else
// an error occurred, so break out
return "";
} else if (nread == 0) {
// the socket is closed
return "";
}
// be sure to use append in case we have binary data
cache.append(buf_,nread);
cout << "cache: " << cache << " : " << endl;
}
int position = cache.find("\n");
// int position = 0;
// while (cache.find("/n") == string::npos)
// {
// position++;
// }
if (position == -1){
request = cache;
cache = "";
}
else{
cout << "Cache position: " << position << endl;
request = cache.substr(0,position+1);
cache.erase(0,position+1);
}
cout << "request: " << request << " : " << endl;
// a better server would cut off anything after the newline and
// save it in a cache
return request;
}
bool Server::send_response(int client, string response) {
// prepare to send response
cout << "sending response:" << response << ":" << endl;
const char* ptr = response.c_str();
int nleft = response.length();
int nwritten;
// loop to be sure it is all sent
while (nleft) {
if ((nwritten = send(client, ptr, nleft, 0)) < 0) {
if (errno == EINTR) {
// the socket call was interrupted -- try again
continue;
} else {
// an error occurred, so break out
perror("write");
return false;
}
} else if (nwritten == 0) {
// the socket is closed
return false;
}
nleft -= nwritten;
ptr += nwritten;
cout << "number written: " << nwritten << endl;
}
cout << "finished sending response " << endl;
return true;
}
bool Server::handle_response(int client, Message message) {
cout << "handling response" << endl;
bool success = false;
if(message.command == "put"){
if(message.length == 0){
return false;
}
message.value = cache.substr(0,message.length);
cache.erase(0,message.length);
if(subjects.count(message.user) == 0){
vector<string> userSubjects;
subjects[message.user] = userSubjects;
}
subjects[message.user].push_back(message.subject);
if(users.count(message.user) == 0){
vector<Message> messages;
users[message.user] = messages;
}
users[message.user].push_back(message);
// users.insert(message.user, message.subject);
cout << "sending response to client" << endl;
success = send_response(client, "OK\n");
}
else if("list" == message.command){
if(message.user == ""){
return false;
}
vector<string> currentSubjects = subjects[message.user];
cout << "subjects for message.user: " << message.user << endl;
stringstream sstream;
sstream << "list " << currentSubjects.size() << "\n";
//success = send_response(client, sstream.str());
// if(success == false){
// return false;
// }
// cout << "client sent user" << endl;
for (int i=0; i<currentSubjects.size(); i++){
// stringstream sstm;
sstream << (i+1) << " " << currentSubjects[i] << "\n";
}
success = send_response(client, sstream.str());
if(success == false){
return false;
}
// success = true;
cout << "message list sent successfully" << endl;
}
else if (message.command == "get"){
if(message.index == -1){
return false;
}
if(message.user == ""){
return false;
}
vector<Message> currentMessages = users[message.user];
if(message.index > currentMessages.size()){
return false;
}
stringstream sstm;
for (int i=0; i<currentMessages.size(); i++){
if ((i+1) == message.index){
sstm << "message " << currentMessages[i].subject << " " << currentMessages[i].length << "\n" << currentMessages[i].value;
cout << "message.value = " << currentMessages[i].value << endl;
}
}
cout << "message to send " << sstm.str() << endl;
success = send_response(client, sstm.str());
if(success == false){
return false;
}
// success = true;
}
else if (message.command == "reset"){
users.clear();
subjects.clear();
success = send_response(client, "OK\n");
// success = true;
}
else {
debug = true;
if (debug == true){
cout << "Debug message: " << "No valid command found in handle" << endl;
}
}
return success;
}
void
Server::handle(int client) {
// loop to handle all requests
while (1) {
// get a request
cout << "looking for new request" << endl;
string request = get_request(client);
cout << "request = " << request << endl;
// break if client is done or an error occurred
if (request.empty()) {
cout << "empty request" << endl;
break;
}
cout << "request:" << request << ":" << endl;
//parse
Message message = parse_request(request);
cout << "finished parsing" << endl;
if(message.valid == false){
cout << "invalid message" << endl;
send_response(client, "error unrecognized command\n");
cout << "cache after break from bad command: " << cache << endl;
continue;
}
if(message.length > cache.size()){
message.needed = true;
cout << "message length greater than cache size" << endl;
cout << "cache.size = " << cache.size() << endl;
}
if(message.needed){
get_value(client, message);
}
// handle message
bool success = handle_response(client, message);
cout << "finished handling response" << endl;
cout << "cache after handle: " << cache << " : " << endl;
// break if an error occurred
if (!success) {
cout << "error handling request" << endl;
send_response(client, "error handling request\n");
continue;
}
cout << "end of request" << endl;
}
close(client);
}

Connecting to an IRC server, getting Ping timeout without receiving PING message

I'm trying my hands at network programming for the first time, implementing a small IRC bot using the SFML network functionality.
The connection gets established, but from there on I can't do much else. Trying to receive any data from the server yields nothing, until I get the "Ping timeout" message after a few seconds.
Removing all or some of the receive() calls in the loginOnIRC function doesn't do any good.
Trying to connect via telnet with the exact same messages works. Here I get a PING message right after sending my NICK message.
Am I missing something?
My code is as follows
#include <iostream>
#include <string>
#include <SFML/Network.hpp>
#define ARRAY_LEN(x) (sizeof(x)/sizeof(*x))
void receive(sf::TcpSocket* sck)
{
char rcvData[100];
memset(rcvData, 0, ARRAY_LEN(rcvData));
std::size_t received;
if (sck->receive(rcvData, ARRAY_LEN(rcvData), received) != sf::Socket::Done)
{
std::cout << "oops" << std::endl;
}
std::cout << "Received " << received << " bytes" << std::endl;
std::cout << rcvData << std::endl;
}
int establishConnection(sf::TcpSocket* sck)
{
sf::Socket::Status status = sck->connect("irc.euirc.net", 6667, sf::seconds(5.0f));
if (status != sf::Socket::Done)
{
std::cout << "Error on connect!" << std::endl;
return 1;
}
std::cout << "Connect was successful!" << std::endl;
return 0;
}
int loginOnIRC(sf::TcpSocket* sck)
{
receive(sck); // We get a Ping timeout here
std::string data{ "NICK NimBot" };
if(sck->send(data.c_str(), data.length()) != sf::Socket::Done)
{
std::cout << "Error on sending " << data << std::endl;
return 1;
}
receive(sck);
data = "USER NimBot * * :Nimelrians Bot";
if (sck->send(data.c_str(), data.length()) != sf::Socket::Done)
{
std::cout << "Error on sending " << data << std::endl;
return 1;
}
receive(sck);
data = "JOIN #nimbottest";
if (sck->send(data.c_str(), data.length()) != sf::Socket::Done)
{
std::cout << "Error on sending " << data << std::endl;
return 1;
}
return 0;
}
int main()
{
sf::TcpSocket sck{};
establishConnection(&sck); // works
loginOnIRC(&sck);
while(true)
{
char data[100];
memset(data, 0, ARRAY_LEN(data));
std::size_t received;
sf::Socket::Status rcvStatus = sck.receive(data, ARRAY_LEN(data), received);
if (rcvStatus != sf::Socket::Done)
{
std::cout << "oops" << std::endl;
if (rcvStatus == sf::Socket::Disconnected)
{
break;
}
}
std::cout << "Received " << received << " bytes" << std::endl;
std::cout << data << std::endl;
}
return 0;
}

highscore only refreshing on launch sqlite

I have a highscore system implemented using SQLite for a c++ shooter ive made but it only refreshes when I relaunch the game, I think this is because it only re- sorts from largest to smallest on game launch. I don't know why this is, it does seem to record all game scores as it should, but I think it is only ordering them on launch. How could I make it so it re-orders before it prints to screen. Here is the code
in main.cpp
case eHIGH_SCORES:
DrawString( "HIGHSCORES", iScreenWidth * 0.38, iScreenHeight * 0.95);
DrawString( "PRESS C TO CLOSE", iScreenWidth * 0.32, iScreenHeight * 0.1);
DatabaseMaker DatabaseMaker("MyDatabase.db");
DatabaseMaker.CreateDatabase();
DatabaseMaker.CreateTable("HIGHSCOREST");
if (scorer<1)
{
DatabaseMaker.InsertRecordIntoTable("HIGHSCOREST",scoreArray);
scorer++;
for (int i=0; i<10; i++)
{
scoreArray[i]=0;
}
}
DatabaseMaker.RetrieveRecordsFromTable("HIGHSCOREST");
DatabaseMaker.databaseprinter();
then in the Database maker class I have
DatabaseMaker::DatabaseMaker(std::string HighScoresT)
{
this->HighScores = HighScoresT;
myDatabase = NULL;
}
int DatabaseMaker::Callback(void* notUsed, int numRows, char **data, char **columnName)
{
for(int i = 0; i < numRows; i++)
{
std::cout << columnName[i] << ": " << data[i] << std::endl;
holder.push_back(atoi(data[i]));
}
return 0;
}
void DatabaseMaker::databaseprinter()
{
for (int i = 0; i < 10; i++)
{
itoa(holder[i], displayHolder, 10);
DrawString(displayHolder, 780/2, 700-(50*i));
}
}
void DatabaseMaker::CreateDatabase()
{
int errorCode = sqlite3_open(HighScores.c_str(), &myDatabase);
if(errorCode == SQLITE_OK)
{
std::cout << "Database opened successfully." << std::endl;
}
else
{
std::cout << "An error has occured." << std::endl;
}
}
void DatabaseMaker::CreateTable(std::string HIGHSCOREST)
{
char* errorMsg = NULL;
std::string sqlStatement;
sqlStatement = "CREATE TABLE HIGHSCOREST(" \
"ID INT," \
"SCORE INT);";
sqlite3_exec(myDatabase, sqlStatement.c_str(), Callback, 0, &errorMsg);
if(errorMsg != NULL)
{
std::cout << "Error message: " << errorMsg << std::endl;
}
}
void DatabaseMaker::InsertRecordIntoTable(std::string HIGHSCOREST,int (&scoreArray)[10] )
{
char*errorMsg = NULL;
std::string sqlStatement;
int x=5;
for(int i=0;i<10;i++)
{
std::string scorestring;
scorestring = std::to_string(scoreArray[i]);
sqlStatement = "INSERT INTO HIGHSCOREST (ID,SCORE)" \
"VALUES (1,"+scorestring+");";
sqlite3_exec(myDatabase, sqlStatement.c_str(), Callback, 0, &errorMsg);
if(errorMsg != NULL)
{
std::cout << "Error message: " << errorMsg << std::endl;
}
}
}
void DatabaseMaker::RetrieveRecordsFromTable(std::string HIGHSCOREST)
{
char* errorMsg = NULL;
std::string sqlStatement;
sqlStatement = "SELECT SCORE from HIGHSCOREST order by SCORE desc;";
sqlite3_exec(myDatabase, sqlStatement.c_str(), Callback, 0, &errorMsg);
if(errorMsg != NULL)
{
std::cout << "Error message: " << errorMsg << std::endl;
}
sqlite3_close(myDatabase);
}
DatabaseMaker::~DatabaseMaker()
{
}
Well, maybe try to move sqlite3_close statement off the RetrieveRecordsFromTable member function, maybe to destructor or seperate function?
Since you close connection to database after calling it for first time (and this might be a reason the problem is fixed by rerunning your application).
Also, consider changing this DatabaseMaker DatabaseMaker("MyDatabase.db"); into this: DatabaseMaker databaseMaker("MyDatabase.db");, otherwise you might have problem defining another DatabaseMaker in same scope.