newtx/sdk/base/ui.cpp

232 lines
6.4 KiB
C++
Raw Normal View History

#include "ui.h"
#include "utils.h"
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ipc class
namespace devui
{
class ui_messenger
{
std::function<void(LPMSGSTREAM)> cb_;
safe_fifo<std::string> sent_que_;
volatile bool run_ = true;
bool ui_;
bool ready_ = true;
safe_thread workers_;
int fdo_ = -1;
int fdi_ = -1;
std::string fmode(int m)
{
if(m == O_RDONLY)
return "O_RDONLY";
if(m == O_WRONLY)
return "O_WRONLY";
return "Unk";
}
void init(void)
{
const char* fifo[] = {"/tmp/worker", "/tmp/ui"};
int mode[] = {O_RDONLY, O_WRONLY};
int *fd[] = {&fdi_, &fdo_};
if(ui_)
{
mkfifo(fifo[!ui_], 0777);
mkfifo(fifo[ui_], 0777);
fdo_ = open(fifo[1], mode[1]);
fdi_ = open(fifo[0], mode[0]);
}
else
{
fdi_ = open(fifo[1], mode[0]);
fdo_ = open(fifo[0], mode[1]);
}
if(fdo_ == -1 || fdi_ == -1)
{
printf("Out fd = %d, In fd = %d\n", fdo_, fdi_);
this->close();
}
else
{
auto r = [this](void) -> void
{
receiver();
};
auto s = [this](void) -> void
{
sender();
};
workers_.start(r, "receiver");
workers_.start(s, "sender");
}
}
void close(void)
{
ready_ = false;
if(fdo_ != -1)
::close(fdo_);
if(fdi_ != -1)
::close(fdi_);
fdi_ = fdo_ = -1;
}
void receiver(void)
{
std::string rcv("");
char buf[300] = {0};
LPMSGSTREAM pack = nullptr;
printf("ui-receiver running ...\n");
while(run_)
{
int r = read(fdi_, buf, _countof(buf));
if(r == -1)
{
printf("Read UI message failed: %d(%s)\n", errno, strerror(errno));
utils::to_log(LOG_LEVEL_FATAL, "Read UI message failed: %d(%s)\n", errno, strerror(errno));
this->close();
break;
}
if(rcv.length())
{
rcv += std::string(buf, r);
pack = (LPMSGSTREAM)&rcv[0];
if(pack->whole_size() <= rcv.length())
{
cb_(pack);
rcv.erase(0, pack->whole_size());
}
}
else
{
int off = 0;
pack = (LPMSGSTREAM)buf;
if(pack->whole_size() <= r)
{
cb_(pack);
off = pack->whole_size();
}
if(off < r)
{
rcv = std::string(buf + off, r - off);
}
}
}
printf("ui-receiver exited.\n");
}
void sender(void)
{
printf("ui-sender running ...\n");
while(run_)
{
std::string cont("");
if(sent_que_.take(cont, true))
{
int s = 0, off = 0;
do
{
s = write(fdo_, cont.c_str() + off, cont.length() - off);
if(s == -1)
{
printf("Send UI message failed: %d(%s)\n", errno, strerror(errno));
utils::to_log(LOG_LEVEL_FATAL, "Send UI message failed: %d(%s)\n", errno, strerror(errno));
this->close();
break;
}
off += s;
}while(off < cont.length());
if(s == -1)
break;
}
}
printf("ui-sender exited.\n");
}
public:
ui_messenger(std::function<void(LPMSGSTREAM)> uicb
, bool ui) : sent_que_("ui-sent-que")
, cb_(uicb), ui_(ui)
{
sent_que_.enable_wait_log(false);
init();
}
~ui_messenger()
{
close();
}
public:
bool send(std::string& msg)
{
if(ready_)
sent_que_.save(msg, true);
return ready_;
}
void stop(void)
{
sent_que_.trigger();
run_ = false;
this->close();
}
};
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// interface
static MUTEX msg_lk_;
static devui::ui_messenger *msgr = nullptr;
namespace devui
{
void init_ui(std::function<void(LPMSGSTREAM)> uicb, bool ui)
{
SIMPLE_LOCK(msg_lk_);
if(!msgr)
msgr = new ui_messenger(uicb, ui);
}
void uninit_ui(void)
{
SIMPLE_LOCK(msg_lk_);
if(msgr)
{
msgr->stop();
delete msgr;
}
msgr = nullptr;
}
bool send_message(uint32_t msgid, uint8_t* data, uint8_t size)
{
std::string stream("");
MSGSTREAM pack;
bool ret = false;
memset(&pack, 0, sizeof(pack));
pack.ver = 1;
pack.msg = msgid;
pack.size = size;
if(size)
pack.data[0] = data[0];
stream = std::string((char*)&pack, sizeof(pack));
if(size > 1)
stream += std::string((char*)data + 1, size - 1);
{
SIMPLE_LOCK(msg_lk_);
if(msgr)
ret = msgr->send(stream);
}
return ret;
}
};