<commit_before>#include <Python.h>
#include <structmember.h>

#include <poppler/cpp/poppler-document.h>
#include <poppler/cpp/poppler-global.h>
#include <poppler/cpp/poppler-page.h>

#include <string>
#include <vector>

static PyObject* PdftotextError;

typedef struct {
    PyObject_HEAD
    int page_count;
    PyObject* data;
    poppler::document* doc;
} PDF;

static PyMemberDef PDF_members[] = {
    {
        (char*)"page_count",
        T_INT,
        offsetof(PDF, page_count),
        READONLY,
        (char*)"Page count.",
    },
    {NULL},  // Sentinel
};

static void PDF_clear(PDF* self) {
    self->page_count = 0;
    delete self->doc;
    self->doc = NULL;
    Py_CLEAR(self->data);
}

static int PDF_load_data(PDF* self, PyObject* args, PyObject* kwds) {
    PyObject* arg;
    static char* kwlist[] = {(char*)"pdf_file", NULL};

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &arg)) {
        return -1;
    }
    self->data = PyObject_CallMethod(arg, "read", NULL);
    if (self->data == NULL) {
        return -1;
    }
    return 0;
}

static int PDF_create_doc(PDF* self) {
    Py_ssize_t len;
    char* buf;

    if (PyBytes_AsStringAndSize(self->data, &buf, &len) < 0) {
        Py_CLEAR(self->data);
        return -1;
    }
    self->doc = poppler::document::load_from_raw_data(buf, len);
    if (self->doc == NULL) {
        PyErr_SetString(PdftotextError, "Poppler error creating document");
        Py_CLEAR(self->data);
        return -1;
    }
    return 0;
}

static int PDF_init(PDF* self, PyObject* args, PyObject* kwds) {
    PDF_clear(self);
    if (PDF_load_data(self, args, kwds) < 0) {
        return -1;
    }
    if (PDF_create_doc(self) < 0) {
        return -1;
    }
    self->page_count = self->doc->pages();
    return 0;
}

static void PDF_dealloc(PDF* self) {
    PDF_clear(self);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject* PDF_read(PDF* self, PyObject* args, PyObject* kwds) {
    int page_number;
    static char* kwlist[] = {(char*)"page_number", NULL};
    const poppler::page* page;
    std::vector<char> page_utf8;

    if (self->doc == NULL) {
        return PyErr_Format(PdftotextError, "No document to read");
    }
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &page_number)) {
        return NULL;
    }
    if (page_number < 1 || page_number > self->page_count) {
        return PyErr_Format(PdftotextError, "Invalid page number: %i", page_number);
    }
    page = self->doc->create_page(page_number - 1);
    if (page == NULL) {
        return PyErr_Format(PdftotextError, "Poppler error creating page");
    }
    page_utf8 = page->text().to_utf8();
    delete page;
    return PyUnicode_DecodeUTF8(page_utf8.data(), page_utf8.size(), NULL);
}

static PyObject* PDF_read_all(PyObject* self, PyObject*) {
    return PyUnicode_FromString("TODO: read the whole document");
}

static PyMethodDef PDF_methods[] = {
    {
        "read",
        (PyCFunction)PDF_read,
        METH_VARARGS | METH_KEYWORDS,
        "Extract text from the given page number.",
    },
    {
        "read_all",
        PDF_read_all,
        METH_NOARGS,
        "Extract text from the entire document.",
    },
    {NULL},  // Sentinel
};

static PyTypeObject pdftotext_PDFType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "pdftotext.PDF",                           // tp_name
    sizeof(PDF),                               // tp_basicsize
    0,                                         // tp_itemsize
    (destructor)PDF_dealloc,                   // tp_dealloc
    0,                                         // tp_print
    0,                                         // tp_getattr
    0,                                         // tp_setattr
    0,                                         // tp_reserved
    0,                                         // tp_repr
    0,                                         // tp_as_number
    0,                                         // tp_as_sequence
    0,                                         // tp_as_mapping
    0,                                         // tp_hash
    0,                                         // tp_call
    0,                                         // tp_str
    0,                                         // tp_getattro
    0,                                         // tp_setattro
    0,                                         // tp_as_buffer
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  // tp_flags
    "PDF document.",                           // tp_doc
    0,                                         // tp_traverse
    0,                                         // tp_clear
    0,                                         // tp_richcompare
    0,                                         // tp_weaklistoffset
    0,                                         // tp_iter
    0,                                         // tp_iternext
    PDF_methods,                               // tp_methods
    PDF_members,                               // tp_members
    0,                                         // tp_getset
    0,                                         // tp_base
    0,                                         // tp_dict
    0,                                         // tp_descr_get
    0,                                         // tp_descr_set
    0,                                         // tp_dictoffset
    (initproc)PDF_init,                        // tp_init
};

static PyModuleDef pdftotextmodule = {
    PyModuleDef_HEAD_INIT,
    "pdftotext",
    "Simple PDF text extraction.",
};

static void do_nothing(const std::string& message, void*) {
    // TODO: Maybe turn the message into a python warning.
}

PyMODINIT_FUNC PyInit_pdftotext() {
    PyObject* module;

    pdftotext_PDFType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&pdftotext_PDFType) < 0) {
        return NULL;
    }

    module = PyModule_Create(&pdftotextmodule);
    if (module == NULL) {
        return NULL;
    }

    Py_INCREF(&pdftotext_PDFType);
    PyModule_AddObject(module, "PDF", (PyObject*)&pdftotext_PDFType);

    PdftotextError = PyErr_NewExceptionWithDoc(
        "pdftotext.Error", "PDF error.", NULL, NULL);
    Py_INCREF(PdftotextError);
    PyModule_AddObject(module, "Error", PdftotextError);

    poppler::set_debug_error_function(do_nothing, NULL);

    return module;
}
<commit_msg>Fix formatting<commit_after>#include <Python.h>
#include <structmember.h>

#include <poppler/cpp/poppler-document.h>
#include <poppler/cpp/poppler-global.h>
#include <poppler/cpp/poppler-page.h>

#include <string>
#include <vector>

static PyObject* PdftotextError;

typedef struct {
    PyObject_HEAD
    int page_count;
    PyObject* data;
    poppler::document* doc;
} PDF;

static PyMemberDef PDF_members[] = {
    {
        (char*)"page_count",
        T_INT,
        offsetof(PDF, page_count),
        READONLY,
        (char*)"Page count.",
    },
    {NULL},  // Sentinel
};

static void PDF_clear(PDF* self) {
    self->page_count = 0;
    delete self->doc;
    self->doc = NULL;
    Py_CLEAR(self->data);
}

static int PDF_load_data(PDF* self, PyObject* args, PyObject* kwds) {
    PyObject* arg;
    static char* kwlist[] = {(char*)"pdf_file", NULL};

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &arg)) {
        return -1;
    }
    self->data = PyObject_CallMethod(arg, "read", NULL);
    if (self->data == NULL) {
        return -1;
    }
    return 0;
}

static int PDF_create_doc(PDF* self) {
    Py_ssize_t len;
    char* buf;

    if (PyBytes_AsStringAndSize(self->data, &buf, &len) < 0) {
        Py_CLEAR(self->data);
        return -1;
    }
    self->doc = poppler::document::load_from_raw_data(buf, len);
    if (self->doc == NULL) {
        PyErr_Format(PdftotextError, "Poppler error creating document");
        Py_CLEAR(self->data);
        return -1;
    }
    return 0;
}

static int PDF_init(PDF* self, PyObject* args, PyObject* kwds) {
    PDF_clear(self);
    if (PDF_load_data(self, args, kwds) < 0) {
        return -1;
    }
    if (PDF_create_doc(self) < 0) {
        return -1;
    }
    self->page_count = self->doc->pages();
    return 0;
}

static void PDF_dealloc(PDF* self) {
    PDF_clear(self);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject* PDF_read(PDF* self, PyObject* args, PyObject* kwds) {
    int page_number;
    static char* kwlist[] = {(char*)"page_number", NULL};
    const poppler::page* page;
    std::vector<char> page_utf8;

    if (self->doc == NULL) {
        return PyErr_Format(PdftotextError, "No document to read");
    }
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &page_number)) {
        return NULL;
    }
    if (page_number < 1 || page_number > self->page_count) {
        return PyErr_Format(
            PdftotextError, "Invalid page number: %i", page_number);
    }
    page = self->doc->create_page(page_number - 1);
    if (page == NULL) {
        return PyErr_Format(PdftotextError, "Poppler error creating page");
    }
    page_utf8 = page->text().to_utf8();
    delete page;
    return PyUnicode_DecodeUTF8(page_utf8.data(), page_utf8.size(), NULL);
}

static PyObject* PDF_read_all(PyObject* self, PyObject*) {
    return PyUnicode_FromString("TODO: read the whole document");
}

static PyMethodDef PDF_methods[] = {
    {
        "read",
        (PyCFunction)PDF_read,
        METH_VARARGS | METH_KEYWORDS,
        "Extract text from the given page number.",
    },
    {
        "read_all",
        PDF_read_all,
        METH_NOARGS,
        "Extract text from the entire document.",
    },
    {NULL},  // Sentinel
};

static PyTypeObject pdftotext_PDFType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "pdftotext.PDF",                           // tp_name
    sizeof(PDF),                               // tp_basicsize
    0,                                         // tp_itemsize
    (destructor)PDF_dealloc,                   // tp_dealloc
    0,                                         // tp_print
    0,                                         // tp_getattr
    0,                                         // tp_setattr
    0,                                         // tp_reserved
    0,                                         // tp_repr
    0,                                         // tp_as_number
    0,                                         // tp_as_sequence
    0,                                         // tp_as_mapping
    0,                                         // tp_hash
    0,                                         // tp_call
    0,                                         // tp_str
    0,                                         // tp_getattro
    0,                                         // tp_setattro
    0,                                         // tp_as_buffer
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  // tp_flags
    "PDF document.",                           // tp_doc
    0,                                         // tp_traverse
    0,                                         // tp_clear
    0,                                         // tp_richcompare
    0,                                         // tp_weaklistoffset
    0,                                         // tp_iter
    0,                                         // tp_iternext
    PDF_methods,                               // tp_methods
    PDF_members,                               // tp_members
    0,                                         // tp_getset
    0,                                         // tp_base
    0,                                         // tp_dict
    0,                                         // tp_descr_get
    0,                                         // tp_descr_set
    0,                                         // tp_dictoffset
    (initproc)PDF_init,                        // tp_init
};

static PyModuleDef pdftotextmodule = {
    PyModuleDef_HEAD_INIT,
    "pdftotext",
    "Simple PDF text extraction.",
};

static void do_nothing(const std::string& message, void*) {
    // TODO: Maybe turn the message into a python warning.
}

PyMODINIT_FUNC PyInit_pdftotext() {
    PyObject* module;

    pdftotext_PDFType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&pdftotext_PDFType) < 0) {
        return NULL;
    }

    module = PyModule_Create(&pdftotextmodule);
    if (module == NULL) {
        return NULL;
    }

    Py_INCREF(&pdftotext_PDFType);
    PyModule_AddObject(module, "PDF", (PyObject*)&pdftotext_PDFType);

    PdftotextError = PyErr_NewExceptionWithDoc(
        "pdftotext.Error", "PDF error.", NULL, NULL);
    Py_INCREF(PdftotextError);
    PyModule_AddObject(module, "Error", PdftotextError);

    poppler::set_debug_error_function(do_nothing, NULL);

    return module;
}
<|endoftext|>


<commit_before>
#include <unistd.h>
#include <sstream>

#include "tclap/CmdLine.h"
#include "beanstalk.hpp"
#include "alpr.h"
#include "openalpr/simpleini/simpleini.h"
#include "openalpr/cjson.h"
#include "support/tinythread.h"
#include "videobuffer.h"
#include "uuid.h"
#include <curl/curl.h>
#include "support/timing.h"

#include <log4cplus/logger.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/configurator.h>
#include <log4cplus/consoleappender.h>
#include <log4cplus/fileappender.h>

// prototypes
void streamRecognitionThread(void* arg);
bool writeToQueue(std::string jsonResult);
bool uploadPost(std::string url, std::string data);
void dataUploadThread(void* arg);

// Constants
const std::string DEFAULT_LOG_FILE_PATH="/var/log/openalpr.log";
const std::string WTS_CONFIG_FILE_PATH="/etc/openalpr/wts.conf";

const std::string BEANSTALK_QUEUE_HOST="127.0.0.1";
const int BEANSTALK_PORT=11300;
const std::string BEANSTALK_TUBE_NAME="alprd";

struct CaptureThreadData
{
  std::string stream_url;
  std::string site_id;
  int camera_id;

  std::string config_file;
  std::string country_code;
  std::string output_image_folder;
};

struct UploadThreadData
{
  std::string upload_url;
};

bool daemon_active;

static log4cplus::Logger logger;

int main( int argc, const char** argv )
{
  daemon_active = true;

  bool noDaemon = false;
  std::string logFile;
  int topn;

  std::string configFile;
  std::string country;

  TCLAP::CmdLine cmd("OpenAlpr Daemon", ' ', Alpr::getVersion());

  TCLAP::ValueArg<std::string> countryCodeArg("c","country","Country code to identify (either us for USA or eu for Europe).  Default=us",false, "us" ,"country_code");
  TCLAP::ValueArg<std::string> configFileArg("","config","Path to the openalpr.conf file.",false, "" ,"config_file");
  TCLAP::ValueArg<int> topNArg("n","topn","Max number of possible plate numbers to return.  Default=10",false, 10 ,"topN");
  TCLAP::ValueArg<std::string> logFileArg("l","log","Log file to write to.  Default=" + DEFAULT_LOG_FILE_PATH,false, DEFAULT_LOG_FILE_PATH ,"topN");

  TCLAP::SwitchArg daemonOffSwitch("f","foreground","Set this flag for debugging.  Disables forking the process as a daemon and runs in the foreground.  Default=off", cmd, false);

  try
  {

    cmd.add( topNArg );
    cmd.add( configFileArg );
    cmd.add( logFileArg );

    if (cmd.parse( argc, argv ) == false)
    {
      // Error occured while parsing.  Exit now.
      return 1;
    }

    country = countryCodeArg.getValue();
    configFile = configFileArg.getValue();
    logFile = logFileArg.getValue();
    topn = topNArg.getValue();
    noDaemon = daemonOffSwitch.getValue();
  }
  catch (TCLAP::ArgException &e)    // catch any exceptions
  {
    std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;
    return 1;
  }

  log4cplus::BasicConfigurator config;
  config.configure();

  if (noDaemon == false)
  {
    // Fork off into a separate daemon
    daemon(0, 0);

    log4cplus::SharedAppenderPtr myAppender(new log4cplus::RollingFileAppender(logFile));
    myAppender->setName("alprd_appender");
    // Redirect std out to log file
    logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("alprd"));
    logger.addAppender(myAppender);

    LOG4CPLUS_INFO(logger, "Running OpenALPR daemon in daemon mode.");
  }
  else
  {
    //log4cplus::SharedAppenderPtr myAppender(new log4cplus::ConsoleAppender());
    //myAppender->setName("alprd_appender");
    // Redirect std out to log file
    logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("alprd"));
    //logger.addAppender(myAppender);

    LOG4CPLUS_INFO(logger, "Running OpenALPR daemon in the foreground.");
  }

  CSimpleIniA ini;
  ini.SetMultiKey();

  ini.LoadFile(WTS_CONFIG_FILE_PATH.c_str());

  std::vector<std::string> stream_urls;

  CSimpleIniA::TNamesDepend values;
  ini.GetAllValues("daemon", "stream", values);

  // sort the values into the original load order
  values.sort(CSimpleIniA::Entry::LoadOrder());

  // output all of the items
  CSimpleIniA::TNamesDepend::const_iterator i;
  for (i = values.begin(); i != values.end(); ++i) {
      stream_urls.push_back(i->pItem);
  }

  if (stream_urls.size() == 0)
  {
    LOG4CPLUS_FATAL(logger, "No video streams defined in the configuration.");
    return 1;
  }

  std::string imageFolder = ini.GetValue("daemon", "image_folder", "/tmp/");
  std::string upload_url = ini.GetValue("daemon", "upload_address", "");
  std::string site_id = ini.GetValue("daemon", "site_id", "");

  LOG4CPLUS_INFO(logger, "Using: " << imageFolder << " for storing valid plate images");

  for (int i = 0; i < stream_urls.size(); i++)
  {
    CaptureThreadData* tdata = new CaptureThreadData();
    tdata->stream_url = stream_urls[i];
    tdata->camera_id = i + 1;
    tdata->config_file = configFile;
    tdata->output_image_folder = imageFolder;
    tdata->country_code = country;
    tdata->site_id = site_id;

    tthread::thread* t = new tthread::thread(streamRecognitionThread, (void*) tdata);
  }

  // Kick off the data upload thread
  UploadThreadData* udata = new UploadThreadData();
  udata->upload_url = upload_url;
  tthread::thread* t = new tthread::thread(dataUploadThread, (void*) udata );

  while (daemon_active)
  {
    usleep(30000);
  }

}

void streamRecognitionThread(void* arg)
{
  CaptureThreadData* tdata = (CaptureThreadData*) arg;

  LOG4CPLUS_INFO(logger, "country: " << tdata->country_code << " -- config file: " << tdata->config_file );
  LOG4CPLUS_INFO(logger, "Stream " << tdata->camera_id << ": " << tdata->stream_url);

  Alpr alpr(tdata->country_code, tdata->config_file);

  int framenum = 0;

  VideoBuffer videoBuffer;

  videoBuffer.connect(tdata->stream_url, 5);

  cv::Mat latestFrame;

  std::vector<uchar> buffer;

  LOG4CPLUS_INFO(logger, "Starting camera " << tdata->camera_id);

  while (daemon_active)
  {
    int response = videoBuffer.getLatestFrame(&latestFrame);

    if (response != -1)
    {

      timespec startTime;
      getTime(&startTime);
      cv::imencode(".bmp", latestFrame, buffer );
      std::vector<AlprResult> results = alpr.recognize(buffer);

      timespec endTime;
      getTime(&endTime);
      double totalProcessingTime = diffclock(startTime, endTime);

      if (results.size() > 0)
      {
	// Create a UUID for the image
	std::string uuid = newUUID();

	// Save the image to disk (using the UUID)
	std::stringstream ss;
	ss << tdata->output_image_folder << "/" << uuid << ".jpg";

	cv::imwrite(ss.str(), latestFrame);

	// Update the JSON content to include UUID and camera ID

	std::string json = alpr.toJson(results, totalProcessingTime);

	cJSON *root = cJSON_Parse(json.c_str());
	cJSON_AddStringToObject(root,	"uuid",		uuid.c_str());
	cJSON_AddNumberToObject(root,	"camera_id",	tdata->camera_id);
	cJSON_AddStringToObject(root, 	"site_id", 	tdata->site_id.c_str());
	cJSON_AddNumberToObject(root,	"img_width",	latestFrame.cols);
	cJSON_AddNumberToObject(root,	"img_height",	latestFrame.rows);

	char *out;
	out=cJSON_PrintUnformatted(root);
	cJSON_Delete(root);

	std::string response(out);

	free(out);

	// Push the results to the Beanstalk queue
	writeToQueue(response);
      }
    }

    usleep(10000);
  }

  videoBuffer.disconnect();

  LOG4CPLUS_INFO(logger, "Video processing ended");

  delete tdata;
}

bool writeToQueue(std::string jsonResult)
{
  try
  {
    Beanstalk::Client client(BEANSTALK_QUEUE_HOST, BEANSTALK_PORT);
    client.use(BEANSTALK_TUBE_NAME);

    int id = client.put(jsonResult);

    if (id <= 0)
    {
      LOG4CPLUS_ERROR(logger, "Failed to write data to queue");
      return false;
    }

    LOG4CPLUS_INFO(logger, "put job id: " << id );

  }
  catch (const std::runtime_error& error)
  {
    LOG4CPLUS_WARN(logger, "Error connecting to Beanstalk.  Result has not been saved.");
    return false;
  }
  return true;
}

void dataUploadThread(void* arg)
{

  /* In windows, this will init the winsock stuff */
  curl_global_init(CURL_GLOBAL_ALL);

  UploadThreadData* udata = (UploadThreadData*) arg;

  while(daemon_active)
  {
    try
    {
      Beanstalk::Client client(BEANSTALK_QUEUE_HOST, BEANSTALK_PORT);

      client.watch(BEANSTALK_TUBE_NAME);

      while (daemon_active)
      {
	Beanstalk::Job job;

	client.reserve(job);

	if (job.id() > 0)
	{
	  LOG4CPLUS_DEBUG(logger, job.body() );
	  if (uploadPost(udata->upload_url, job.body()))
	  {
	    client.del(job.id());
	    LOG4CPLUS_INFO(logger, "Job: " << job.id() << " successfully uploaded" );
	  }
	  else
	  {
	    client.release(job);
	    LOG4CPLUS_WARN(logger, "Job: " << job.id() << " failed to upload.  Will retry." );
	  }
	}

	// Wait 10ms
	usleep(10000);
      }

    }
    catch (const std::runtime_error& error)
    {
      LOG4CPLUS_WARN(logger, "Error connecting to Beanstalk.  Will retry." );
    }
    // wait 5 seconds
    usleep(5000000);
  }

  curl_global_cleanup();
}

bool uploadPost(std::string url, std::string data)
{
  bool success = true;
  CURL *curl;
  CURLcode res;

  /* get a curl handle */
  curl = curl_easy_init();
  if(curl) {
    /* First set the URL that is about to receive our POST. This URL can
       just as well be a https:// URL if that is what should receive the
       data. */
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    /* Now specify the POST data */
    //char* escaped_data = curl_easy_escape(curl, data.c_str(), data.length());
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
    //curl_free(escaped_data);

    /* Perform the request, res will get the return code */
    res = curl_easy_perform(curl);
    /* Check for errors */
    if(res != CURLE_OK)
    {
      success = false;
    }

    /* always cleanup */
    curl_easy_cleanup(curl);
  }

  return success;

}<commit_msg>Sleep for longer when a connection cannot be established<commit_after>
#include <unistd.h>
#include <sstream>

#include "tclap/CmdLine.h"
#include "beanstalk.hpp"
#include "alpr.h"
#include "openalpr/simpleini/simpleini.h"
#include "openalpr/cjson.h"
#include "support/tinythread.h"
#include "videobuffer.h"
#include "uuid.h"
#include <curl/curl.h>
#include "support/timing.h"

#include <log4cplus/logger.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/configurator.h>
#include <log4cplus/consoleappender.h>
#include <log4cplus/fileappender.h>

// prototypes
void streamRecognitionThread(void* arg);
bool writeToQueue(std::string jsonResult);
bool uploadPost(std::string url, std::string data);
void dataUploadThread(void* arg);

// Constants
const std::string DEFAULT_LOG_FILE_PATH="/var/log/openalpr.log";
const std::string WTS_CONFIG_FILE_PATH="/etc/openalpr/wts.conf";

const std::string BEANSTALK_QUEUE_HOST="127.0.0.1";
const int BEANSTALK_PORT=11300;
const std::string BEANSTALK_TUBE_NAME="alprd";

struct CaptureThreadData
{
  std::string stream_url;
  std::string site_id;
  int camera_id;

  std::string config_file;
  std::string country_code;
  std::string output_image_folder;
};

struct UploadThreadData
{
  std::string upload_url;
};

bool daemon_active;

static log4cplus::Logger logger;

int main( int argc, const char** argv )
{
  daemon_active = true;

  bool noDaemon = false;
  std::string logFile;
  int topn;

  std::string configFile;
  std::string country;

  TCLAP::CmdLine cmd("OpenAlpr Daemon", ' ', Alpr::getVersion());

  TCLAP::ValueArg<std::string> countryCodeArg("c","country","Country code to identify (either us for USA or eu for Europe).  Default=us",false, "us" ,"country_code");
  TCLAP::ValueArg<std::string> configFileArg("","config","Path to the openalpr.conf file.",false, "" ,"config_file");
  TCLAP::ValueArg<int> topNArg("n","topn","Max number of possible plate numbers to return.  Default=10",false, 10 ,"topN");
  TCLAP::ValueArg<std::string> logFileArg("l","log","Log file to write to.  Default=" + DEFAULT_LOG_FILE_PATH,false, DEFAULT_LOG_FILE_PATH ,"topN");

  TCLAP::SwitchArg daemonOffSwitch("f","foreground","Set this flag for debugging.  Disables forking the process as a daemon and runs in the foreground.  Default=off", cmd, false);

  try
  {

    cmd.add( topNArg );
    cmd.add( configFileArg );
    cmd.add( logFileArg );

    if (cmd.parse( argc, argv ) == false)
    {
      // Error occured while parsing.  Exit now.
      return 1;
    }

    country = countryCodeArg.getValue();
    configFile = configFileArg.getValue();
    logFile = logFileArg.getValue();
    topn = topNArg.getValue();
    noDaemon = daemonOffSwitch.getValue();
  }
  catch (TCLAP::ArgException &e)    // catch any exceptions
  {
    std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;
    return 1;
  }

  log4cplus::BasicConfigurator config;
  config.configure();

  if (noDaemon == false)
  {
    // Fork off into a separate daemon
    daemon(0, 0);

    log4cplus::SharedAppenderPtr myAppender(new log4cplus::RollingFileAppender(logFile));
    myAppender->setName("alprd_appender");
    // Redirect std out to log file
    logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("alprd"));
    logger.addAppender(myAppender);

    LOG4CPLUS_INFO(logger, "Running OpenALPR daemon in daemon mode.");
  }
  else
  {
    //log4cplus::SharedAppenderPtr myAppender(new log4cplus::ConsoleAppender());
    //myAppender->setName("alprd_appender");
    // Redirect std out to log file
    logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("alprd"));
    //logger.addAppender(myAppender);

    LOG4CPLUS_INFO(logger, "Running OpenALPR daemon in the foreground.");
  }

  CSimpleIniA ini;
  ini.SetMultiKey();

  ini.LoadFile(WTS_CONFIG_FILE_PATH.c_str());

  std::vector<std::string> stream_urls;

  CSimpleIniA::TNamesDepend values;
  ini.GetAllValues("daemon", "stream", values);

  // sort the values into the original load order
  values.sort(CSimpleIniA::Entry::LoadOrder());

  // output all of the items
  CSimpleIniA::TNamesDepend::const_iterator i;
  for (i = values.begin(); i != values.end(); ++i) {
      stream_urls.push_back(i->pItem);
  }

  if (stream_urls.size() == 0)
  {
    LOG4CPLUS_FATAL(logger, "No video streams defined in the configuration.");
    return 1;
  }

  std::string imageFolder = ini.GetValue("daemon", "image_folder", "/tmp/");
  std::string upload_url = ini.GetValue("daemon", "upload_address", "");
  std::string site_id = ini.GetValue("daemon", "site_id", "");

  LOG4CPLUS_INFO(logger, "Using: " << imageFolder << " for storing valid plate images");

  for (int i = 0; i < stream_urls.size(); i++)
  {
    CaptureThreadData* tdata = new CaptureThreadData();
    tdata->stream_url = stream_urls[i];
    tdata->camera_id = i + 1;
    tdata->config_file = configFile;
    tdata->output_image_folder = imageFolder;
    tdata->country_code = country;
    tdata->site_id = site_id;

    tthread::thread* t = new tthread::thread(streamRecognitionThread, (void*) tdata);
  }

  // Kick off the data upload thread
  UploadThreadData* udata = new UploadThreadData();
  udata->upload_url = upload_url;
  tthread::thread* t = new tthread::thread(dataUploadThread, (void*) udata );

  while (daemon_active)
  {
    usleep(30000);
  }

}

void streamRecognitionThread(void* arg)
{
  CaptureThreadData* tdata = (CaptureThreadData*) arg;

  LOG4CPLUS_INFO(logger, "country: " << tdata->country_code << " -- config file: " << tdata->config_file );
  LOG4CPLUS_INFO(logger, "Stream " << tdata->camera_id << ": " << tdata->stream_url);

  Alpr alpr(tdata->country_code, tdata->config_file);

  int framenum = 0;

  VideoBuffer videoBuffer;

  videoBuffer.connect(tdata->stream_url, 5);

  cv::Mat latestFrame;

  std::vector<uchar> buffer;

  LOG4CPLUS_INFO(logger, "Starting camera " << tdata->camera_id);

  while (daemon_active)
  {
    int response = videoBuffer.getLatestFrame(&latestFrame);

    if (response != -1)
    {

      timespec startTime;
      getTime(&startTime);
      cv::imencode(".bmp", latestFrame, buffer );
      std::vector<AlprResult> results = alpr.recognize(buffer);

      timespec endTime;
      getTime(&endTime);
      double totalProcessingTime = diffclock(startTime, endTime);

      if (results.size() > 0)
      {
	// Create a UUID for the image
	std::string uuid = newUUID();

	// Save the image to disk (using the UUID)
	std::stringstream ss;
	ss << tdata->output_image_folder << "/" << uuid << ".jpg";

	cv::imwrite(ss.str(), latestFrame);

	// Update the JSON content to include UUID and camera ID

	std::string json = alpr.toJson(results, totalProcessingTime);

	cJSON *root = cJSON_Parse(json.c_str());
	cJSON_AddStringToObject(root,	"uuid",		uuid.c_str());
	cJSON_AddNumberToObject(root,	"camera_id",	tdata->camera_id);
	cJSON_AddStringToObject(root, 	"site_id", 	tdata->site_id.c_str());
	cJSON_AddNumberToObject(root,	"img_width",	latestFrame.cols);
	cJSON_AddNumberToObject(root,	"img_height",	latestFrame.rows);

	char *out;
	out=cJSON_PrintUnformatted(root);
	cJSON_Delete(root);

	std::string response(out);

	free(out);

	// Push the results to the Beanstalk queue
	writeToQueue(response);
      }
    }

    usleep(10000);
  }

  videoBuffer.disconnect();

  LOG4CPLUS_INFO(logger, "Video processing ended");

  delete tdata;
}

bool writeToQueue(std::string jsonResult)
{
  try
  {
    Beanstalk::Client client(BEANSTALK_QUEUE_HOST, BEANSTALK_PORT);
    client.use(BEANSTALK_TUBE_NAME);

    int id = client.put(jsonResult);

    if (id <= 0)
    {
      LOG4CPLUS_ERROR(logger, "Failed to write data to queue");
      return false;
    }

    LOG4CPLUS_INFO(logger, "put job id: " << id );

  }
  catch (const std::runtime_error& error)
  {
    LOG4CPLUS_WARN(logger, "Error connecting to Beanstalk.  Result has not been saved.");
    return false;
  }
  return true;
}

void dataUploadThread(void* arg)
{

  /* In windows, this will init the winsock stuff */
  curl_global_init(CURL_GLOBAL_ALL);

  UploadThreadData* udata = (UploadThreadData*) arg;

  while(daemon_active)
  {
    try
    {
      Beanstalk::Client client(BEANSTALK_QUEUE_HOST, BEANSTALK_PORT);

      client.watch(BEANSTALK_TUBE_NAME);

      while (daemon_active)
      {
	Beanstalk::Job job;

	client.reserve(job);

	if (job.id() > 0)
	{
	  //LOG4CPLUS_DEBUG(logger, job.body() );
	  if (uploadPost(udata->upload_url, job.body()))
	  {
	    client.del(job.id());
	    LOG4CPLUS_INFO(logger, "Job: " << job.id() << " successfully uploaded" );
	    // Wait 10ms
	    usleep(10000);
	  }
	  else
	  {
	    client.release(job);
	    LOG4CPLUS_WARN(logger, "Job: " << job.id() << " failed to upload.  Will retry." );
	    // Wait 2 seconds
	    usleep(2000000);
	  }
	}

      }

    }
    catch (const std::runtime_error& error)
    {
      LOG4CPLUS_WARN(logger, "Error connecting to Beanstalk.  Will retry." );
    }
    // wait 5 seconds
    usleep(5000000);
  }

  curl_global_cleanup();
}

bool uploadPost(std::string url, std::string data)
{
  bool success = true;
  CURL *curl;
  CURLcode res;

  /* get a curl handle */
  curl = curl_easy_init();
  if(curl) {
    /* First set the URL that is about to receive our POST. This URL can
       just as well be a https:// URL if that is what should receive the
       data. */
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    /* Now specify the POST data */
    //char* escaped_data = curl_easy_escape(curl, data.c_str(), data.length());
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
    //curl_free(escaped_data);

    /* Perform the request, res will get the return code */
    res = curl_easy_perform(curl);
    /* Check for errors */
    if(res != CURLE_OK)
    {
      success = false;
    }

    /* always cleanup */
    curl_easy_cleanup(curl);
  }

  return success;

}<|endoftext|>


<commit_before>#include "platform.hpp"

#include "../base/assert.hpp"
#include "../base/macros.hpp"
#include "../base/timer.hpp"
#include "../base/logging.hpp"
#include "../defines.hpp"

#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QTemporaryFile>

#include "../std/target_os.hpp"

#if defined(OMIM_OS_WINDOWS)
  #include "../std/windows.hpp"
  #include <shlobj.h>
  #define DIR_SLASH "\\"

#elif defined(OMIM_OS_MAC)
  #include <stdlib.h>
  #include <mach-o/dyld.h>
  #include <sys/param.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <sys/sysctl.h>
  #include <glob.h>
  #include <NSSystemDirectories.h>
  #define DIR_SLASH "/"

#elif defined(OMIM_OS_LINUX)
  #include <stdlib.h>
  #include <unistd.h>
  #include <sys/stat.h>
  #define DIR_SLASH "/"

#endif

#include "../base/start_mem_debug.hpp"

// default writable directory name for dev/standalone installs
#define MAPDATA_DIR "data"
// default writable dir name in LocalAppData or ~/Library/AppData/ folders
#define LOCALAPPDATA_DIR "MapsWithMe"
// default Resources read-only dir
#define RESOURCES_DIR "Resources"

/// Contains all resources needed to launch application
static char const * sRequiredResourcesList[] =
{
  "classificator.txt",
  "drawing_rules.bin",
  "basic.skn",
  "basic_highres.skn",
  "visibility.txt",
  "symbols_24.png",
  "symbols_48.png"//,
  //"countries.txt"
};

#ifdef OMIM_OS_MAC
string ExpandTildePath(char const * path)
{
//  ASSERT(path, ());
  glob_t globbuf;
  string result = path;

  if (::glob(path, GLOB_TILDE, NULL, &globbuf) == 0) //success
  {
    if (globbuf.gl_pathc > 0)
      result = globbuf.gl_pathv[0];

    globfree(&globbuf);
  }
  return result;
}
#endif

static bool GetUserWritableDir(string & outDir)
{
#if defined(OMIM_OS_WINDOWS)
  char pathBuf[MAX_PATH] = {0};
  if (SUCCEEDED(::SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, pathBuf)))
  {
    outDir = pathBuf;
    ::CreateDirectoryA(outDir.c_str(), NULL);
    outDir += "\\" LOCALAPPDATA_DIR "\\";
    ::CreateDirectoryA(outDir.c_str(), NULL);
    return true;
  }

#elif defined(OMIM_OS_MAC)
  char pathBuf[PATH_MAX];
  NSSearchPathEnumerationState state = ::NSStartSearchPathEnumeration(NSApplicationSupportDirectory, NSUserDomainMask);
  while ((state = NSGetNextSearchPathEnumeration(state, pathBuf)))
  {
    outDir = ExpandTildePath(pathBuf);
    ::mkdir(outDir.c_str(), 0755);
    outDir += "/" LOCALAPPDATA_DIR "/";
    ::mkdir(outDir.c_str(), 0755);
    return true;
  }

#elif defined(OMIM_OS_LINUX)
  char * path = ::getenv("HOME");
  if (path)
  {
    outDir = path;
    outDir += "." LOCALAPPDATA_DIR "/";
    ::mkdir(outDir.c_str(), 0755);
    return true;
  }

#else
  #error "Implement code for your OS"

#endif
  return false;
}

/// @return full path including binary itself
static bool GetPathToBinary(string & outPath)
{
#if defined(OMIM_OS_WINDOWS)
    // get path to executable
    char pathBuf[MAX_PATH] = {0};
    if (0 < ::GetModuleFileNameA(NULL, pathBuf, MAX_PATH))
    {
      outPath = pathBuf;
      return true;
    }

#elif defined (OMIM_OS_MAC)
    char path[MAXPATHLEN] = {0};
    uint32_t pathSize = ARRAY_SIZE(path);
    if (0 == ::_NSGetExecutablePath(path, &pathSize))
    {
      char fixedPath[MAXPATHLEN] = {0};
      if (::realpath(path, fixedPath))
      {
        outPath = fixedPath;
        return true;
      }
    }

#elif defined (OMIM_OS_LINUX)
    char path[4096] = {0};
    if (0 < ::readlink("/proc/self/exe", path, ARRAY_SIZE(path)))
    {
      outPath = path;
      return true;
    }

#else
  #error "Add implementation for your operating system, please"

#endif
    return false;
}

static bool IsDirectoryWritable(string const & dir)
{
  if (!dir.empty())
  {
    QString qDir = dir.c_str();
    if (dir[dir.size() - 1] != '/' && dir[dir.size() - 1] != '\\')
      qDir.append('/');

    QTemporaryFile file(qDir + "XXXXXX");
    if (file.open())
      return true;
  }
  return false;
}

////////////////////////////////////////////////////////////////////////////////////////
class QtPlatform : public Platform
{
  my::Timer m_startTime;
  string m_writableDir;
  string m_resourcesDir;

  /// Scans all upper directories for the presence of given directory
  /// @param[in] startPath full path to lowest file in hierarchy (usually binary)
  /// @param[in] dirName directory name we want to be present
  /// @return if not empty, contains full path to existing directory
  string DirFinder(string const & startPath, string const & dirName)
  {
    size_t slashPos = startPath.size();
    while ((slashPos = startPath.rfind(DIR_SLASH, slashPos - 1)) != string::npos)
    {
      string const dir = startPath.substr(0, slashPos) + DIR_SLASH + dirName + DIR_SLASH;
      if (IsFileExists(dir))
        return dir;
      if (slashPos == 0)
        break;
    }
    return string();
  }

  /// @TODO: add better validity check
  bool AreResourcesValidInDir(string const & dir)
  {
    for (size_t i = 0; i < ARRAY_SIZE(sRequiredResourcesList); ++i)
    {
      if (!IsFileExists(dir + sRequiredResourcesList[i]))
        return false;
    }
    return true;
  }

  bool GetOSSpecificResourcesDir(string const & exePath, string & dir)
  {
    dir = DirFinder(exePath, RESOURCES_DIR);
    return !dir.empty();
  }

  void InitResourcesDir(string & dir)
  {
    // Resources dir can be any "data" folder found in the nearest upper directory,
    // where all necessary resources files are present and accessible
    string exePath;
    CHECK( GetPathToBinary(exePath), ("Can't get full path to executable") );
    dir = DirFinder(exePath, MAPDATA_DIR);
    if (!dir.empty())
    {
      // check if all necessary resources are present in found dir
      if (AreResourcesValidInDir(dir))
        return;
    }
    // retrieve OS-specific resources dir
    CHECK( GetOSSpecificResourcesDir(exePath, dir), ("Can't retrieve resources directory") );
    CHECK( AreResourcesValidInDir(dir), ("Required resources are missing, terminating...") );
  }

  void InitWritableDir(string & dir)
  {
    // Writable dir can be any "data" folder found in the nearest upper directory
    // ./data     - For Windows portable builds
    // ../data
    // ../../data - For developer builds
    // etc. (for Mac in can be up to 6 levels above due to packages structure
    // and if no _writable_ "data" folder was found, User/Application Data/MapsWithMe will be used

    string path;
    CHECK( GetPathToBinary(path), ("Can't get full path to executable") );
    dir = DirFinder(path, MAPDATA_DIR);
    if (!(!dir.empty() && IsDirectoryWritable(dir)))
    {
      CHECK( GetUserWritableDir(dir), ("Can't get User's Application Data writable directory") );
    }
  }

public:
  QtPlatform()
  {
    InitWritableDir(m_writableDir);
    InitResourcesDir(m_resourcesDir);
  }

  virtual double TimeInSec() const
  {
    return m_startTime.ElapsedSeconds();
  }

  /// @return path to /data/ with ending slash
  virtual string WritableDir() const
  {
    return m_writableDir;
  }

  virtual string ReadPathForFile(char const * file) const
  {
    string fullPath = m_writableDir + file;
    if (!IsFileExists(fullPath))
    {
      fullPath = m_resourcesDir + file;
      if (!IsFileExists(fullPath))
        MYTHROW(FileAbsentException, ("File doesn't exist", fullPath));
    }
    return fullPath;
  }

  virtual int GetFilesInDir(string const & directory, string const & mask, FilesList & outFiles) const
  {
    outFiles.clear();
    QDir dir(directory.c_str(), mask.c_str(), QDir::Unsorted,
             QDir::Files | QDir::Readable | QDir::Dirs | QDir::NoDotAndDotDot);
    int const count = dir.count();
    for (int i = 0; i < count; ++i)
      outFiles.push_back(dir[i].toUtf8().data());
    return count;
  }

  virtual bool GetFileSize(string const & file, uint64_t & size) const
  {
    QFileInfo fileInfo(file.c_str());
    if (fileInfo.exists())
    {
      size = fileInfo.size();
      return true;
    }
    return false;
  }

  virtual bool RenameFileX(string const & original, string const & newName) const
  {
    return QFile::rename(original.c_str(), newName.c_str());
  }

  virtual int CpuCores() const
  {
#if defined(OMIM_OS_WINDOWS)
    SYSTEM_INFO sysinfo = {0};
    GetSystemInfo(&sysinfo);
    DWORD numCPU = sysinfo.dwNumberOfProcessors;
    if (numCPU >= 1)
      return static_cast<int>(numCPU);

#elif defined(OMIM_OS_MAC)
    int mib[2], numCPU = 0;
    size_t len = sizeof(numCPU);
    mib[0] = CTL_HW;
    mib[1] = HW_AVAILCPU;
    sysctl(mib, 2, &numCPU, &len, NULL, 0);
    if (numCPU >= 1)
      return numCPU;
    // second try
    mib[1] = HW_NCPU;
    len = sizeof(numCPU);
    sysctl(mib, 2, &numCPU, &len, NULL, 0);
    if (numCPU >= 1)
     return numCPU;

#elif defined(OMIM_OS_LINUX)
    long numCPU = sysconf(_SC_NPROCESSORS_ONLN);
    if (numCPU >= 1)
      return static_cast<int>(numCPU);
#endif
    return 1;
  }

  double VisualScale() const
  {
    return 1.0;
  }

  string const SkinName() const
  {
    return "basic.skn";
  }

  bool IsMultiSampled() const
  {
    return true;
  }

  bool DoPeriodicalUpdate() const
  {
    return true;
  }

  double PeriodicalUpdateInterval() const
  {
    return 0.3;
  }

  vector<string> GetFontNames() const
  {
     vector<string> res;

     string fontFolder = m_resourcesDir;
     //string fontFolder = "/Library/Fonts/";

     GetFilesInDir(fontFolder, "*.ttf", res);

     sort(res.begin(), res.end());

     for (size_t i = 0; i < res.size(); ++i)
       res[i] = fontFolder + res[i];

     return res;
  }

  bool IsBenchmarking() const
  {
    bool res = false;
#ifndef OMIM_PRODUCTION
    if (res)
    {
      static bool first = true;
      if (first)
      {
        LOG(LCRITICAL, ("benchmarking only defined in production configuration"));
        first = false;
      }
      res = false;
    }
#endif
    return res;
  }

  string const DeviceID() const
  {
    return "DesktopVersion";
  }

  bool IsVisualLog() const
  {
    return false;
  }

  unsigned ScaleEtalonSize() const
  {
    return 512 + 256;
  }
};

extern "C" Platform & GetPlatform()
{
  static QtPlatform platform;
  return platform;
}
<commit_msg>Warning fix<commit_after>#include "platform.hpp"

#include "../base/assert.hpp"
#include "../base/macros.hpp"
#include "../base/timer.hpp"
#include "../base/logging.hpp"
#include "../defines.hpp"

#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QTemporaryFile>

#include "../std/target_os.hpp"

#if defined(OMIM_OS_WINDOWS)
  #include "../std/windows.hpp"
  #include <shlobj.h>
  #define DIR_SLASH "\\"

#elif defined(OMIM_OS_MAC)
  #include <stdlib.h>
  #include <mach-o/dyld.h>
  #include <sys/param.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <sys/sysctl.h>
  #include <glob.h>
  #include <NSSystemDirectories.h>
  #define DIR_SLASH "/"

#elif defined(OMIM_OS_LINUX)
  #include <stdlib.h>
  #include <unistd.h>
  #include <sys/stat.h>
  #define DIR_SLASH "/"

#endif

#include "../base/start_mem_debug.hpp"

// default writable directory name for dev/standalone installs
#define MAPDATA_DIR "data"
// default writable dir name in LocalAppData or ~/Library/AppData/ folders
#define LOCALAPPDATA_DIR "MapsWithMe"
// default Resources read-only dir
#define RESOURCES_DIR "Resources"

/// Contains all resources needed to launch application
static char const * sRequiredResourcesList[] =
{
  "classificator.txt",
  "drawing_rules.bin",
  "basic.skn",
  "basic_highres.skn",
  "visibility.txt",
  "symbols_24.png",
  "symbols_48.png"//,
  //"countries.txt"
};

#ifdef OMIM_OS_MAC
string ExpandTildePath(char const * path)
{
//  ASSERT(path, ());
  glob_t globbuf;
  string result = path;

  if (::glob(path, GLOB_TILDE, NULL, &globbuf) == 0) //success
  {
    if (globbuf.gl_pathc > 0)
      result = globbuf.gl_pathv[0];

    globfree(&globbuf);
  }
  return result;
}
#endif

static bool GetUserWritableDir(string & outDir)
{
#if defined(OMIM_OS_WINDOWS)
  char pathBuf[MAX_PATH] = {0};
  if (SUCCEEDED(::SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, pathBuf)))
  {
    outDir = pathBuf;
    ::CreateDirectoryA(outDir.c_str(), NULL);
    outDir += "\\" LOCALAPPDATA_DIR "\\";
    ::CreateDirectoryA(outDir.c_str(), NULL);
    return true;
  }

#elif defined(OMIM_OS_MAC)
  char pathBuf[PATH_MAX];
  NSSearchPathEnumerationState state = ::NSStartSearchPathEnumeration(NSApplicationSupportDirectory, NSUserDomainMask);
  while ((state = NSGetNextSearchPathEnumeration(state, pathBuf)))
  {
    outDir = ExpandTildePath(pathBuf);
    ::mkdir(outDir.c_str(), 0755);
    outDir += "/" LOCALAPPDATA_DIR "/";
    ::mkdir(outDir.c_str(), 0755);
    return true;
  }

#elif defined(OMIM_OS_LINUX)
  char * path = ::getenv("HOME");
  if (path)
  {
    outDir = path;
    outDir += "." LOCALAPPDATA_DIR "/";
    ::mkdir(outDir.c_str(), 0755);
    return true;
  }

#else
  #error "Implement code for your OS"

#endif
  return false;
}

/// @return full path including binary itself
static bool GetPathToBinary(string & outPath)
{
#if defined(OMIM_OS_WINDOWS)
    // get path to executable
    char pathBuf[MAX_PATH] = {0};
    if (0 < ::GetModuleFileNameA(NULL, pathBuf, MAX_PATH))
    {
      outPath = pathBuf;
      return true;
    }

#elif defined (OMIM_OS_MAC)
    char path[MAXPATHLEN] = {0};
    uint32_t pathSize = ARRAY_SIZE(path);
    if (0 == ::_NSGetExecutablePath(path, &pathSize))
    {
      char fixedPath[MAXPATHLEN] = {0};
      if (::realpath(path, fixedPath))
      {
        outPath = fixedPath;
        return true;
      }
    }

#elif defined (OMIM_OS_LINUX)
    char path[4096] = {0};
    if (0 < ::readlink("/proc/self/exe", path, ARRAY_SIZE(path)))
    {
      outPath = path;
      return true;
    }

#else
  #error "Add implementation for your operating system, please"

#endif
    return false;
}

static bool IsDirectoryWritable(string const & dir)
{
  if (!dir.empty())
  {
    QString qDir = dir.c_str();
    if (dir[dir.size() - 1] != '/' && dir[dir.size() - 1] != '\\')
      qDir.append('/');

    QTemporaryFile file(qDir + "XXXXXX");
    if (file.open())
      return true;
  }
  return false;
}

////////////////////////////////////////////////////////////////////////////////////////
class QtPlatform : public Platform
{
  my::Timer m_startTime;
  string m_writableDir;
  string m_resourcesDir;

  /// Scans all upper directories for the presence of given directory
  /// @param[in] startPath full path to lowest file in hierarchy (usually binary)
  /// @param[in] dirName directory name we want to be present
  /// @return if not empty, contains full path to existing directory
  string DirFinder(string const & startPath, string const & dirName)
  {
    size_t slashPos = startPath.size();
    while ((slashPos = startPath.rfind(DIR_SLASH, slashPos - 1)) != string::npos)
    {
      string const dir = startPath.substr(0, slashPos) + DIR_SLASH + dirName + DIR_SLASH;
      if (IsFileExists(dir))
        return dir;
      if (slashPos == 0)
        break;
    }
    return string();
  }

  /// @TODO: add better validity check
  bool AreResourcesValidInDir(string const & dir)
  {
    for (size_t i = 0; i < ARRAY_SIZE(sRequiredResourcesList); ++i)
    {
      if (!IsFileExists(dir + sRequiredResourcesList[i]))
        return false;
    }
    return true;
  }

  bool GetOSSpecificResourcesDir(string const & exePath, string & dir)
  {
    dir = DirFinder(exePath, RESOURCES_DIR);
    return !dir.empty();
  }

  void InitResourcesDir(string & dir)
  {
    // Resources dir can be any "data" folder found in the nearest upper directory,
    // where all necessary resources files are present and accessible
    string exePath;
    CHECK( GetPathToBinary(exePath), ("Can't get full path to executable") );
    dir = DirFinder(exePath, MAPDATA_DIR);
    if (!dir.empty())
    {
      // check if all necessary resources are present in found dir
      if (AreResourcesValidInDir(dir))
        return;
    }
    // retrieve OS-specific resources dir
    CHECK( GetOSSpecificResourcesDir(exePath, dir), ("Can't retrieve resources directory") );
    CHECK( AreResourcesValidInDir(dir), ("Required resources are missing, terminating...") );
  }

  void InitWritableDir(string & dir)
  {
    // Writable dir can be any "data" folder found in the nearest upper directory
    // ./data     - For Windows portable builds
    // ../data
    // ../../data - For developer builds
    // etc. (for Mac in can be up to 6 levels above due to packages structure
    // and if no _writable_ "data" folder was found, User/Application Data/MapsWithMe will be used

    string path;
    CHECK( GetPathToBinary(path), ("Can't get full path to executable") );
    dir = DirFinder(path, MAPDATA_DIR);
    if (!(!dir.empty() && IsDirectoryWritable(dir)))
    {
      CHECK( GetUserWritableDir(dir), ("Can't get User's Application Data writable directory") );
    }
  }

public:
  QtPlatform()
  {
    InitWritableDir(m_writableDir);
    InitResourcesDir(m_resourcesDir);
  }

  virtual double TimeInSec() const
  {
    return m_startTime.ElapsedSeconds();
  }

  /// @return path to /data/ with ending slash
  virtual string WritableDir() const
  {
    return m_writableDir;
  }

  virtual string ReadPathForFile(char const * file) const
  {
    string fullPath = m_writableDir + file;
    if (!IsFileExists(fullPath))
    {
      fullPath = m_resourcesDir + file;
      if (!IsFileExists(fullPath))
        MYTHROW(FileAbsentException, ("File doesn't exist", fullPath));
    }
    return fullPath;
  }

  virtual int GetFilesInDir(string const & directory, string const & mask, FilesList & outFiles) const
  {
    outFiles.clear();
    QDir dir(directory.c_str(), mask.c_str(), QDir::Unsorted,
             QDir::Files | QDir::Readable | QDir::Dirs | QDir::NoDotAndDotDot);
    int const count = dir.count();
    for (int i = 0; i < count; ++i)
      outFiles.push_back(dir[i].toUtf8().data());
    return count;
  }

  virtual bool GetFileSize(string const & file, uint64_t & size) const
  {
    QFileInfo fileInfo(file.c_str());
    if (fileInfo.exists())
    {
      size = fileInfo.size();
      return true;
    }
    return false;
  }

  virtual bool RenameFileX(string const & original, string const & newName) const
  {
    return QFile::rename(original.c_str(), newName.c_str());
  }

  virtual int CpuCores() const
  {
#if defined(OMIM_OS_WINDOWS)
    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    DWORD numCPU = sysinfo.dwNumberOfProcessors;
    if (numCPU >= 1)
      return static_cast<int>(numCPU);

#elif defined(OMIM_OS_MAC)
    int mib[2], numCPU = 0;
    size_t len = sizeof(numCPU);
    mib[0] = CTL_HW;
    mib[1] = HW_AVAILCPU;
    sysctl(mib, 2, &numCPU, &len, NULL, 0);
    if (numCPU >= 1)
      return numCPU;
    // second try
    mib[1] = HW_NCPU;
    len = sizeof(numCPU);
    sysctl(mib, 2, &numCPU, &len, NULL, 0);
    if (numCPU >= 1)
     return numCPU;

#elif defined(OMIM_OS_LINUX)
    long numCPU = sysconf(_SC_NPROCESSORS_ONLN);
    if (numCPU >= 1)
      return static_cast<int>(numCPU);
#endif
    return 1;
  }

  double VisualScale() const
  {
    return 1.0;
  }

  string const SkinName() const
  {
    return "basic.skn";
  }

  bool IsMultiSampled() const
  {
    return true;
  }

  bool DoPeriodicalUpdate() const
  {
    return true;
  }

  double PeriodicalUpdateInterval() const
  {
    return 0.3;
  }

  vector<string> GetFontNames() const
  {
     vector<string> res;

     string fontFolder = m_resourcesDir;
     //string fontFolder = "/Library/Fonts/";

     GetFilesInDir(fontFolder, "*.ttf", res);

     sort(res.begin(), res.end());

     for (size_t i = 0; i < res.size(); ++i)
       res[i] = fontFolder + res[i];

     return res;
  }

  bool IsBenchmarking() const
  {
    bool res = false;
#ifndef OMIM_PRODUCTION
    if (res)
    {
      static bool first = true;
      if (first)
      {
        LOG(LCRITICAL, ("benchmarking only defined in production configuration"));
        first = false;
      }
      res = false;
    }
#endif
    return res;
  }

  string const DeviceID() const
  {
    return "DesktopVersion";
  }

  bool IsVisualLog() const
  {
    return false;
  }

  unsigned ScaleEtalonSize() const
  {
    return 512 + 256;
  }
};

extern "C" Platform & GetPlatform()
{
  static QtPlatform platform;
  return platform;
}
<|endoftext|>


<commit_before>
#include <unistd.h>
#include <sstream>

#include "tclap/CmdLine.h"
#include "beanstalk.hpp"
#include "alpr.h"
#include "openalpr/simpleini/simpleini.h"
#include "openalpr/cjson.h"
#include "support/tinythread.h"
#include "videobuffer.h"
#include "uuid.h"
#include <curl/curl.h>

// prototypes
void streamRecognitionThread(void* arg);
bool writeToQueue(std::string jsonResult);
bool uploadPost(std::string url, std::string data);
void dataUploadThread(void* arg);

// Constants
const std::string DEFAULT_LOG_FILE_PATH="/var/log/openalpr.log";
const std::string WTS_CONFIG_FILE_PATH="/etc/openalpr/wts.conf";

const std::string BEANSTALK_QUEUE_HOST="127.0.0.1";
const int BEANSTALK_PORT=11300;
const std::string BEANSTALK_TUBE_NAME="alprd";

struct CaptureThreadData
{
  std::string stream_url;
  std::string site_id;
  int camera_id;

  std::string config_file;
  std::string country_code;
  std::string output_image_folder;
};

struct UploadThreadData
{
  std::string upload_url;
};

bool daemon_active;

int main( int argc, const char** argv )
{
  daemon_active = true;

  bool noDaemon = false;
  std::string logFile;
  int topn;

  std::string configFile;
  std::string country;

  TCLAP::CmdLine cmd("OpenAlpr Daemon", ' ', Alpr::getVersion());

  TCLAP::ValueArg<std::string> countryCodeArg("c","country","Country code to identify (either us for USA or eu for Europe).  Default=us",false, "us" ,"country_code");
  TCLAP::ValueArg<std::string> configFileArg("","config","Path to the openalpr.conf file.",false, "" ,"config_file");
  TCLAP::ValueArg<int> topNArg("n","topn","Max number of possible plate numbers to return.  Default=10",false, 10 ,"topN");
  TCLAP::ValueArg<std::string> logFileArg("l","log","Log file to write to.  Default=" + DEFAULT_LOG_FILE_PATH,false, DEFAULT_LOG_FILE_PATH ,"topN");

  TCLAP::SwitchArg daemonOffSwitch("f","foreground","Set this flag for debugging.  Disables forking the process as a daemon and runs in the foreground.  Default=off", cmd, false);

  try
  {

    cmd.add( topNArg );
    cmd.add( configFileArg );
    cmd.add( logFileArg );

    if (cmd.parse( argc, argv ) == false)
    {
      // Error occured while parsing.  Exit now.
      return 1;
    }

    country = countryCodeArg.getValue();
    configFile = configFileArg.getValue();
    logFile = logFileArg.getValue();
    topn = topNArg.getValue();
    noDaemon = daemonOffSwitch.getValue();
  }
  catch (TCLAP::ArgException &e)    // catch any exceptions
  {
    std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;
    return 1;
  }

  if (noDaemon == false)
  {
    // Fork off into a separate daemon
    daemon(0, 0);

    // Redirect std out to log file

    std::ofstream out(logFile.c_str());
    std::cout.rdbuf(out.rdbuf());
    std::cerr.rdbuf(out.rdbuf());

    std::cout << "Running OpenALPR daemon in daemon mode." << std::endl;
  }
  else
  {
    std::cout << "Running OpenALPR daemon in the foreground" << std::endl;
  }

  CSimpleIniA ini;
  ini.SetMultiKey();

  ini.LoadFile(WTS_CONFIG_FILE_PATH.c_str());

  std::vector<std::string> stream_urls;

  CSimpleIniA::TNamesDepend values;
  ini.GetAllValues("daemon", "stream", values);

  // sort the values into the original load order
  values.sort(CSimpleIniA::Entry::LoadOrder());

  // output all of the items
  CSimpleIniA::TNamesDepend::const_iterator i;
  for (i = values.begin(); i != values.end(); ++i) {
      stream_urls.push_back(i->pItem);
  }

  if (stream_urls.size() == 0)
  {
    std::cout << "No video streams defined in the configuration" << std::endl;
    return 1;
  }

  std::string imageFolder = ini.GetValue("daemon", "image_folder", "/tmp/");
  std::string upload_url = ini.GetValue("daemon", "upload_address", "");
  std::string site_id = ini.GetValue("daemon", "site_id", "");

  std::cout << "Using: " << imageFolder << " for storing valid plate images" << std::endl;

  for (int i = 0; i < stream_urls.size(); i++)
  {
    CaptureThreadData* tdata = new CaptureThreadData();
    tdata->stream_url = stream_urls[i];
    tdata->camera_id = i + 1;
    tdata->config_file = configFile;
    tdata->output_image_folder = imageFolder;
    tdata->country_code = country;
    tdata->site_id = site_id;

    tthread::thread* t = new tthread::thread(streamRecognitionThread, (void*) tdata);
  }

  // Kick off the data upload thread
  UploadThreadData* udata = new UploadThreadData();
  udata->upload_url = upload_url;
  tthread::thread* t = new tthread::thread(dataUploadThread, (void*) udata );

  while (daemon_active)
  {
    usleep(30000);
  }

}

void streamRecognitionThread(void* arg)
{
  CaptureThreadData* tdata = (CaptureThreadData*) arg;

  std::cout << "country: " << tdata->country_code << " -- config file: " << tdata->config_file << std::endl;
  std::cout << "Stream " << tdata->camera_id << ": " << tdata->stream_url << std::endl;

  Alpr alpr(tdata->country_code, tdata->config_file);

  std::cout << "asdf" << std::endl;

  int framenum = 0;

  VideoBuffer videoBuffer;

  videoBuffer.connect(tdata->stream_url, 5);

  cv::Mat latestFrame;

  std::vector<uchar> buffer;

  std::cout << "Daemon active: " << daemon_active << std::endl;

  while (daemon_active)
  {
    int response = videoBuffer.getLatestFrame(&latestFrame);

    if (response != -1)
    {
      cv::imencode(".bmp", latestFrame, buffer );
      std::vector<AlprResult> results = alpr.recognize(buffer);

      if (results.size() > 0)
      {
	// Create a UUID for the image
	std::string uuid = newUUID();

	// Save the image to disk (using the UUID)
	std::stringstream ss;
	ss << tdata->output_image_folder << "/" << uuid << ".jpg";

	cv::imwrite(ss.str(), latestFrame);

	// Update the JSON content to include UUID and camera ID
	cJSON *root;

	root=cJSON_CreateObject();

	std::string json = alpr.toJson(results);

	cJSON *array = cJSON_Parse(json.c_str());
	cJSON_AddStringToObject(root,	"uuid",		uuid.c_str());
	cJSON_AddNumberToObject(root,	"camera_id",	tdata->camera_id);
	cJSON_AddStringToObject(root, "site_id", 	tdata->site_id.c_str());
	cJSON_AddItemToObject(root, 	"results", 	array);

	char *out;
	out=cJSON_PrintUnformatted(root);
	cJSON_Delete(root);

	std::string response(out);

	free(out);

	// Push the results to the Beanstalk queue
	writeToQueue(response);
      }
    }

    usleep(10000);
  }

  videoBuffer.disconnect();

  std::cout << "Video processing ended" << std::endl;

  delete tdata;
}

bool writeToQueue(std::string jsonResult)
{

    Beanstalk::Client client(BEANSTALK_QUEUE_HOST, BEANSTALK_PORT);
    client.use(BEANSTALK_TUBE_NAME);

    int id = client.put(jsonResult);

    if (id <= 0)
      return false;

    std::cout << "put job id: " << id << std::endl;

    return true;
}

void dataUploadThread(void* arg)
{

  /* In windows, this will init the winsock stuff */
  curl_global_init(CURL_GLOBAL_ALL);

  UploadThreadData* udata = (UploadThreadData*) arg;

  Beanstalk::Client client(BEANSTALK_QUEUE_HOST, BEANSTALK_PORT);

  client.watch(BEANSTALK_TUBE_NAME);

  while(daemon_active)
  {
    Beanstalk::Job job;

    client.reserve(job);

    if (job.id() > 0)
    {
      if (uploadPost(udata->upload_url, job.body()))
      {
	client.del(job.id());
	std::cout << "Job: " << job.id() << " successfully uploaded" << std::endl;
      }
      else
      {
	client.release(job);
	std::cout << "Job: " << job.id() << " failed to upload.  Will retry." << std::endl;
      }
    }

    usleep(10000);
  }

  curl_global_cleanup();
}

bool uploadPost(std::string url, std::string data)
{
  bool success = true;
  CURL *curl;
  CURLcode res;

  /* get a curl handle */
  curl = curl_easy_init();
  if(curl) {
    /* First set the URL that is about to receive our POST. This URL can
       just as well be a https:// URL if that is what should receive the
       data. */
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    /* Now specify the POST data */
    //char* escaped_data = curl_easy_escape(curl, data.c_str(), data.length());
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
    //curl_free(escaped_data);

    /* Perform the request, res will get the return code */
    res = curl_easy_perform(curl);
    /* Check for errors */
    if(res != CURLE_OK)
    {
      success = false;
    }

    /* always cleanup */
    curl_easy_cleanup(curl);
  }

  return success;

}<commit_msg>Added image width/height to uploaded json<commit_after>
#include <unistd.h>
#include <sstream>

#include "tclap/CmdLine.h"
#include "beanstalk.hpp"
#include "alpr.h"
#include "openalpr/simpleini/simpleini.h"
#include "openalpr/cjson.h"
#include "support/tinythread.h"
#include "videobuffer.h"
#include "uuid.h"
#include <curl/curl.h>

// prototypes
void streamRecognitionThread(void* arg);
bool writeToQueue(std::string jsonResult);
bool uploadPost(std::string url, std::string data);
void dataUploadThread(void* arg);

// Constants
const std::string DEFAULT_LOG_FILE_PATH="/var/log/openalpr.log";
const std::string WTS_CONFIG_FILE_PATH="/etc/openalpr/wts.conf";

const std::string BEANSTALK_QUEUE_HOST="127.0.0.1";
const int BEANSTALK_PORT=11300;
const std::string BEANSTALK_TUBE_NAME="alprd";

struct CaptureThreadData
{
  std::string stream_url;
  std::string site_id;
  int camera_id;

  std::string config_file;
  std::string country_code;
  std::string output_image_folder;
};

struct UploadThreadData
{
  std::string upload_url;
};

bool daemon_active;

int main( int argc, const char** argv )
{
  daemon_active = true;

  bool noDaemon = false;
  std::string logFile;
  int topn;

  std::string configFile;
  std::string country;

  TCLAP::CmdLine cmd("OpenAlpr Daemon", ' ', Alpr::getVersion());

  TCLAP::ValueArg<std::string> countryCodeArg("c","country","Country code to identify (either us for USA or eu for Europe).  Default=us",false, "us" ,"country_code");
  TCLAP::ValueArg<std::string> configFileArg("","config","Path to the openalpr.conf file.",false, "" ,"config_file");
  TCLAP::ValueArg<int> topNArg("n","topn","Max number of possible plate numbers to return.  Default=10",false, 10 ,"topN");
  TCLAP::ValueArg<std::string> logFileArg("l","log","Log file to write to.  Default=" + DEFAULT_LOG_FILE_PATH,false, DEFAULT_LOG_FILE_PATH ,"topN");

  TCLAP::SwitchArg daemonOffSwitch("f","foreground","Set this flag for debugging.  Disables forking the process as a daemon and runs in the foreground.  Default=off", cmd, false);

  try
  {

    cmd.add( topNArg );
    cmd.add( configFileArg );
    cmd.add( logFileArg );

    if (cmd.parse( argc, argv ) == false)
    {
      // Error occured while parsing.  Exit now.
      return 1;
    }

    country = countryCodeArg.getValue();
    configFile = configFileArg.getValue();
    logFile = logFileArg.getValue();
    topn = topNArg.getValue();
    noDaemon = daemonOffSwitch.getValue();
  }
  catch (TCLAP::ArgException &e)    // catch any exceptions
  {
    std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;
    return 1;
  }

  if (noDaemon == false)
  {
    // Fork off into a separate daemon
    daemon(0, 0);

    // Redirect std out to log file

    std::ofstream out(logFile.c_str());
    std::cout.rdbuf(out.rdbuf());
    std::cerr.rdbuf(out.rdbuf());

    std::cout << "Running OpenALPR daemon in daemon mode." << std::endl;
  }
  else
  {
    std::cout << "Running OpenALPR daemon in the foreground" << std::endl;
  }

  CSimpleIniA ini;
  ini.SetMultiKey();

  ini.LoadFile(WTS_CONFIG_FILE_PATH.c_str());

  std::vector<std::string> stream_urls;

  CSimpleIniA::TNamesDepend values;
  ini.GetAllValues("daemon", "stream", values);

  // sort the values into the original load order
  values.sort(CSimpleIniA::Entry::LoadOrder());

  // output all of the items
  CSimpleIniA::TNamesDepend::const_iterator i;
  for (i = values.begin(); i != values.end(); ++i) {
      stream_urls.push_back(i->pItem);
  }

  if (stream_urls.size() == 0)
  {
    std::cout << "No video streams defined in the configuration" << std::endl;
    return 1;
  }

  std::string imageFolder = ini.GetValue("daemon", "image_folder", "/tmp/");
  std::string upload_url = ini.GetValue("daemon", "upload_address", "");
  std::string site_id = ini.GetValue("daemon", "site_id", "");

  std::cout << "Using: " << imageFolder << " for storing valid plate images" << std::endl;

  for (int i = 0; i < stream_urls.size(); i++)
  {
    CaptureThreadData* tdata = new CaptureThreadData();
    tdata->stream_url = stream_urls[i];
    tdata->camera_id = i + 1;
    tdata->config_file = configFile;
    tdata->output_image_folder = imageFolder;
    tdata->country_code = country;
    tdata->site_id = site_id;

    tthread::thread* t = new tthread::thread(streamRecognitionThread, (void*) tdata);
  }

  // Kick off the data upload thread
  UploadThreadData* udata = new UploadThreadData();
  udata->upload_url = upload_url;
  tthread::thread* t = new tthread::thread(dataUploadThread, (void*) udata );

  while (daemon_active)
  {
    usleep(30000);
  }

}

void streamRecognitionThread(void* arg)
{
  CaptureThreadData* tdata = (CaptureThreadData*) arg;

  std::cout << "country: " << tdata->country_code << " -- config file: " << tdata->config_file << std::endl;
  std::cout << "Stream " << tdata->camera_id << ": " << tdata->stream_url << std::endl;

  Alpr alpr(tdata->country_code, tdata->config_file);

  int framenum = 0;

  VideoBuffer videoBuffer;

  videoBuffer.connect(tdata->stream_url, 5);

  cv::Mat latestFrame;

  std::vector<uchar> buffer;

  std::cout << "Daemon active: " << daemon_active << std::endl;

  while (daemon_active)
  {
    int response = videoBuffer.getLatestFrame(&latestFrame);

    if (response != -1)
    {
      cv::imencode(".bmp", latestFrame, buffer );
      std::vector<AlprResult> results = alpr.recognize(buffer);

      if (results.size() > 0)
      {
	// Create a UUID for the image
	std::string uuid = newUUID();

	// Save the image to disk (using the UUID)
	std::stringstream ss;
	ss << tdata->output_image_folder << "/" << uuid << ".jpg";

	cv::imwrite(ss.str(), latestFrame);

	// Update the JSON content to include UUID and camera ID
	cJSON *root;

	root=cJSON_CreateObject();

	std::string json = alpr.toJson(results);

	cJSON *array = cJSON_Parse(json.c_str());
	cJSON_AddStringToObject(root,	"uuid",		uuid.c_str());
	cJSON_AddNumberToObject(root,	"camera_id",	tdata->camera_id);
	cJSON_AddStringToObject(root, "site_id", 	tdata->site_id.c_str());
	cJSON_AddNumberToObject(root,	"img_width",	latestFrame.cols);
	cJSON_AddNumberToObject(root,	"img_height",	latestFrame.rows);
	cJSON_AddItemToObject(root, 	"results", 	array);

	char *out;
	out=cJSON_PrintUnformatted(root);
	cJSON_Delete(root);

	std::string response(out);

	free(out);

	// Push the results to the Beanstalk queue
	writeToQueue(response);
      }
    }

    usleep(10000);
  }

  videoBuffer.disconnect();

  std::cout << "Video processing ended" << std::endl;

  delete tdata;
}

bool writeToQueue(std::string jsonResult)
{

    Beanstalk::Client client(BEANSTALK_QUEUE_HOST, BEANSTALK_PORT);
    client.use(BEANSTALK_TUBE_NAME);

    int id = client.put(jsonResult);

    if (id <= 0)
      return false;

    std::cout << "put job id: " << id << std::endl;

    return true;
}

void dataUploadThread(void* arg)
{

  /* In windows, this will init the winsock stuff */
  curl_global_init(CURL_GLOBAL_ALL);

  UploadThreadData* udata = (UploadThreadData*) arg;

  Beanstalk::Client client(BEANSTALK_QUEUE_HOST, BEANSTALK_PORT);

  client.watch(BEANSTALK_TUBE_NAME);

  while(daemon_active)
  {
    Beanstalk::Job job;

    client.reserve(job);

    if (job.id() > 0)
    {
      //std::cout << job.body() << std::endl;
      if (uploadPost(udata->upload_url, job.body()))
      {
	client.del(job.id());
	std::cout << "Job: " << job.id() << " successfully uploaded" << std::endl;
      }
      else
      {
	client.release(job);
	std::cout << "Job: " << job.id() << " failed to upload.  Will retry." << std::endl;
      }
    }

    usleep(10000);
  }

  curl_global_cleanup();
}

bool uploadPost(std::string url, std::string data)
{
  bool success = true;
  CURL *curl;
  CURLcode res;

  /* get a curl handle */
  curl = curl_easy_init();
  if(curl) {
    /* First set the URL that is about to receive our POST. This URL can
       just as well be a https:// URL if that is what should receive the
       data. */
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    /* Now specify the POST data */
    //char* escaped_data = curl_easy_escape(curl, data.c_str(), data.length());
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
    //curl_free(escaped_data);

    /* Perform the request, res will get the return code */
    res = curl_easy_perform(curl);
    /* Check for errors */
    if(res != CURLE_OK)
    {
      success = false;
    }

    /* always cleanup */
    curl_easy_cleanup(curl);
  }

  return success;

}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011, Ben Noordhuis <info@bnoordhuis.nl>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <stdlib.h>
#include "node.h"
#include "nan.h"

using namespace v8;
using namespace node;

namespace {

typedef struct proxy_container {
  Persistent<Object> proxy;
  Persistent<Object> target;
  Persistent<Array>  callbacks;
} proxy_container;

Persistent<ObjectTemplate> proxyClass;

bool IsDead(Handle<Object> proxy) {
  assert(proxy->InternalFieldCount() == 1);
  proxy_container *cont = reinterpret_cast<proxy_container*>(
    NanGetInternalFieldPointer(proxy, 0)
  );
  return cont == NULL || cont->target.IsEmpty();
}

Handle<Object> Unwrap(Handle<Object> proxy) {
  assert(!IsDead(proxy));
  proxy_container *cont = reinterpret_cast<proxy_container*>(
    NanGetInternalFieldPointer(proxy, 0)
  );
  return NanPersistentToLocal(cont->target);
}

Handle<Array> GetCallbacks(Handle<Object> proxy) {
  proxy_container *cont = reinterpret_cast<proxy_container*>(
    NanGetInternalFieldPointer(proxy, 0)
  );
  assert(cont != NULL);
  return NanPersistentToLocal(cont->callbacks);
}

#define UNWRAP                            \
  NanScope();                             \
  Handle<Object> obj;                     \
  const bool dead = IsDead(args.This());  \
  if (!dead) obj = Unwrap(args.This());   \

NAN_PROPERTY_GETTER(WeakNamedPropertyGetter) {
  UNWRAP
  NanReturnValue(dead ? Local<Value>() : obj->Get(property));
}

NAN_PROPERTY_SETTER(WeakNamedPropertySetter) {
  UNWRAP
  if (!dead) obj->Set(property, value);
  NanReturnValue(value);
}

NAN_PROPERTY_QUERY(WeakNamedPropertyQuery) {
  NanScope();
  NanReturnValue(Integer::New(None));
}

NAN_PROPERTY_DELETER(WeakNamedPropertyDeleter) {
  UNWRAP
  NanReturnValue(Boolean::New(!dead && obj->Delete(property)));
}

NAN_INDEX_GETTER(WeakIndexedPropertyGetter) {
  UNWRAP
  NanReturnValue(dead ? Local<Value>() : obj->Get(index));
}

NAN_INDEX_SETTER(WeakIndexedPropertySetter) {
  UNWRAP
  if (!dead) obj->Set(index, value);
  NanReturnValue(value);
}

NAN_INDEX_QUERY(WeakIndexedPropertyQuery) {
  NanScope();
  NanReturnValue(Integer::New(None));
}

NAN_INDEX_DELETER(WeakIndexedPropertyDeleter) {
  UNWRAP
  NanReturnValue(Boolean::New(!dead && obj->Delete(index)));
}

NAN_PROPERTY_ENUMERATOR(WeakPropertyEnumerator) {
  UNWRAP
  NanReturnValue(dead ? Array::New(0) : obj->GetPropertyNames());
}

void AddCallback(Handle<Object> proxy, Handle<Function> callback) {
  Handle<Array> callbacks = GetCallbacks(proxy);
  callbacks->Set(Integer::New(callbacks->Length()), callback);
}

NAN_WEAK_CALLBACK(void*, TargetCallback) {
  NanScope();

  assert(NAN_WEAK_CALLBACK_OBJECT.IsNearDeath());
  void* arg = NAN_WEAK_CALLBACK_DATA(void *);

  proxy_container *cont = reinterpret_cast<proxy_container*>(arg);

  // invoke any listening callbacks
  uint32_t len = NanPersistentToLocal(cont->callbacks)->Length();
  Handle<Value> callbackArgs[] = {
    NanPersistentToLocal(NAN_WEAK_CALLBACK_OBJECT)
  };

  for (uint32_t i=0; i<len; i++) {

    Handle<Function> cb = Handle<Function>::Cast(
        NanPersistentToLocal(cont->callbacks)->Get(Integer::New(i)));

    TryCatch try_catch;

    cb->Call(NanPersistentToLocal(NAN_WEAK_CALLBACK_OBJECT)->ToObject(), 1, callbackArgs);

    if (try_catch.HasCaught()) {
      FatalException(try_catch);
    }
  }

  // clean everything up
  NanSetInternalFieldPointer(NanPersistentToLocal(cont->proxy), 0, NULL);
  NanDispose(cont->proxy);
  NanDispose(cont->target);
  NanDispose(cont->callbacks);
  free(cont);
}

NAN_METHOD(Create) {
  NanScope();

  if (!args[0]->IsObject()) {
    return NanThrowTypeError("Object expected");
  }

  proxy_container *cont = (proxy_container *)
    malloc(sizeof(proxy_container));

  NanAssignPersistent(Object, cont->target, args[0]->ToObject());
  NanAssignPersistent(Array, cont->callbacks, Array::New());
  NanAssignPersistent(Object, cont->proxy, NanPersistentToLocal(proxyClass)->NewInstance());
  NanSetInternalFieldPointer(NanPersistentToLocal(cont->proxy), 0, cont);

  NanMakeWeak(cont->target, reinterpret_cast<void *>(cont), TargetCallback);

  if (args.Length() >= 2) {
    AddCallback(NanPersistentToLocal(cont->proxy), Handle<Function>::Cast(args[1]));
  }

  NanReturnValue(cont->proxy);
}

/**
 * TODO: Make this better.
 */

bool isWeakRef (Handle<Value> val) {
  return val->IsObject() && val->ToObject()->InternalFieldCount() == 1;
}

NAN_METHOD(IsWeakRef) {
  NanScope();
  NanReturnValue(Boolean::New(isWeakRef(args[0])));
}

NAN_METHOD(Get) {
  NanScope();

  if (!isWeakRef(args[0])) {
    return NanThrowTypeError("Weakref instance expected");
  }
  Local<Object> proxy = args[0]->ToObject();

  const bool dead = IsDead(proxy);
  if (dead) NanReturnUndefined();

  Handle<Object> obj = Unwrap(proxy);
  NanReturnValue(obj);
}

NAN_METHOD(IsNearDeath) {
  NanScope();

  if (!isWeakRef(args[0])) {
    return NanThrowTypeError("Weakref instance expected");
  }
  Local<Object> proxy = args[0]->ToObject();

  proxy_container *cont = reinterpret_cast<proxy_container*>(
    NanGetInternalFieldPointer(proxy, 0)
  );
  assert(cont != NULL);

  Handle<Boolean> rtn = Boolean::New(cont->target.IsNearDeath());

  NanReturnValue(rtn);
}

NAN_METHOD(IsDead) {
  NanScope();

  if (!isWeakRef(args[0])) {
    return NanThrowTypeError("Weakref instance expected");
  }
  Local<Object> proxy = args[0]->ToObject();

  const bool dead = IsDead(proxy);
  NanReturnValue(Boolean::New(dead));
}

NAN_METHOD(AddCallback) {
  NanScope();

  if (!isWeakRef(args[0])) {
    return NanThrowTypeError("Weakref instance expected");
  }
  Local<Object> proxy = args[0]->ToObject();

  AddCallback(proxy, Handle<Function>::Cast(args[1]));

  NanReturnUndefined();
}

NAN_METHOD(Callbacks) {
  NanScope();

  if (!isWeakRef(args[0])) {
    return NanThrowTypeError("Weakref instance expected");
  }
  Local<Object> proxy = args[0]->ToObject();

  NanReturnValue(GetCallbacks(proxy));
}

void Initialize(Handle<Object> exports) {
  NanScope();

  Handle<ObjectTemplate> p = ObjectTemplate::New();
  NanAssignPersistent(ObjectTemplate, proxyClass, p);
  p->SetNamedPropertyHandler(WeakNamedPropertyGetter,
                             WeakNamedPropertySetter,
                             WeakNamedPropertyQuery,
                             WeakNamedPropertyDeleter,
                             WeakPropertyEnumerator);
  p->SetIndexedPropertyHandler(WeakIndexedPropertyGetter,
                               WeakIndexedPropertySetter,
                               WeakIndexedPropertyQuery,
                               WeakIndexedPropertyDeleter,
                               WeakPropertyEnumerator);
  p->SetInternalFieldCount(1);

  NODE_SET_METHOD(exports, "get", Get);
  NODE_SET_METHOD(exports, "create", Create);
  NODE_SET_METHOD(exports, "isWeakRef", IsWeakRef);
  NODE_SET_METHOD(exports, "isNearDeath", IsNearDeath);
  NODE_SET_METHOD(exports, "isDead", IsDead);
  NODE_SET_METHOD(exports, "callbacks", Callbacks);
  NODE_SET_METHOD(exports, "addCallback", AddCallback);
}

} // anonymous namespace

NODE_MODULE(weakref, Initialize);
<commit_msg>weakref: add comment<commit_after>/*
 * Copyright (c) 2011, Ben Noordhuis <info@bnoordhuis.nl>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <stdlib.h>
#include "node.h"
#include "nan.h"

using namespace v8;
using namespace node;

namespace {

typedef struct proxy_container {
  Persistent<Object> proxy;
  Persistent<Object> target;
  Persistent<Array>  callbacks;
} proxy_container;

Persistent<ObjectTemplate> proxyClass;

bool IsDead(Handle<Object> proxy) {
  assert(proxy->InternalFieldCount() == 1);
  proxy_container *cont = reinterpret_cast<proxy_container*>(
    NanGetInternalFieldPointer(proxy, 0)
  );
  return cont == NULL || cont->target.IsEmpty();
}

Handle<Object> Unwrap(Handle<Object> proxy) {
  assert(!IsDead(proxy));
  proxy_container *cont = reinterpret_cast<proxy_container*>(
    NanGetInternalFieldPointer(proxy, 0)
  );
  return NanPersistentToLocal(cont->target);
}

Handle<Array> GetCallbacks(Handle<Object> proxy) {
  proxy_container *cont = reinterpret_cast<proxy_container*>(
    NanGetInternalFieldPointer(proxy, 0)
  );
  assert(cont != NULL);
  return NanPersistentToLocal(cont->callbacks);
}

#define UNWRAP                            \
  NanScope();                             \
  Handle<Object> obj;                     \
  const bool dead = IsDead(args.This());  \
  if (!dead) obj = Unwrap(args.This());   \

NAN_PROPERTY_GETTER(WeakNamedPropertyGetter) {
  UNWRAP
  NanReturnValue(dead ? Local<Value>() : obj->Get(property));
}

NAN_PROPERTY_SETTER(WeakNamedPropertySetter) {
  UNWRAP
  if (!dead) obj->Set(property, value);
  NanReturnValue(value);
}

NAN_PROPERTY_QUERY(WeakNamedPropertyQuery) {
  NanScope();
  NanReturnValue(Integer::New(None));
}

NAN_PROPERTY_DELETER(WeakNamedPropertyDeleter) {
  UNWRAP
  NanReturnValue(Boolean::New(!dead && obj->Delete(property)));
}

NAN_INDEX_GETTER(WeakIndexedPropertyGetter) {
  UNWRAP
  NanReturnValue(dead ? Local<Value>() : obj->Get(index));
}

NAN_INDEX_SETTER(WeakIndexedPropertySetter) {
  UNWRAP
  if (!dead) obj->Set(index, value);
  NanReturnValue(value);
}

NAN_INDEX_QUERY(WeakIndexedPropertyQuery) {
  NanScope();
  NanReturnValue(Integer::New(None));
}

NAN_INDEX_DELETER(WeakIndexedPropertyDeleter) {
  UNWRAP
  NanReturnValue(Boolean::New(!dead && obj->Delete(index)));
}

/**
 * Only one "enumerator" function needs to be defined. This function is used for
 * both the property and indexed enumerator functions.
 */

NAN_PROPERTY_ENUMERATOR(WeakPropertyEnumerator) {
  UNWRAP
  NanReturnValue(dead ? Array::New(0) : obj->GetPropertyNames());
}

void AddCallback(Handle<Object> proxy, Handle<Function> callback) {
  Handle<Array> callbacks = GetCallbacks(proxy);
  callbacks->Set(Integer::New(callbacks->Length()), callback);
}

NAN_WEAK_CALLBACK(void*, TargetCallback) {
  NanScope();

  assert(NAN_WEAK_CALLBACK_OBJECT.IsNearDeath());
  void* arg = NAN_WEAK_CALLBACK_DATA(void *);

  proxy_container *cont = reinterpret_cast<proxy_container*>(arg);

  // invoke any listening callbacks
  uint32_t len = NanPersistentToLocal(cont->callbacks)->Length();
  Handle<Value> callbackArgs[] = {
    NanPersistentToLocal(NAN_WEAK_CALLBACK_OBJECT)
  };

  for (uint32_t i=0; i<len; i++) {

    Handle<Function> cb = Handle<Function>::Cast(
        NanPersistentToLocal(cont->callbacks)->Get(Integer::New(i)));

    TryCatch try_catch;

    cb->Call(NanPersistentToLocal(NAN_WEAK_CALLBACK_OBJECT)->ToObject(), 1, callbackArgs);

    if (try_catch.HasCaught()) {
      FatalException(try_catch);
    }
  }

  // clean everything up
  NanSetInternalFieldPointer(NanPersistentToLocal(cont->proxy), 0, NULL);
  NanDispose(cont->proxy);
  NanDispose(cont->target);
  NanDispose(cont->callbacks);
  free(cont);
}

NAN_METHOD(Create) {
  NanScope();

  if (!args[0]->IsObject()) {
    return NanThrowTypeError("Object expected");
  }

  proxy_container *cont = (proxy_container *)
    malloc(sizeof(proxy_container));

  NanAssignPersistent(Object, cont->target, args[0]->ToObject());
  NanAssignPersistent(Array, cont->callbacks, Array::New());
  NanAssignPersistent(Object, cont->proxy, NanPersistentToLocal(proxyClass)->NewInstance());
  NanSetInternalFieldPointer(NanPersistentToLocal(cont->proxy), 0, cont);

  NanMakeWeak(cont->target, reinterpret_cast<void *>(cont), TargetCallback);

  if (args.Length() >= 2) {
    AddCallback(NanPersistentToLocal(cont->proxy), Handle<Function>::Cast(args[1]));
  }

  NanReturnValue(cont->proxy);
}

/**
 * TODO: Make this better.
 */

bool isWeakRef (Handle<Value> val) {
  return val->IsObject() && val->ToObject()->InternalFieldCount() == 1;
}

NAN_METHOD(IsWeakRef) {
  NanScope();
  NanReturnValue(Boolean::New(isWeakRef(args[0])));
}

NAN_METHOD(Get) {
  NanScope();

  if (!isWeakRef(args[0])) {
    return NanThrowTypeError("Weakref instance expected");
  }
  Local<Object> proxy = args[0]->ToObject();

  const bool dead = IsDead(proxy);
  if (dead) NanReturnUndefined();

  Handle<Object> obj = Unwrap(proxy);
  NanReturnValue(obj);
}

NAN_METHOD(IsNearDeath) {
  NanScope();

  if (!isWeakRef(args[0])) {
    return NanThrowTypeError("Weakref instance expected");
  }
  Local<Object> proxy = args[0]->ToObject();

  proxy_container *cont = reinterpret_cast<proxy_container*>(
    NanGetInternalFieldPointer(proxy, 0)
  );
  assert(cont != NULL);

  Handle<Boolean> rtn = Boolean::New(cont->target.IsNearDeath());

  NanReturnValue(rtn);
}

NAN_METHOD(IsDead) {
  NanScope();

  if (!isWeakRef(args[0])) {
    return NanThrowTypeError("Weakref instance expected");
  }
  Local<Object> proxy = args[0]->ToObject();

  const bool dead = IsDead(proxy);
  NanReturnValue(Boolean::New(dead));
}

NAN_METHOD(AddCallback) {
  NanScope();

  if (!isWeakRef(args[0])) {
    return NanThrowTypeError("Weakref instance expected");
  }
  Local<Object> proxy = args[0]->ToObject();

  AddCallback(proxy, Handle<Function>::Cast(args[1]));

  NanReturnUndefined();
}

NAN_METHOD(Callbacks) {
  NanScope();

  if (!isWeakRef(args[0])) {
    return NanThrowTypeError("Weakref instance expected");
  }
  Local<Object> proxy = args[0]->ToObject();

  NanReturnValue(GetCallbacks(proxy));
}

void Initialize(Handle<Object> exports) {
  NanScope();

  Handle<ObjectTemplate> p = ObjectTemplate::New();
  NanAssignPersistent(ObjectTemplate, proxyClass, p);
  p->SetNamedPropertyHandler(WeakNamedPropertyGetter,
                             WeakNamedPropertySetter,
                             WeakNamedPropertyQuery,
                             WeakNamedPropertyDeleter,
                             WeakPropertyEnumerator);
  p->SetIndexedPropertyHandler(WeakIndexedPropertyGetter,
                               WeakIndexedPropertySetter,
                               WeakIndexedPropertyQuery,
                               WeakIndexedPropertyDeleter,
                               WeakPropertyEnumerator);
  p->SetInternalFieldCount(1);

  NODE_SET_METHOD(exports, "get", Get);
  NODE_SET_METHOD(exports, "create", Create);
  NODE_SET_METHOD(exports, "isWeakRef", IsWeakRef);
  NODE_SET_METHOD(exports, "isNearDeath", IsNearDeath);
  NODE_SET_METHOD(exports, "isDead", IsDead);
  NODE_SET_METHOD(exports, "callbacks", Callbacks);
  NODE_SET_METHOD(exports, "addCallback", AddCallback);
}

} // anonymous namespace

NODE_MODULE(weakref, Initialize);
<|endoftext|>


<commit_before>#include "window.h"
#include <SDL2/SDL.h>
#include <GL/glew.h>

Window::Window(int width, int height, const std::string& title) :
	m_width(width),
	m_height(height),
	m_title(title),
	m_input(this),
	m_isCloseRequested(false)
{
	SDL_Init(SDL_INIT_EVERYTHING);

	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE,32);
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,16);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);

	m_window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL);
	m_glContext = SDL_GL_CreateContext(m_window);

	//SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1");
	SDL_GL_SetSwapInterval(1);

	GLenum res = glewInit();
	if(res != GLEW_OK)
	{
		fprintf(stderr, "Error: '%s'\n", glewGetErrorString(res));
	}
}

Window::~Window()
{
	SDL_GL_DeleteContext(m_glContext);
	SDL_DestroyWindow(m_window);
	SDL_Quit();
}

void Window::Update()
{
	for(int i = 0; i < Input::NUM_MOUSEBUTTONS; i++)
	{
		m_input.SetMouseDown(i, false);
		m_input.SetMouseUp(i, false);
	}

	for(int i = 0; i < Input::NUM_KEYS; i++)
	{
		m_input.SetKeyDown(i, false);
		m_input.SetKeyUp(i, false);
	}

	SDL_Event e;
	while(SDL_PollEvent(&e))
	{
		if(e.type == SDL_QUIT)
		{
			m_isCloseRequested = true;
		}

		if(e.type == SDL_MOUSEMOTION)
		{
			m_input.SetMouseX(e.motion.x);
			m_input.SetMouseY(e.motion.y);
		}

		if(e.type == SDL_KEYDOWN)
		{
			int value = e.key.keysym.scancode;

			m_input.SetKey(value, true);
			m_input.SetKeyDown(value, true);
		}
		if(e.type == SDL_KEYUP)
		{
			int value = e.key.keysym.scancode;

			m_input.SetKey(value, false);
			m_input.SetKeyUp(value, true);
		}
		if(e.type == SDL_MOUSEBUTTONDOWN)
		{
			int value = e.button.button;

			m_input.SetMouse(value, true);
			m_input.SetMouseDown(value, true);
		}
		if(e.type == SDL_MOUSEBUTTONUP)
		{
			int value = e.button.button;

			m_input.SetMouse(value, false);
			m_input.SetMouseUp(value, true);
		}
	}
}

void Window::SwapBuffers()
{
	SDL_GL_SwapWindow(m_window);
}

void Window::BindAsRenderTarget() const
{
	glBindTexture(GL_TEXTURE_2D,0);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	glViewport(0, 0, GetWidth(), GetHeight());
}

void Window::SetFullScreen(bool value)
{
	int mode = 0;
	if(value)
		mode = SDL_WINDOW_FULLSCREEN;
	else
		mode = 0;

	SDL_SetWindowFullscreen(m_window, mode);
}

<commit_msg>Possibly fixed issue for some things<commit_after>#include "window.h"
#include <SDL2/SDL.h>
#include <GL/glew.h>

Window::Window(int width, int height, const std::string& title) :
	m_width(width),
	m_height(height),
	m_title(title),
	m_input(this),
	m_isCloseRequested(false)
{
	SDL_Init(SDL_INIT_EVERYTHING);

	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE,32);
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,16);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);

	m_window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL);
	m_glContext = SDL_GL_CreateContext(m_window);

	//SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1");
	SDL_GL_SetSwapInterval(1);

	//Apparently this is necessary to build with Xcode
	glewExperimental = GL_TRUE;

	GLenum res = glewInit();
	if(res != GLEW_OK)
	{
		fprintf(stderr, "Error: '%s'\n", glewGetErrorString(res));
	}
}

Window::~Window()
{
	SDL_GL_DeleteContext(m_glContext);
	SDL_DestroyWindow(m_window);
	SDL_Quit();
}

void Window::Update()
{
	for(int i = 0; i < Input::NUM_MOUSEBUTTONS; i++)
	{
		m_input.SetMouseDown(i, false);
		m_input.SetMouseUp(i, false);
	}

	for(int i = 0; i < Input::NUM_KEYS; i++)
	{
		m_input.SetKeyDown(i, false);
		m_input.SetKeyUp(i, false);
	}

	SDL_Event e;
	while(SDL_PollEvent(&e))
	{
		if(e.type == SDL_QUIT)
		{
			m_isCloseRequested = true;
		}

		if(e.type == SDL_MOUSEMOTION)
		{
			m_input.SetMouseX(e.motion.x);
			m_input.SetMouseY(e.motion.y);
		}

		if(e.type == SDL_KEYDOWN)
		{
			int value = e.key.keysym.scancode;

			m_input.SetKey(value, true);
			m_input.SetKeyDown(value, true);
		}
		if(e.type == SDL_KEYUP)
		{
			int value = e.key.keysym.scancode;

			m_input.SetKey(value, false);
			m_input.SetKeyUp(value, true);
		}
		if(e.type == SDL_MOUSEBUTTONDOWN)
		{
			int value = e.button.button;

			m_input.SetMouse(value, true);
			m_input.SetMouseDown(value, true);
		}
		if(e.type == SDL_MOUSEBUTTONUP)
		{
			int value = e.button.button;

			m_input.SetMouse(value, false);
			m_input.SetMouseUp(value, true);
		}
	}
}

void Window::SwapBuffers()
{
	SDL_GL_SwapWindow(m_window);
}

void Window::BindAsRenderTarget() const
{
	glBindTexture(GL_TEXTURE_2D,0);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	glViewport(0, 0, GetWidth(), GetHeight());
}

void Window::SetFullScreen(bool value)
{
	int mode = 0;
	if(value)
		mode = SDL_WINDOW_FULLSCREEN;
	else
		mode = 0;

	SDL_SetWindowFullscreen(m_window, mode);
}

<|endoftext|>