chore: CRLF to LF

This commit is contained in:
smpn2
2022-12-16 23:18:35 +09:00
parent b7a60638a4
commit 6c914266d9
725 changed files with 131020 additions and 131020 deletions
+82 -82
View File
@@ -1,82 +1,82 @@
#pragma once
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include <winsock2.h>
#include "util/rc4.h"
#include "module.h"
#include "websocket.h"
#include "serial.h"
namespace api {
struct ClientState {
SOCKADDR_IN address;
SOCKET socket;
bool close = false;
std::vector<Module*> modules;
std::string password;
bool password_change = false;
util::RC4 *cipher = nullptr;
};
class Controller {
private:
// configuration
const static int server_backlog = 16;
const static int server_receive_buffer_size = 64 * 1024;
const static int server_message_buffer_max_size = 64 * 1024;
const static int server_worker_count = 2;
const static int server_connection_limit = 4096;
// settings
unsigned short port;
std::string password;
bool pretty;
// server
WebSocketController *websocket;
std::vector<SerialController *> serial;
std::vector<std::thread> server_workers;
std::vector<std::thread> server_handlers;
std::mutex server_handlers_m;
std::vector<api::ClientState *> client_states;
std::mutex client_states_m;
SOCKET server;
void server_worker();
void connection_handler(ClientState client_state);
public:
// state
bool server_running;
// constructor / destructor
Controller(unsigned short port, std::string password, bool pretty);
~Controller();
void listen_serial(std::string port, DWORD baud);
bool process_request(ClientState *state, std::vector<char> *in, std::vector<char> *out);
bool process_request(ClientState *state, const char *in, size_t in_size, std::vector<char> *out);
static void process_password_change(ClientState *state);
void init_state(ClientState *state);
static void free_state(ClientState *state);
void free_socket();
void obtain_client_states(std::vector<ClientState> *output);
std::string get_ip_address(sockaddr_in addr);
inline const std::string &get_password() const {
return this->password;
}
};
}
#pragma once
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include <winsock2.h>
#include "util/rc4.h"
#include "module.h"
#include "websocket.h"
#include "serial.h"
namespace api {
struct ClientState {
SOCKADDR_IN address;
SOCKET socket;
bool close = false;
std::vector<Module*> modules;
std::string password;
bool password_change = false;
util::RC4 *cipher = nullptr;
};
class Controller {
private:
// configuration
const static int server_backlog = 16;
const static int server_receive_buffer_size = 64 * 1024;
const static int server_message_buffer_max_size = 64 * 1024;
const static int server_worker_count = 2;
const static int server_connection_limit = 4096;
// settings
unsigned short port;
std::string password;
bool pretty;
// server
WebSocketController *websocket;
std::vector<SerialController *> serial;
std::vector<std::thread> server_workers;
std::vector<std::thread> server_handlers;
std::mutex server_handlers_m;
std::vector<api::ClientState *> client_states;
std::mutex client_states_m;
SOCKET server;
void server_worker();
void connection_handler(ClientState client_state);
public:
// state
bool server_running;
// constructor / destructor
Controller(unsigned short port, std::string password, bool pretty);
~Controller();
void listen_serial(std::string port, DWORD baud);
bool process_request(ClientState *state, std::vector<char> *in, std::vector<char> *out);
bool process_request(ClientState *state, const char *in, size_t in_size, std::vector<char> *out);
static void process_password_change(ClientState *state);
void init_state(ClientState *state);
static void free_state(ClientState *state);
void free_socket();
void obtain_client_states(std::vector<ClientState> *output);
std::string get_ip_address(sockaddr_in addr);
inline const std::string &get_password() const {
return this->password;
}
};
}
+43 -43
View File
@@ -1,43 +1,43 @@
#include <utility>
#include "util/logging.h"
#include "module.h"
using namespace rapidjson;
namespace api {
// logging setting
bool LOGGING = false;
Module::Module(std::string name, bool password_force) {
this->name = std::move(name);
this->password_force = password_force;
}
void Module::handle(Request &req, Response &res) {
// log module access
if (LOGGING)
log_info("api::" + this->name, "handling request");
// find function
auto pos = functions.find(req.function);
if (pos == functions.end())
return error_function_unknown(res);
// call function
pos->second(req, res);
}
void Module::error(Response &res, std::string err) {
// log the warning
log_warning("api::" + this->name, "error: {}", err);
// add error to response
Value val(err.c_str(), res.doc()->GetAllocator());
res.add_error(val);
}
}
#include <utility>
#include "util/logging.h"
#include "module.h"
using namespace rapidjson;
namespace api {
// logging setting
bool LOGGING = false;
Module::Module(std::string name, bool password_force) {
this->name = std::move(name);
this->password_force = password_force;
}
void Module::handle(Request &req, Response &res) {
// log module access
if (LOGGING)
log_info("api::" + this->name, "handling request");
// find function
auto pos = functions.find(req.function);
if (pos == functions.end())
return error_function_unknown(res);
// call function
pos->second(req, res);
}
void Module::error(Response &res, std::string err) {
// log the warning
log_warning("api::" + this->name, "error: {}", err);
// add error to response
Value val(err.c_str(), res.doc()->GetAllocator());
res.add_error(val);
}
}
+67 -67
View File
@@ -1,67 +1,67 @@
#pragma once
#include <functional>
#include <map>
#include <string>
#include <sstream>
#include <external/robin_hood.h>
#include "response.h"
#include "request.h"
namespace api {
// logging setting
extern bool LOGGING;
// callback
typedef std::function<void(Request &, Response &)> ModuleFunctionCallback;
class Module {
protected:
// map of available functions
robin_hood::unordered_map<std::string, ModuleFunctionCallback> functions;
// default constructor
explicit Module(std::string name, bool password_force=false);
public:
// virtual deconstructor
virtual ~Module() = default;
// name of the module (should match namespace)
std::string name;
bool password_force;
// the magic
void handle(Request &req, Response &res);
/*
* Error definitions.
*/
void error(Response &res, std::string err);
void error_type(Response &res, const std::string &field, const std::string &type) {
std::ostringstream s;
s << field << " must be a " << type;
error(res, s.str());
};
void error_size(Response &res, const std::string &field, size_t size) {
std::ostringstream s;
s << field << " must be of size " << size;
error(res, s.str());
}
void error_unknown(Response &res, const std::string &field, const std::string &name) {
std::ostringstream s;
s << "Unknown " << field << ": " << name;
error(res, s.str());
}
#define ERR(name, err) void error_##name(Response &res) { error(res, err); }
ERR(function_unknown, "Unknown function.");
ERR(params_insufficient, "Insufficient number of parameters.");
#undef ERR
};
}
#pragma once
#include <functional>
#include <map>
#include <string>
#include <sstream>
#include <external/robin_hood.h>
#include "response.h"
#include "request.h"
namespace api {
// logging setting
extern bool LOGGING;
// callback
typedef std::function<void(Request &, Response &)> ModuleFunctionCallback;
class Module {
protected:
// map of available functions
robin_hood::unordered_map<std::string, ModuleFunctionCallback> functions;
// default constructor
explicit Module(std::string name, bool password_force=false);
public:
// virtual deconstructor
virtual ~Module() = default;
// name of the module (should match namespace)
std::string name;
bool password_force;
// the magic
void handle(Request &req, Response &res);
/*
* Error definitions.
*/
void error(Response &res, std::string err);
void error_type(Response &res, const std::string &field, const std::string &type) {
std::ostringstream s;
s << field << " must be a " << type;
error(res, s.str());
};
void error_size(Response &res, const std::string &field, size_t size) {
std::ostringstream s;
s << field << " must be of size " << size;
error(res, s.str());
}
void error_unknown(Response &res, const std::string &field, const std::string &name) {
std::ostringstream s;
s << "Unknown " << field << ": " << name;
error(res, s.str());
}
#define ERR(name, err) void error_##name(Response &res) { error(res, err); }
ERR(function_unknown, "Unknown function.");
ERR(params_insufficient, "Insufficient number of parameters.");
#undef ERR
};
}
+177 -177
View File
@@ -1,177 +1,177 @@
#include "analogs.h"
#include <functional>
#include "external/rapidjson/document.h"
#include "misc/eamuse.h"
#include "cfg/analog.h"
#include "launcher/launcher.h"
#include "games/io.h"
#include "util/utils.h"
using namespace std::placeholders;
using namespace rapidjson;
namespace api::modules {
Analogs::Analogs() : Module("analogs") {
functions["read"] = std::bind(&Analogs::read, this, _1, _2);
functions["write"] = std::bind(&Analogs::write, this, _1, _2);
functions["write_reset"] = std::bind(&Analogs::write_reset, this, _1, _2);
analogs = games::get_analogs(eamuse_get_game());
}
/**
* read()
*/
void Analogs::read(api::Request &req, Response &res) {
// check analog cache
if (!analogs) {
return;
}
// add state for each analog
for (auto &analog : *this->analogs) {
Value state(kArrayType);
Value analog_name(analog.getName().c_str(), res.doc()->GetAllocator());
Value analog_state(GameAPI::Analogs::getState(RI_MGR, analog));
Value analog_enabled(analog.override_enabled);
state.PushBack(analog_name, res.doc()->GetAllocator());
state.PushBack(analog_state, res.doc()->GetAllocator());
state.PushBack(analog_enabled, res.doc()->GetAllocator());
res.add_data(state);
}
}
/**
* write([name: str, state: float], ...)
*/
void Analogs::write(Request &req, Response &res) {
// check analog cache
if (!analogs)
return;
// loop parameters
for (Value &param : req.params.GetArray()) {
// check params
if (!param.IsArray()) {
error(res, "parameters must be arrays");
return;
}
if (param.Size() < 2) {
error_params_insufficient(res);
continue;
}
if (!param[0].IsString()) {
error_type(res, "name", "string");
continue;
}
if (!param[1].IsFloat() && !param[1].IsInt()) {
error_type(res, "state", "float");
continue;
}
// get params
auto analog_name = param[0].GetString();
auto analog_state = param[1].GetFloat();
// write analog state
if (!this->write_analog(analog_name, analog_state)) {
error_unknown(res, "analog", analog_name);
continue;
}
}
}
/**
* write_reset()
* write_reset([name: str], ...)
*/
void Analogs::write_reset(Request &req, Response &res) {
// check analog cache
if (!analogs)
return;
// get params
auto params = req.params.GetArray();
// write_reset()
if (params.Size() == 0) {
if (analogs != nullptr) {
for (auto &analog : *this->analogs) {
analog.override_enabled = false;
}
}
return;
}
// loop parameters
for (Value &param : req.params.GetArray()) {
// check params
if (!param.IsArray()) {
error(res, "parameters must be arrays");
return;
}
if (param.Size() < 1) {
error_params_insufficient(res);
continue;
}
if (!param[0].IsString()) {
error_type(res, "name", "string");
continue;
}
// get params
auto analog_name = param[0].GetString();
// write analog state
if (!this->write_analog_reset(analog_name)) {
error_unknown(res, "analog", analog_name);
continue;
}
}
}
bool Analogs::write_analog(std::string name, float state) {
// check analog cache
if (!this->analogs) {
return false;
}
// find analog
for (auto &analog : *this->analogs) {
if (analog.getName() == name) {
analog.override_state = CLAMP(state, 0.f, 1.f);
analog.override_enabled = true;
return true;
}
}
// unknown analog
return false;
}
bool Analogs::write_analog_reset(std::string name) {
// check analog cache
if (!analogs) {
return false;
}
// find analog
for (auto &analog : *this->analogs) {
if (analog.getName() == name) {
analog.override_enabled = false;
return true;
}
}
// unknown analog
return false;
}
}
#include "analogs.h"
#include <functional>
#include "external/rapidjson/document.h"
#include "misc/eamuse.h"
#include "cfg/analog.h"
#include "launcher/launcher.h"
#include "games/io.h"
#include "util/utils.h"
using namespace std::placeholders;
using namespace rapidjson;
namespace api::modules {
Analogs::Analogs() : Module("analogs") {
functions["read"] = std::bind(&Analogs::read, this, _1, _2);
functions["write"] = std::bind(&Analogs::write, this, _1, _2);
functions["write_reset"] = std::bind(&Analogs::write_reset, this, _1, _2);
analogs = games::get_analogs(eamuse_get_game());
}
/**
* read()
*/
void Analogs::read(api::Request &req, Response &res) {
// check analog cache
if (!analogs) {
return;
}
// add state for each analog
for (auto &analog : *this->analogs) {
Value state(kArrayType);
Value analog_name(analog.getName().c_str(), res.doc()->GetAllocator());
Value analog_state(GameAPI::Analogs::getState(RI_MGR, analog));
Value analog_enabled(analog.override_enabled);
state.PushBack(analog_name, res.doc()->GetAllocator());
state.PushBack(analog_state, res.doc()->GetAllocator());
state.PushBack(analog_enabled, res.doc()->GetAllocator());
res.add_data(state);
}
}
/**
* write([name: str, state: float], ...)
*/
void Analogs::write(Request &req, Response &res) {
// check analog cache
if (!analogs)
return;
// loop parameters
for (Value &param : req.params.GetArray()) {
// check params
if (!param.IsArray()) {
error(res, "parameters must be arrays");
return;
}
if (param.Size() < 2) {
error_params_insufficient(res);
continue;
}
if (!param[0].IsString()) {
error_type(res, "name", "string");
continue;
}
if (!param[1].IsFloat() && !param[1].IsInt()) {
error_type(res, "state", "float");
continue;
}
// get params
auto analog_name = param[0].GetString();
auto analog_state = param[1].GetFloat();
// write analog state
if (!this->write_analog(analog_name, analog_state)) {
error_unknown(res, "analog", analog_name);
continue;
}
}
}
/**
* write_reset()
* write_reset([name: str], ...)
*/
void Analogs::write_reset(Request &req, Response &res) {
// check analog cache
if (!analogs)
return;
// get params
auto params = req.params.GetArray();
// write_reset()
if (params.Size() == 0) {
if (analogs != nullptr) {
for (auto &analog : *this->analogs) {
analog.override_enabled = false;
}
}
return;
}
// loop parameters
for (Value &param : req.params.GetArray()) {
// check params
if (!param.IsArray()) {
error(res, "parameters must be arrays");
return;
}
if (param.Size() < 1) {
error_params_insufficient(res);
continue;
}
if (!param[0].IsString()) {
error_type(res, "name", "string");
continue;
}
// get params
auto analog_name = param[0].GetString();
// write analog state
if (!this->write_analog_reset(analog_name)) {
error_unknown(res, "analog", analog_name);
continue;
}
}
}
bool Analogs::write_analog(std::string name, float state) {
// check analog cache
if (!this->analogs) {
return false;
}
// find analog
for (auto &analog : *this->analogs) {
if (analog.getName() == name) {
analog.override_state = CLAMP(state, 0.f, 1.f);
analog.override_enabled = true;
return true;
}
}
// unknown analog
return false;
}
bool Analogs::write_analog_reset(std::string name) {
// check analog cache
if (!analogs) {
return false;
}
// find analog
for (auto &analog : *this->analogs) {
if (analog.getName() == name) {
analog.override_enabled = false;
return true;
}
}
// unknown analog
return false;
}
}
+28 -28
View File
@@ -1,28 +1,28 @@
#pragma once
#include <vector>
#include "api/module.h"
#include "api/request.h"
#include "cfg/api.h"
namespace api::modules {
class Analogs : public Module {
public:
Analogs();
private:
// state
std::vector<Analog> *analogs;
// function definitions
void read(Request &req, Response &res);
void write(Request &req, Response &res);
void write_reset(Request &req, Response &res);
// helper
bool write_analog(std::string name, float state);
bool write_analog_reset(std::string name);
};
}
#pragma once
#include <vector>
#include "api/module.h"
#include "api/request.h"
#include "cfg/api.h"
namespace api::modules {
class Analogs : public Module {
public:
Analogs();
private:
// state
std::vector<Analog> *analogs;
// function definitions
void read(Request &req, Response &res);
void write(Request &req, Response &res);
void write_reset(Request &req, Response &res);
// helper
bool write_analog(std::string name, float state);
bool write_analog_reset(std::string name);
};
}
+28 -28
View File
@@ -1,28 +1,28 @@
#pragma once
#include <vector>
#include "api/module.h"
#include "api/request.h"
#include "cfg/api.h"
namespace api::modules {
class Buttons : public Module {
public:
Buttons();
private:
// state
std::vector<Button> *buttons;
// function definitions
void read(Request &req, Response &res);
void write(Request &req, Response &res);
void write_reset(Request &req, Response &res);
// helper
bool write_button(std::string name, float state);
bool write_button_reset(std::string name);
};
}
#pragma once
#include <vector>
#include "api/module.h"
#include "api/request.h"
#include "cfg/api.h"
namespace api::modules {
class Buttons : public Module {
public:
Buttons();
private:
// state
std::vector<Button> *buttons;
// function definitions
void read(Request &req, Response &res);
void write(Request &req, Response &res);
void write_reset(Request &req, Response &res);
// helper
bool write_button(std::string name, float state);
bool write_button_reset(std::string name);
};
}
+82 -82
View File
@@ -1,82 +1,82 @@
#include "capture.h"
#include <functional>
#include "external/rapidjson/document.h"
#include "hooks/graphics/graphics.h"
#include "util/crypt.h"
using namespace std::placeholders;
using namespace rapidjson;
namespace api::modules {
static thread_local std::vector<uint8_t> CAPTURE_BUFFER;
Capture::Capture() : Module("capture") {
functions["get_screens"] = std::bind(&Capture::get_screens, this, _1, _2);
functions["get_jpg"] = std::bind(&Capture::get_jpg, this, _1, _2);
}
/**
* get_screens()
*/
void Capture::get_screens(Request &req, Response &res) {
// aquire screens
std::vector<int> screens;
graphics_screens_get(screens);
// add screens to response
for (auto &screen : screens) {
res.add_data(screen);
}
}
/**
* get_jpg([screen=0, quality=70, downscale=0, divide=1])
* screen: uint specifying the window
* quality: uint in range [0, 100]
* reduce: uint for dividing image size
*/
void Capture::get_jpg(Request &req, Response &res) {
CAPTURE_BUFFER.reserve(1024 * 128);
// settings
int screen = 0;
int quality = 70;
int divide = 1;
if (req.params.Size() > 0 && req.params[0].IsUint())
screen = req.params[0].GetUint();
if (req.params.Size() > 1 && req.params[1].IsUint())
quality = req.params[1].GetUint();
if (req.params.Size() > 2 && req.params[2].IsUint())
divide = req.params[2].GetUint();
// receive JPEG data
uint64_t timestamp = 0;
int width = 0;
int height = 0;
graphics_capture_trigger(screen);
bool success = graphics_capture_receive_jpeg(screen, [] (uint8_t byte) {
CAPTURE_BUFFER.push_back(byte);
}, true, quality, true, divide, &timestamp, &width, &height);
if (!success) {
return;
}
// encode to base64
auto encoded = crypt::base64_encode(
CAPTURE_BUFFER.data(),
CAPTURE_BUFFER.size());
// clear buffer
CAPTURE_BUFFER.clear();
// add data to response
Value data;
data.SetString(encoded.c_str(), encoded.length(), res.doc()->GetAllocator());
res.add_data(timestamp);
res.add_data(width);
res.add_data(height);
res.add_data(data);
}
}
#include "capture.h"
#include <functional>
#include "external/rapidjson/document.h"
#include "hooks/graphics/graphics.h"
#include "util/crypt.h"
using namespace std::placeholders;
using namespace rapidjson;
namespace api::modules {
static thread_local std::vector<uint8_t> CAPTURE_BUFFER;
Capture::Capture() : Module("capture") {
functions["get_screens"] = std::bind(&Capture::get_screens, this, _1, _2);
functions["get_jpg"] = std::bind(&Capture::get_jpg, this, _1, _2);
}
/**
* get_screens()
*/
void Capture::get_screens(Request &req, Response &res) {
// aquire screens
std::vector<int> screens;
graphics_screens_get(screens);
// add screens to response
for (auto &screen : screens) {
res.add_data(screen);
}
}
/**
* get_jpg([screen=0, quality=70, downscale=0, divide=1])
* screen: uint specifying the window
* quality: uint in range [0, 100]
* reduce: uint for dividing image size
*/
void Capture::get_jpg(Request &req, Response &res) {
CAPTURE_BUFFER.reserve(1024 * 128);
// settings
int screen = 0;
int quality = 70;
int divide = 1;
if (req.params.Size() > 0 && req.params[0].IsUint())
screen = req.params[0].GetUint();
if (req.params.Size() > 1 && req.params[1].IsUint())
quality = req.params[1].GetUint();
if (req.params.Size() > 2 && req.params[2].IsUint())
divide = req.params[2].GetUint();
// receive JPEG data
uint64_t timestamp = 0;
int width = 0;
int height = 0;
graphics_capture_trigger(screen);
bool success = graphics_capture_receive_jpeg(screen, [] (uint8_t byte) {
CAPTURE_BUFFER.push_back(byte);
}, true, quality, true, divide, &timestamp, &width, &height);
if (!success) {
return;
}
// encode to base64
auto encoded = crypt::base64_encode(
CAPTURE_BUFFER.data(),
CAPTURE_BUFFER.size());
// clear buffer
CAPTURE_BUFFER.clear();
// add data to response
Value data;
data.SetString(encoded.c_str(), encoded.length(), res.doc()->GetAllocator());
res.add_data(timestamp);
res.add_data(width);
res.add_data(height);
res.add_data(data);
}
}
+18 -18
View File
@@ -1,18 +1,18 @@
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class Capture : public Module {
public:
Capture();
private:
// function definitions
void get_screens(Request &req, Response &res);
void get_jpg(Request &req, Response &res);
};
}
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class Capture : public Module {
public:
Capture();
private:
// function definitions
void get_screens(Request &req, Response &res);
void get_jpg(Request &req, Response &res);
};
}
+17 -17
View File
@@ -1,17 +1,17 @@
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class Card : public Module {
public:
Card();
private:
// function definitions
void insert(Request &req, Response &res);
};
}
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class Card : public Module {
public:
Card();
private:
// function definitions
void insert(Request &req, Response &res);
};
}
+20 -20
View File
@@ -1,20 +1,20 @@
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class Coin : public Module {
public:
Coin();
private:
// function definitions
void get(Request &req, Response &res);
void set(Request &req, Response &res);
void insert(Request &req, Response &res);
void blocker_get(Request &req, Response &res);
};
}
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class Coin : public Module {
public:
Coin();
private:
// function definitions
void get(Request &req, Response &res);
void set(Request &req, Response &res);
void insert(Request &req, Response &res);
void blocker_get(Request &req, Response &res);
};
}
+180 -180
View File
@@ -1,180 +1,180 @@
#include "control.h"
#include <csignal>
#include <functional>
#include "external/rapidjson/document.h"
#include "launcher/shutdown.h"
#include "util/logging.h"
#include "util/crypt.h"
#include "util/utils.h"
using namespace std::placeholders;
using namespace rapidjson;
namespace api::modules {
struct SignalMapping {
int signum;
const char* name;
};
static SignalMapping SIGNAL_MAPPINGS[] = {
{ SIGABRT, "SIGABRT" },
{ SIGFPE, "SIGFPE" },
{ SIGILL, "SIGILL" },
{ SIGINT, "SIGINT" },
{ SIGSEGV, "SIGSEGV" },
{ SIGTERM, "SIGTERM" },
};
static inline bool acquire_shutdown_privs() {
// check if already acquired
static bool acquired = false;
if (acquired)
return true;
// get process token
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return false;
// get the LUID for the shutdown privilege
TOKEN_PRIVILEGES tkp;
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// get the shutdown privilege for this process
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
// check for error
bool success = GetLastError() == ERROR_SUCCESS;
if (success)
acquired = true;
return success;
}
Control::Control() : Module("control", true) {
functions["raise"] = std::bind(&Control::raise, this, _1, _2);
functions["exit"] = std::bind(&Control::exit, this, _1, _2);
functions["restart"] = std::bind(&Control::restart, this, _1, _2);
functions["session_refresh"] = std::bind(&Control::session_refresh, this, _1, _2);
functions["shutdown"] = std::bind(&Control::shutdown, this, _1, _2);
functions["reboot"] = std::bind(&Control::reboot, this, _1, _2);
}
/**
* raise(signal: str)
*/
void Control::raise(Request &req, Response &res) {
// check args
if (req.params.Size() < 1)
return error_params_insufficient(res);
if (!req.params[0].IsString())
return error_type(res, "signal", "string");
// get signal
auto signal_str = req.params[0].GetString();
int signal_val = -1;
for (auto mapping : SIGNAL_MAPPINGS) {
if (_stricmp(mapping.name, signal_str) == 0) {
signal_val = mapping.signum;
break;
}
}
// check if not found
if (signal_val < 0)
return error_unknown(res, "signal", signal_str);
// raise signal
if (::raise(signal_val))
return error(res, "Failed to raise signo " + to_string(signal_val));
}
/**
* exit()
* exit(code: int)
*/
void Control::exit(Request &req, Response &res) {
// exit()
if (req.params.Size() == 0) {
launcher::shutdown();
}
// check code
if (!req.params[0].IsInt())
return error_type(res, "code", "int");
// exit
launcher::shutdown(req.params[0].GetInt());
}
/**
* restart()
*/
void Control::restart(Request &req, Response &res) {
// restart launcher
launcher::restart();
}
/**
* session_refresh()
*/
void Control::session_refresh(Request &req, Response &res) {
// generate new password
uint8_t password_bin[128];
crypt::random_bytes(password_bin, std::size(password_bin));
std::string password = bin2hex(&password_bin[0], std::size(password_bin));
// add to response
Value password_val(password.c_str(), res.doc()->GetAllocator());
res.add_data(password_val);
// change password
res.password_change(password);
}
/**
* shutdown()
*/
void Control::shutdown(Request &req, Response &res) {
// acquire privileges
if (!acquire_shutdown_privs())
return error(res, "Unable to acquire shutdown privileges");
// exit windows
if (!ExitWindowsEx(EWX_POWEROFF | EWX_FORCE,
SHTDN_REASON_MAJOR_APPLICATION |
SHTDN_REASON_MINOR_MAINTENANCE))
return error(res, "Unable to shutdown system");
// terminate this process
launcher::shutdown(0);
}
/**
* reboot()
*/
void Control::reboot(Request &req, Response &res) {
// acquire privileges
if (!acquire_shutdown_privs())
return error(res, "Unable to acquire shutdown privileges");
// exit windows
if (!ExitWindowsEx(EWX_REBOOT | EWX_FORCE,
SHTDN_REASON_MAJOR_APPLICATION |
SHTDN_REASON_MINOR_MAINTENANCE))
return error(res, "Unable to reboot system");
// terminate this process
launcher::shutdown(0);
}
}
#include "control.h"
#include <csignal>
#include <functional>
#include "external/rapidjson/document.h"
#include "launcher/shutdown.h"
#include "util/logging.h"
#include "util/crypt.h"
#include "util/utils.h"
using namespace std::placeholders;
using namespace rapidjson;
namespace api::modules {
struct SignalMapping {
int signum;
const char* name;
};
static SignalMapping SIGNAL_MAPPINGS[] = {
{ SIGABRT, "SIGABRT" },
{ SIGFPE, "SIGFPE" },
{ SIGILL, "SIGILL" },
{ SIGINT, "SIGINT" },
{ SIGSEGV, "SIGSEGV" },
{ SIGTERM, "SIGTERM" },
};
static inline bool acquire_shutdown_privs() {
// check if already acquired
static bool acquired = false;
if (acquired)
return true;
// get process token
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return false;
// get the LUID for the shutdown privilege
TOKEN_PRIVILEGES tkp;
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// get the shutdown privilege for this process
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
// check for error
bool success = GetLastError() == ERROR_SUCCESS;
if (success)
acquired = true;
return success;
}
Control::Control() : Module("control", true) {
functions["raise"] = std::bind(&Control::raise, this, _1, _2);
functions["exit"] = std::bind(&Control::exit, this, _1, _2);
functions["restart"] = std::bind(&Control::restart, this, _1, _2);
functions["session_refresh"] = std::bind(&Control::session_refresh, this, _1, _2);
functions["shutdown"] = std::bind(&Control::shutdown, this, _1, _2);
functions["reboot"] = std::bind(&Control::reboot, this, _1, _2);
}
/**
* raise(signal: str)
*/
void Control::raise(Request &req, Response &res) {
// check args
if (req.params.Size() < 1)
return error_params_insufficient(res);
if (!req.params[0].IsString())
return error_type(res, "signal", "string");
// get signal
auto signal_str = req.params[0].GetString();
int signal_val = -1;
for (auto mapping : SIGNAL_MAPPINGS) {
if (_stricmp(mapping.name, signal_str) == 0) {
signal_val = mapping.signum;
break;
}
}
// check if not found
if (signal_val < 0)
return error_unknown(res, "signal", signal_str);
// raise signal
if (::raise(signal_val))
return error(res, "Failed to raise signo " + to_string(signal_val));
}
/**
* exit()
* exit(code: int)
*/
void Control::exit(Request &req, Response &res) {
// exit()
if (req.params.Size() == 0) {
launcher::shutdown();
}
// check code
if (!req.params[0].IsInt())
return error_type(res, "code", "int");
// exit
launcher::shutdown(req.params[0].GetInt());
}
/**
* restart()
*/
void Control::restart(Request &req, Response &res) {
// restart launcher
launcher::restart();
}
/**
* session_refresh()
*/
void Control::session_refresh(Request &req, Response &res) {
// generate new password
uint8_t password_bin[128];
crypt::random_bytes(password_bin, std::size(password_bin));
std::string password = bin2hex(&password_bin[0], std::size(password_bin));
// add to response
Value password_val(password.c_str(), res.doc()->GetAllocator());
res.add_data(password_val);
// change password
res.password_change(password);
}
/**
* shutdown()
*/
void Control::shutdown(Request &req, Response &res) {
// acquire privileges
if (!acquire_shutdown_privs())
return error(res, "Unable to acquire shutdown privileges");
// exit windows
if (!ExitWindowsEx(EWX_POWEROFF | EWX_FORCE,
SHTDN_REASON_MAJOR_APPLICATION |
SHTDN_REASON_MINOR_MAINTENANCE))
return error(res, "Unable to shutdown system");
// terminate this process
launcher::shutdown(0);
}
/**
* reboot()
*/
void Control::reboot(Request &req, Response &res) {
// acquire privileges
if (!acquire_shutdown_privs())
return error(res, "Unable to acquire shutdown privileges");
// exit windows
if (!ExitWindowsEx(EWX_REBOOT | EWX_FORCE,
SHTDN_REASON_MAJOR_APPLICATION |
SHTDN_REASON_MINOR_MAINTENANCE))
return error(res, "Unable to reboot system");
// terminate this process
launcher::shutdown(0);
}
}
+22 -22
View File
@@ -1,22 +1,22 @@
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class Control : public Module {
public:
Control();
private:
// function definitions
void raise(Request &req, Response &res);
void exit(Request &req, Response &res);
void restart(Request &req, Response &res);
void session_refresh(Request &req, Response &res);
void shutdown(Request &req, Response &res);
void reboot(Request &req, Response &res);
};
}
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class Control : public Module {
public:
Control();
private:
// function definitions
void raise(Request &req, Response &res);
void exit(Request &req, Response &res);
void restart(Request &req, Response &res);
void session_refresh(Request &req, Response &res);
void shutdown(Request &req, Response &res);
void reboot(Request &req, Response &res);
};
}
+19 -19
View File
@@ -1,19 +1,19 @@
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class Info : public Module {
public:
Info();
private:
// function definitions
void avs(Request &req, Response &res);
void launcher(Request &req, Response &res);
void memory(Request &req, Response &res);
};
}
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class Info : public Module {
public:
Info();
private:
// function definitions
void avs(Request &req, Response &res);
void launcher(Request &req, Response &res);
void memory(Request &req, Response &res);
};
}
+176 -176
View File
@@ -1,176 +1,176 @@
#include "keypads.h"
#include <functional>
#include <windows.h>
#include "avs/game.h"
#include "external/rapidjson/document.h"
#include "misc/eamuse.h"
using namespace std::placeholders;
using namespace rapidjson;
namespace api::modules {
struct KeypadMapping {
char character;
uint16_t state;
};
static KeypadMapping KEYPAD_MAPPINGS[] = {
{ '0', 1 << EAM_IO_KEYPAD_0 },
{ '1', 1 << EAM_IO_KEYPAD_1 },
{ '2', 1 << EAM_IO_KEYPAD_2 },
{ '3', 1 << EAM_IO_KEYPAD_3 },
{ '4', 1 << EAM_IO_KEYPAD_4 },
{ '5', 1 << EAM_IO_KEYPAD_5 },
{ '6', 1 << EAM_IO_KEYPAD_6 },
{ '7', 1 << EAM_IO_KEYPAD_7 },
{ '8', 1 << EAM_IO_KEYPAD_8 },
{ '9', 1 << EAM_IO_KEYPAD_9 },
{ 'A', 1 << EAM_IO_KEYPAD_00 },
{ 'D', 1 << EAM_IO_KEYPAD_DECIMAL },
};
Keypads::Keypads() : Module("keypads") {
functions["write"] = std::bind(&Keypads::write, this, _1, _2);
functions["set"] = std::bind(&Keypads::set, this, _1, _2);
functions["get"] = std::bind(&Keypads::get, this, _1, _2);
}
/**
* write(keypad: uint, input: str)
*/
void Keypads::write(Request &req, Response &res) {
// check params
if (req.params.Size() < 2) {
return error_params_insufficient(res);
}
if (!req.params[0].IsUint()) {
return error_type(res, "keypad", "uint");
}
if (!req.params[1].IsString()) {
return error_type(res, "input", "string");
}
// get params
auto keypad = req.params[0].GetUint();
auto input = std::string(req.params[1].GetString());
// process all chars
for (auto c : input) {
uint16_t state = 0;
// find mapping
bool mapping_found = false;
for (auto &mapping : KEYPAD_MAPPINGS) {
if (_strnicmp(&mapping.character, &c, 1) == 0) {
state |= mapping.state;
mapping_found = true;
break;
}
}
// check for error
if (!mapping_found) {
return error_unknown(res, "char", std::string("") + c);
}
/*
* Write input to keypad.
* We try to make sure it was accepted by waiting a bit more than two frames.
*/
DWORD sleep_time = 70;
if (avs::game::is_model("MDX")) {
// cuz fuck DDR
sleep_time = 150;
}
// set
eamuse_set_keypad_overrides(keypad, state);
Sleep(sleep_time);
// unset
eamuse_set_keypad_overrides(keypad, 0);
Sleep(sleep_time);
}
}
/**
* set(keypad: uint, key: char, ...)
*/
void Keypads::set(Request &req, Response &res) {
// check keypad
if (req.params.Size() < 1) {
return error_params_insufficient(res);
}
if (!req.params[0].IsUint()) {
return error_type(res, "keypad", "uint");
}
auto keypad = req.params[0].GetUint();
// iterate params
uint16_t state = 0;
auto params = req.params.GetArray();
for (size_t i = 1; i < params.Size(); i++) {
auto &param = params[i];
// check key
if (!param.IsString()) {
error_type(res, "key", "char");
}
if (param.GetStringLength() < 1) {
error_size(res, "key", 1);
}
// find mapping
auto key = param.GetString();
bool mapping_found = false;
for (auto &mapping : KEYPAD_MAPPINGS) {
if (_strnicmp(&mapping.character, key, 1) == 0) {
state |= mapping.state;
mapping_found = true;
break;
}
}
// check for error
if (!mapping_found) {
return error_unknown(res, "key", key);
}
}
// set keypad state
eamuse_set_keypad_overrides(keypad, state);
}
/**
* get(keypad: uint)
*/
void Keypads::get(Request &req, Response &res) {
// check keypad
if (req.params.Size() < 1) {
return error_params_insufficient(res);
}
if (!req.params[0].IsUint()) {
return error_type(res, "keypad", "uint");
}
auto keypad = req.params[0].GetUint();
// get keypad state
auto state = eamuse_get_keypad_state(keypad);
// add keys to response
for (auto &mapping : KEYPAD_MAPPINGS) {
if (state & mapping.state) {
Value val(&mapping.character, 1);
res.add_data(val);
}
}
}
}
#include "keypads.h"
#include <functional>
#include <windows.h>
#include "avs/game.h"
#include "external/rapidjson/document.h"
#include "misc/eamuse.h"
using namespace std::placeholders;
using namespace rapidjson;
namespace api::modules {
struct KeypadMapping {
char character;
uint16_t state;
};
static KeypadMapping KEYPAD_MAPPINGS[] = {
{ '0', 1 << EAM_IO_KEYPAD_0 },
{ '1', 1 << EAM_IO_KEYPAD_1 },
{ '2', 1 << EAM_IO_KEYPAD_2 },
{ '3', 1 << EAM_IO_KEYPAD_3 },
{ '4', 1 << EAM_IO_KEYPAD_4 },
{ '5', 1 << EAM_IO_KEYPAD_5 },
{ '6', 1 << EAM_IO_KEYPAD_6 },
{ '7', 1 << EAM_IO_KEYPAD_7 },
{ '8', 1 << EAM_IO_KEYPAD_8 },
{ '9', 1 << EAM_IO_KEYPAD_9 },
{ 'A', 1 << EAM_IO_KEYPAD_00 },
{ 'D', 1 << EAM_IO_KEYPAD_DECIMAL },
};
Keypads::Keypads() : Module("keypads") {
functions["write"] = std::bind(&Keypads::write, this, _1, _2);
functions["set"] = std::bind(&Keypads::set, this, _1, _2);
functions["get"] = std::bind(&Keypads::get, this, _1, _2);
}
/**
* write(keypad: uint, input: str)
*/
void Keypads::write(Request &req, Response &res) {
// check params
if (req.params.Size() < 2) {
return error_params_insufficient(res);
}
if (!req.params[0].IsUint()) {
return error_type(res, "keypad", "uint");
}
if (!req.params[1].IsString()) {
return error_type(res, "input", "string");
}
// get params
auto keypad = req.params[0].GetUint();
auto input = std::string(req.params[1].GetString());
// process all chars
for (auto c : input) {
uint16_t state = 0;
// find mapping
bool mapping_found = false;
for (auto &mapping : KEYPAD_MAPPINGS) {
if (_strnicmp(&mapping.character, &c, 1) == 0) {
state |= mapping.state;
mapping_found = true;
break;
}
}
// check for error
if (!mapping_found) {
return error_unknown(res, "char", std::string("") + c);
}
/*
* Write input to keypad.
* We try to make sure it was accepted by waiting a bit more than two frames.
*/
DWORD sleep_time = 70;
if (avs::game::is_model("MDX")) {
// cuz fuck DDR
sleep_time = 150;
}
// set
eamuse_set_keypad_overrides(keypad, state);
Sleep(sleep_time);
// unset
eamuse_set_keypad_overrides(keypad, 0);
Sleep(sleep_time);
}
}
/**
* set(keypad: uint, key: char, ...)
*/
void Keypads::set(Request &req, Response &res) {
// check keypad
if (req.params.Size() < 1) {
return error_params_insufficient(res);
}
if (!req.params[0].IsUint()) {
return error_type(res, "keypad", "uint");
}
auto keypad = req.params[0].GetUint();
// iterate params
uint16_t state = 0;
auto params = req.params.GetArray();
for (size_t i = 1; i < params.Size(); i++) {
auto &param = params[i];
// check key
if (!param.IsString()) {
error_type(res, "key", "char");
}
if (param.GetStringLength() < 1) {
error_size(res, "key", 1);
}
// find mapping
auto key = param.GetString();
bool mapping_found = false;
for (auto &mapping : KEYPAD_MAPPINGS) {
if (_strnicmp(&mapping.character, key, 1) == 0) {
state |= mapping.state;
mapping_found = true;
break;
}
}
// check for error
if (!mapping_found) {
return error_unknown(res, "key", key);
}
}
// set keypad state
eamuse_set_keypad_overrides(keypad, state);
}
/**
* get(keypad: uint)
*/
void Keypads::get(Request &req, Response &res) {
// check keypad
if (req.params.Size() < 1) {
return error_params_insufficient(res);
}
if (!req.params[0].IsUint()) {
return error_type(res, "keypad", "uint");
}
auto keypad = req.params[0].GetUint();
// get keypad state
auto state = eamuse_get_keypad_state(keypad);
// add keys to response
for (auto &mapping : KEYPAD_MAPPINGS) {
if (state & mapping.state) {
Value val(&mapping.character, 1);
res.add_data(val);
}
}
}
}
+19 -19
View File
@@ -1,19 +1,19 @@
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class Keypads : public Module {
public:
Keypads();
private:
// function definitions
void write(Request &req, Response &res);
void set(Request &req, Response &res);
void get(Request &req, Response &res);
};
}
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class Keypads : public Module {
public:
Keypads();
private:
// function definitions
void write(Request &req, Response &res);
void set(Request &req, Response &res);
void get(Request &req, Response &res);
};
}
+36 -36
View File
@@ -1,36 +1,36 @@
#include "lcd.h"
#include "external/rapidjson/document.h"
#include "games/shared/lcdhandle.h"
using namespace std::placeholders;
using namespace rapidjson;
namespace api::modules {
LCD::LCD() : Module("lcd") {
functions["info"] = std::bind(&LCD::info, this, _1, _2);
}
/*
* info()
*/
void LCD::info(Request &req, Response &res) {
// get allocator
auto &alloc = res.doc()->GetAllocator();
// build info object
Value info(kObjectType);
info.AddMember("enabled", games::shared::LCD_ENABLED, alloc);
info.AddMember("csm", StringRef(games::shared::LCD_CSM.c_str()), alloc);
info.AddMember("bri", games::shared::LCD_BRI, alloc);
info.AddMember("con", games::shared::LCD_CON, alloc);
info.AddMember("bl", games::shared::LCD_BL, alloc);
info.AddMember("red", games::shared::LCD_RED, alloc);
info.AddMember("green", games::shared::LCD_GREEN, alloc);
info.AddMember("blue", games::shared::LCD_BLUE, alloc);
// add info object
res.add_data(info);
}
}
#include "lcd.h"
#include "external/rapidjson/document.h"
#include "games/shared/lcdhandle.h"
using namespace std::placeholders;
using namespace rapidjson;
namespace api::modules {
LCD::LCD() : Module("lcd") {
functions["info"] = std::bind(&LCD::info, this, _1, _2);
}
/*
* info()
*/
void LCD::info(Request &req, Response &res) {
// get allocator
auto &alloc = res.doc()->GetAllocator();
// build info object
Value info(kObjectType);
info.AddMember("enabled", games::shared::LCD_ENABLED, alloc);
info.AddMember("csm", StringRef(games::shared::LCD_CSM.c_str()), alloc);
info.AddMember("bri", games::shared::LCD_BRI, alloc);
info.AddMember("con", games::shared::LCD_CON, alloc);
info.AddMember("bl", games::shared::LCD_BL, alloc);
info.AddMember("red", games::shared::LCD_RED, alloc);
info.AddMember("green", games::shared::LCD_GREEN, alloc);
info.AddMember("blue", games::shared::LCD_BLUE, alloc);
// add info object
res.add_data(info);
}
}
+17 -17
View File
@@ -1,17 +1,17 @@
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class LCD : public Module {
public:
LCD();
private:
// function definitions
void info(Request &req, Response &res);
};
}
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class LCD : public Module {
public:
LCD();
private:
// function definitions
void info(Request &req, Response &res);
};
}
+179 -179
View File
@@ -1,179 +1,179 @@
#include "lights.h"
#include <functional>
#include "external/rapidjson/document.h"
#include "misc/eamuse.h"
#include "cfg/light.h"
#include "launcher/launcher.h"
#include "games/io.h"
#include "util/utils.h"
using namespace std::placeholders;
using namespace rapidjson;
namespace api::modules {
Lights::Lights() : Module("lights") {
functions["read"] = std::bind(&Lights::read, this, _1, _2);
functions["write"] = std::bind(&Lights::write, this, _1, _2);
functions["write_reset"] = std::bind(&Lights::write_reset, this, _1, _2);
lights = games::get_lights(eamuse_get_game());
}
/**
* read()
*/
void Lights::read(api::Request &req, Response &res) {
// check light cache
if (!this->lights) {
return;
}
// add state for each light
for (auto &light : *this->lights) {
Value state(kArrayType);
Value light_name(light.getName().c_str(), res.doc()->GetAllocator());
Value light_state(GameAPI::Lights::readLight(RI_MGR, light));
Value light_enabled(light.override_enabled);
state.PushBack(light_name, res.doc()->GetAllocator());
state.PushBack(light_state, res.doc()->GetAllocator());
state.PushBack(light_enabled, res.doc()->GetAllocator());
res.add_data(state);
}
}
/**
* write([name: str, state: float], ...)
*/
void Lights::write(Request &req, Response &res) {
// check light cache
if (!this->lights) {
return;
}
// loop parameters
for (Value &param : req.params.GetArray()) {
// check params
if (!param.IsArray()) {
error(res, "parameters must be arrays");
return;
}
if (param.Size() < 2) {
error_params_insufficient(res);
continue;
}
if (!param[0].IsString()) {
error_type(res, "name", "string");
continue;
}
if (!param[1].IsFloat() && !param[1].IsInt()) {
error_type(res, "state", "float");
continue;
}
// get params
auto light_name = param[0].GetString();
auto light_state = param[1].GetFloat();
// write light state
if (!this->write_light(light_name, light_state)) {
error_unknown(res, "light", light_name);
continue;
}
}
}
/**
* write_reset()
* write_reset([name: str], ...)
*/
void Lights::write_reset(Request &req, Response &res) {
// check light cache
if (!this->lights) {
return;
}
// get params
auto params = req.params.GetArray();
// write_reset()
if (params.Size() == 0) {
if (lights != nullptr) {
for (auto &light : *this->lights) {
light.override_enabled = false;
}
}
return;
}
// loop parameters
for (Value &param : req.params.GetArray()) {
// check params
if (!param.IsArray()) {
error(res, "parameters must be arrays");
return;
}
if (param.Size() < 1) {
error_params_insufficient(res);
continue;
}
if (!param[0].IsString()) {
error_type(res, "name", "string");
continue;
}
// get params
auto light_name = param[0].GetString();
// write analog state
if (!this->write_light_reset(light_name)) {
error_unknown(res, "analog", light_name);
continue;
}
}
}
bool Lights::write_light(std::string name, float state) {
// check light cache
if (!this->lights) {
return false;
}
// find light
for (auto &light : *this->lights) {
if (light.getName() == name) {
light.override_state = CLAMP(state, 0.f, 1.f);
light.override_enabled = true;
return true;
}
}
// unknown light
return false;
}
bool Lights::write_light_reset(std::string name) {
// check light cache
if (!this->lights) {
return false;
}
// find light
for (auto &light : *this->lights) {
if (light.getName() == name) {
light.override_enabled = false;
return true;
}
}
// unknown light
return false;
}
}
#include "lights.h"
#include <functional>
#include "external/rapidjson/document.h"
#include "misc/eamuse.h"
#include "cfg/light.h"
#include "launcher/launcher.h"
#include "games/io.h"
#include "util/utils.h"
using namespace std::placeholders;
using namespace rapidjson;
namespace api::modules {
Lights::Lights() : Module("lights") {
functions["read"] = std::bind(&Lights::read, this, _1, _2);
functions["write"] = std::bind(&Lights::write, this, _1, _2);
functions["write_reset"] = std::bind(&Lights::write_reset, this, _1, _2);
lights = games::get_lights(eamuse_get_game());
}
/**
* read()
*/
void Lights::read(api::Request &req, Response &res) {
// check light cache
if (!this->lights) {
return;
}
// add state for each light
for (auto &light : *this->lights) {
Value state(kArrayType);
Value light_name(light.getName().c_str(), res.doc()->GetAllocator());
Value light_state(GameAPI::Lights::readLight(RI_MGR, light));
Value light_enabled(light.override_enabled);
state.PushBack(light_name, res.doc()->GetAllocator());
state.PushBack(light_state, res.doc()->GetAllocator());
state.PushBack(light_enabled, res.doc()->GetAllocator());
res.add_data(state);
}
}
/**
* write([name: str, state: float], ...)
*/
void Lights::write(Request &req, Response &res) {
// check light cache
if (!this->lights) {
return;
}
// loop parameters
for (Value &param : req.params.GetArray()) {
// check params
if (!param.IsArray()) {
error(res, "parameters must be arrays");
return;
}
if (param.Size() < 2) {
error_params_insufficient(res);
continue;
}
if (!param[0].IsString()) {
error_type(res, "name", "string");
continue;
}
if (!param[1].IsFloat() && !param[1].IsInt()) {
error_type(res, "state", "float");
continue;
}
// get params
auto light_name = param[0].GetString();
auto light_state = param[1].GetFloat();
// write light state
if (!this->write_light(light_name, light_state)) {
error_unknown(res, "light", light_name);
continue;
}
}
}
/**
* write_reset()
* write_reset([name: str], ...)
*/
void Lights::write_reset(Request &req, Response &res) {
// check light cache
if (!this->lights) {
return;
}
// get params
auto params = req.params.GetArray();
// write_reset()
if (params.Size() == 0) {
if (lights != nullptr) {
for (auto &light : *this->lights) {
light.override_enabled = false;
}
}
return;
}
// loop parameters
for (Value &param : req.params.GetArray()) {
// check params
if (!param.IsArray()) {
error(res, "parameters must be arrays");
return;
}
if (param.Size() < 1) {
error_params_insufficient(res);
continue;
}
if (!param[0].IsString()) {
error_type(res, "name", "string");
continue;
}
// get params
auto light_name = param[0].GetString();
// write analog state
if (!this->write_light_reset(light_name)) {
error_unknown(res, "analog", light_name);
continue;
}
}
}
bool Lights::write_light(std::string name, float state) {
// check light cache
if (!this->lights) {
return false;
}
// find light
for (auto &light : *this->lights) {
if (light.getName() == name) {
light.override_state = CLAMP(state, 0.f, 1.f);
light.override_enabled = true;
return true;
}
}
// unknown light
return false;
}
bool Lights::write_light_reset(std::string name) {
// check light cache
if (!this->lights) {
return false;
}
// find light
for (auto &light : *this->lights) {
if (light.getName() == name) {
light.override_enabled = false;
return true;
}
}
// unknown light
return false;
}
}
+28 -28
View File
@@ -1,28 +1,28 @@
#pragma once
#include <vector>
#include "api/module.h"
#include "api/request.h"
#include "cfg/api.h"
namespace api::modules {
class Lights : public Module {
public:
Lights();
private:
// state
std::vector<Light> *lights;
// function definitions
void read(Request &req, Response &res);
void write(Request &req, Response &res);
void write_reset(Request &req, Response &res);
// helper
bool write_light(std::string name, float state);
bool write_light_reset(std::string name);
};
}
#pragma once
#include <vector>
#include "api/module.h"
#include "api/request.h"
#include "cfg/api.h"
namespace api::modules {
class Lights : public Module {
public:
Lights();
private:
// state
std::vector<Light> *lights;
// function definitions
void read(Request &req, Response &res);
void write(Request &req, Response &res);
void write_reset(Request &req, Response &res);
// helper
bool write_light(std::string name, float state);
bool write_light_reset(std::string name);
};
}
+233 -233
View File
@@ -1,233 +1,233 @@
#include "memory.h"
#include <functional>
#include <mutex>
#include "external/rapidjson/document.h"
#include "util/fileutils.h"
#include "util/libutils.h"
#include "util/memutils.h"
#include "util/sigscan.h"
#include "util/utils.h"
using namespace std::placeholders;
using namespace rapidjson;
namespace api::modules {
// global lock to prevent simultaneous access to memory
static std::mutex MEMORY_LOCK;
Memory::Memory() : Module("memory", true) {
functions["write"] = std::bind(&Memory::write, this, _1, _2);
functions["read"] = std::bind(&Memory::read, this, _1, _2);
functions["signature"] = std::bind(&Memory::signature, this, _1, _2);
}
/**
* write(dll_name: str, data: hex, offset: uint)
*/
void Memory::write(Request &req, Response &res) {
std::lock_guard<std::mutex> lock(MEMORY_LOCK);
// check params
if (req.params.Size() < 3) {
return error_params_insufficient(res);
}
if (!req.params[0].IsString()) {
return error_type(res, "dll_name", "str");
}
if (!req.params[1].IsString() || (req.params[1].GetStringLength() & 1)) {
return error_type(res, "data", "hex string");
}
if (!req.params[2].IsUint()) {
return error_type(res, "offset", "uint");
}
// get params
auto dll_name = req.params[0].GetString();
auto dll_path = MODULE_PATH / dll_name;
auto data = req.params[1].GetString();
intptr_t offset = req.params[2].GetUint();
// convert data to bin
size_t data_bin_size = strlen(data) / 2;
auto data_bin = std::make_unique<uint8_t[]>(data_bin_size);
hex2bin(data, data_bin.get());
// check if file exists in modules
if (!fileutils::file_exists(dll_path)) {
return error(res, "Couldn't find " + dll_path.string());
}
// get module
auto module = libutils::try_module(dll_name);
if (!module) {
return error(res, "Couldn't find module.");
}
// convert offset to RVA
offset = libutils::offset2rva(dll_path, offset);
if (offset == ~0) {
return error(res, "Couldn't convert offset to RVA.");
}
// get module information
MODULEINFO module_info {};
if (!GetModuleInformation(GetCurrentProcess(), module, &module_info, sizeof(MODULEINFO))) {
return error(res, "Couldn't get module information.");
}
// check bounds
if (offset + data_bin_size >= (size_t) module_info.lpBaseOfDll + module_info.SizeOfImage) {
return error(res, "Data out of bounds.");
}
auto data_pos = reinterpret_cast<uint8_t *>(module_info.lpBaseOfDll) + offset;
// replace data
memutils::VProtectGuard guard(data_pos, data_bin_size);
memcpy(data_pos, data_bin.get(), data_bin_size);
}
/**
* read(dll_name: str, offset: uint, size: uint)
*/
void Memory::read(Request &req, Response &res) {
std::lock_guard<std::mutex> lock(MEMORY_LOCK);
// check params
if (req.params.Size() < 3) {
return error_params_insufficient(res);
}
if (!req.params[0].IsString()) {
return error_type(res, "dll_name", "str");
}
if (!req.params[1].IsUint()) {
return error_type(res, "offset", "uint");
}
if (!req.params[2].IsUint()) {
return error_type(res, "size", "uint");
}
// get params
auto dll_name = req.params[0].GetString();
auto dll_path = MODULE_PATH / dll_name;
intptr_t offset = req.params[1].GetUint();
auto size = req.params[2].GetUint();
// check if file exists in modules
if (!fileutils::file_exists(dll_path)) {
return error(res, "Couldn't find " + dll_path.string());
}
// get module
auto module = libutils::try_module(dll_name);
if (!module) {
return error(res, "Couldn't find module.");
}
// convert offset to RVA
offset = libutils::offset2rva(dll_path, offset);
if (offset == ~0) {
return error(res, "Couldn't convert offset to RVA.");
}
// get module information
MODULEINFO module_info {};
if (!GetModuleInformation(GetCurrentProcess(), module, &module_info, sizeof(MODULEINFO))) {
return error(res, "Couldn't get module information.");
}
// check bounds
auto max = offset + size;
if ((size_t) max >= (size_t) module_info.lpBaseOfDll + module_info.SizeOfImage) {
return error(res, "Data out of bounds.");
}
// read memory to hex (without virtual protect)
std::string hex = bin2hex((uint8_t*) module_info.lpBaseOfDll + offset, size);
Value hex_val(hex.c_str(), res.doc()->GetAllocator());
res.add_data(hex_val);
}
/**
* signature(
* dll_name: str,
* signature: hex,
* replacement: hex,
* offset: uint,
* usage: uint)
*
* Both signature and replacement will ignore bytes specified as "??" in the hex string.
* The offset specifies the offset between the found signature and the position to write the replacement to.
* The resulting integer is the file offset where the replacement was written to.
*/
void Memory::signature(Request &req, Response &res) {
std::lock_guard<std::mutex> lock(MEMORY_LOCK);
// check params
if (req.params.Size() < 5) {
return error_params_insufficient(res);
}
if (!req.params[0].IsString()) {
return error_type(res, "dll_name", "string");
}
if (!req.params[1].IsString() || (req.params[1].GetStringLength() & 1)) {
return error_type(res, "signature", "hex string");
}
if (!req.params[2].IsString() || (req.params[2].GetStringLength() & 1)) {
return error_type(res, "replacement", "hex string");
}
if (!req.params[3].IsUint()) {
return error_type(res, "offset", "uint");
}
if (!req.params[4].IsUint()) {
return error_type(res, "usage", "uint");
}
// get params
auto dll_name = req.params[0].GetString();
auto dll_path = MODULE_PATH / dll_name;
auto signature = req.params[1].GetString();
auto replacement = req.params[2].GetString();
auto offset = req.params[3].GetUint();
auto usage = req.params[4].GetUint();
// check if file exists in modules
if (!fileutils::file_exists(dll_path)) {
return error(res, "Couldn't find " + dll_path.string());
}
// get module
auto module = libutils::try_module(dll_name);
if (!module) {
return error(res, "Couldn't find module.");
}
// execute
auto result = replace_pattern(
module,
signature,
replacement,
offset,
usage
);
// check result
if (!result) {
return error(res, std::string("Pattern not found in memory of ") + dll_name);
}
// convert to offset
auto rva = result - reinterpret_cast<intptr_t>(module);
result = libutils::rva2offset(dll_path, rva);
if (result == -1) {
return error(res, "Couldn't convert RVA to file offset.");
}
// add result
Value result_val(result);
res.add_data(result_val);
}
}
#include "memory.h"
#include <functional>
#include <mutex>
#include "external/rapidjson/document.h"
#include "util/fileutils.h"
#include "util/libutils.h"
#include "util/memutils.h"
#include "util/sigscan.h"
#include "util/utils.h"
using namespace std::placeholders;
using namespace rapidjson;
namespace api::modules {
// global lock to prevent simultaneous access to memory
static std::mutex MEMORY_LOCK;
Memory::Memory() : Module("memory", true) {
functions["write"] = std::bind(&Memory::write, this, _1, _2);
functions["read"] = std::bind(&Memory::read, this, _1, _2);
functions["signature"] = std::bind(&Memory::signature, this, _1, _2);
}
/**
* write(dll_name: str, data: hex, offset: uint)
*/
void Memory::write(Request &req, Response &res) {
std::lock_guard<std::mutex> lock(MEMORY_LOCK);
// check params
if (req.params.Size() < 3) {
return error_params_insufficient(res);
}
if (!req.params[0].IsString()) {
return error_type(res, "dll_name", "str");
}
if (!req.params[1].IsString() || (req.params[1].GetStringLength() & 1)) {
return error_type(res, "data", "hex string");
}
if (!req.params[2].IsUint()) {
return error_type(res, "offset", "uint");
}
// get params
auto dll_name = req.params[0].GetString();
auto dll_path = MODULE_PATH / dll_name;
auto data = req.params[1].GetString();
intptr_t offset = req.params[2].GetUint();
// convert data to bin
size_t data_bin_size = strlen(data) / 2;
auto data_bin = std::make_unique<uint8_t[]>(data_bin_size);
hex2bin(data, data_bin.get());
// check if file exists in modules
if (!fileutils::file_exists(dll_path)) {
return error(res, "Couldn't find " + dll_path.string());
}
// get module
auto module = libutils::try_module(dll_name);
if (!module) {
return error(res, "Couldn't find module.");
}
// convert offset to RVA
offset = libutils::offset2rva(dll_path, offset);
if (offset == ~0) {
return error(res, "Couldn't convert offset to RVA.");
}
// get module information
MODULEINFO module_info {};
if (!GetModuleInformation(GetCurrentProcess(), module, &module_info, sizeof(MODULEINFO))) {
return error(res, "Couldn't get module information.");
}
// check bounds
if (offset + data_bin_size >= (size_t) module_info.lpBaseOfDll + module_info.SizeOfImage) {
return error(res, "Data out of bounds.");
}
auto data_pos = reinterpret_cast<uint8_t *>(module_info.lpBaseOfDll) + offset;
// replace data
memutils::VProtectGuard guard(data_pos, data_bin_size);
memcpy(data_pos, data_bin.get(), data_bin_size);
}
/**
* read(dll_name: str, offset: uint, size: uint)
*/
void Memory::read(Request &req, Response &res) {
std::lock_guard<std::mutex> lock(MEMORY_LOCK);
// check params
if (req.params.Size() < 3) {
return error_params_insufficient(res);
}
if (!req.params[0].IsString()) {
return error_type(res, "dll_name", "str");
}
if (!req.params[1].IsUint()) {
return error_type(res, "offset", "uint");
}
if (!req.params[2].IsUint()) {
return error_type(res, "size", "uint");
}
// get params
auto dll_name = req.params[0].GetString();
auto dll_path = MODULE_PATH / dll_name;
intptr_t offset = req.params[1].GetUint();
auto size = req.params[2].GetUint();
// check if file exists in modules
if (!fileutils::file_exists(dll_path)) {
return error(res, "Couldn't find " + dll_path.string());
}
// get module
auto module = libutils::try_module(dll_name);
if (!module) {
return error(res, "Couldn't find module.");
}
// convert offset to RVA
offset = libutils::offset2rva(dll_path, offset);
if (offset == ~0) {
return error(res, "Couldn't convert offset to RVA.");
}
// get module information
MODULEINFO module_info {};
if (!GetModuleInformation(GetCurrentProcess(), module, &module_info, sizeof(MODULEINFO))) {
return error(res, "Couldn't get module information.");
}
// check bounds
auto max = offset + size;
if ((size_t) max >= (size_t) module_info.lpBaseOfDll + module_info.SizeOfImage) {
return error(res, "Data out of bounds.");
}
// read memory to hex (without virtual protect)
std::string hex = bin2hex((uint8_t*) module_info.lpBaseOfDll + offset, size);
Value hex_val(hex.c_str(), res.doc()->GetAllocator());
res.add_data(hex_val);
}
/**
* signature(
* dll_name: str,
* signature: hex,
* replacement: hex,
* offset: uint,
* usage: uint)
*
* Both signature and replacement will ignore bytes specified as "??" in the hex string.
* The offset specifies the offset between the found signature and the position to write the replacement to.
* The resulting integer is the file offset where the replacement was written to.
*/
void Memory::signature(Request &req, Response &res) {
std::lock_guard<std::mutex> lock(MEMORY_LOCK);
// check params
if (req.params.Size() < 5) {
return error_params_insufficient(res);
}
if (!req.params[0].IsString()) {
return error_type(res, "dll_name", "string");
}
if (!req.params[1].IsString() || (req.params[1].GetStringLength() & 1)) {
return error_type(res, "signature", "hex string");
}
if (!req.params[2].IsString() || (req.params[2].GetStringLength() & 1)) {
return error_type(res, "replacement", "hex string");
}
if (!req.params[3].IsUint()) {
return error_type(res, "offset", "uint");
}
if (!req.params[4].IsUint()) {
return error_type(res, "usage", "uint");
}
// get params
auto dll_name = req.params[0].GetString();
auto dll_path = MODULE_PATH / dll_name;
auto signature = req.params[1].GetString();
auto replacement = req.params[2].GetString();
auto offset = req.params[3].GetUint();
auto usage = req.params[4].GetUint();
// check if file exists in modules
if (!fileutils::file_exists(dll_path)) {
return error(res, "Couldn't find " + dll_path.string());
}
// get module
auto module = libutils::try_module(dll_name);
if (!module) {
return error(res, "Couldn't find module.");
}
// execute
auto result = replace_pattern(
module,
signature,
replacement,
offset,
usage
);
// check result
if (!result) {
return error(res, std::string("Pattern not found in memory of ") + dll_name);
}
// convert to offset
auto rva = result - reinterpret_cast<intptr_t>(module);
result = libutils::rva2offset(dll_path, rva);
if (result == -1) {
return error(res, "Couldn't convert RVA to file offset.");
}
// add result
Value result_val(result);
res.add_data(result_val);
}
}
+19 -19
View File
@@ -1,19 +1,19 @@
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class Memory : public Module {
public:
Memory();
private:
// function definitions
void write(Request &req, Response &res);
void read(Request &req, Response &res);
void signature(Request &req, Response &res);
};
}
#pragma once
#include "api/module.h"
#include "api/request.h"
namespace api::modules {
class Memory : public Module {
public:
Memory();
private:
// function definitions
void write(Request &req, Response &res);
void read(Request &req, Response &res);
void signature(Request &req, Response &res);
};
}
+55 -55
View File
@@ -1,55 +1,55 @@
#include "request.h"
#include "../util/logging.h"
#include "module.h"
using namespace rapidjson;
namespace api {
Request::Request(rapidjson::Document &document) {
Value::MemberIterator it;
this->parse_error = false;
// get ID
it = document.FindMember("id");
if (it == document.MemberEnd() || !(*it).value.IsUint64()) {
log_warning("api", "Request ID is invalid");
this->parse_error = true;
return;
}
this->id = (*it).value.GetUint64();
// get module
it = document.FindMember("module");
if (it == document.MemberEnd() || !(*it).value.IsString()) {
log_warning("api", "Request module is invalid");
this->parse_error = true;
return;
}
this->module = (*it).value.GetString();
// get function
it = document.FindMember("function");
if (it == document.MemberEnd() || !(*it).value.IsString()) {
log_warning("api", "Request function is invalid");
this->parse_error = true;
return;
}
this->function = (*it).value.GetString();
// get params
it = document.FindMember("params");
if (it == document.MemberEnd() || !(*it).value.IsArray()) {
log_warning("api", "Request params is invalid");
this->parse_error = true;
return;
}
this->params = document["params"];
// log request
if (LOGGING) {
log_info("api", "new request > id: {}, module: {}, function: {}",
this->id, this->module, this->function);
}
}
}
#include "request.h"
#include "../util/logging.h"
#include "module.h"
using namespace rapidjson;
namespace api {
Request::Request(rapidjson::Document &document) {
Value::MemberIterator it;
this->parse_error = false;
// get ID
it = document.FindMember("id");
if (it == document.MemberEnd() || !(*it).value.IsUint64()) {
log_warning("api", "Request ID is invalid");
this->parse_error = true;
return;
}
this->id = (*it).value.GetUint64();
// get module
it = document.FindMember("module");
if (it == document.MemberEnd() || !(*it).value.IsString()) {
log_warning("api", "Request module is invalid");
this->parse_error = true;
return;
}
this->module = (*it).value.GetString();
// get function
it = document.FindMember("function");
if (it == document.MemberEnd() || !(*it).value.IsString()) {
log_warning("api", "Request function is invalid");
this->parse_error = true;
return;
}
this->function = (*it).value.GetString();
// get params
it = document.FindMember("params");
if (it == document.MemberEnd() || !(*it).value.IsArray()) {
log_warning("api", "Request params is invalid");
this->parse_error = true;
return;
}
this->params = document["params"];
// log request
if (LOGGING) {
log_info("api", "new request > id: {}, module: {}, function: {}",
this->id, this->module, this->function);
}
}
}
+21 -21
View File
@@ -1,21 +1,21 @@
#pragma once
#include <string>
#include <stdint.h>
#include "external/rapidjson/document.h"
namespace api {
class Request {
public:
uint64_t id;
std::string module;
std::string function;
rapidjson::Value params;
bool parse_error;
Request(rapidjson::Document &document);
};
}
#pragma once
#include <string>
#include <stdint.h>
#include "external/rapidjson/document.h"
namespace api {
class Request {
public:
uint64_t id;
std::string module;
std::string function;
rapidjson::Value params;
bool parse_error;
Request(rapidjson::Document &document);
};
}
+4 -4
View File
@@ -1,4 +1,4 @@
# SpiceAPI Arduino Library
This library is still a bit experimental and might contain bugs.
To use this library, it's recommended to just copy the Arduino project and start from that.
# SpiceAPI Arduino Library
This library is still a bit experimental and might contain bugs.
To use this library, it's recommended to just copy the Arduino project and start from that.
+65 -65
View File
@@ -1,65 +1,65 @@
#ifndef SPICEAPI_RC4_H
#define SPICEAPI_RC4_H
#include <stdint.h>
#include <stddef.h>
namespace spiceapi {
class RC4 {
private:
uint8_t s_box[256];
size_t a = 0, b = 0;
public:
RC4(uint8_t *key, size_t key_size);
void crypt(uint8_t *data, size_t size);
};
}
spiceapi::RC4::RC4(uint8_t *key, size_t key_size) {
// initialize S-BOX
for (size_t i = 0; i < sizeof(s_box); i++)
s_box[i] = (uint8_t) i;
// check key size
if (!key_size)
return;
// KSA
size_t j = 0;
for (size_t i = 0; i < sizeof(s_box); i++) {
// update
j = (j + s_box[i] + key[i % key_size]) % sizeof(s_box);
// swap
auto tmp = s_box[i];
s_box[i] = s_box[j];
s_box[j] = tmp;
}
}
void spiceapi::RC4::crypt(uint8_t *data, size_t size) {
// iterate all bytes
for (size_t pos = 0; pos < size; pos++) {
// update
a = (a + 1) % sizeof(s_box);
b = (b + s_box[a]) % sizeof(s_box);
// swap
auto tmp = s_box[a];
s_box[a] = s_box[b];
s_box[b] = tmp;
// crypt
data[pos] ^= s_box[(s_box[a] + s_box[b]) % sizeof(s_box)];
}
}
#endif //SPICEAPI_RC4_H
#ifndef SPICEAPI_RC4_H
#define SPICEAPI_RC4_H
#include <stdint.h>
#include <stddef.h>
namespace spiceapi {
class RC4 {
private:
uint8_t s_box[256];
size_t a = 0, b = 0;
public:
RC4(uint8_t *key, size_t key_size);
void crypt(uint8_t *data, size_t size);
};
}
spiceapi::RC4::RC4(uint8_t *key, size_t key_size) {
// initialize S-BOX
for (size_t i = 0; i < sizeof(s_box); i++)
s_box[i] = (uint8_t) i;
// check key size
if (!key_size)
return;
// KSA
size_t j = 0;
for (size_t i = 0; i < sizeof(s_box); i++) {
// update
j = (j + s_box[i] + key[i % key_size]) % sizeof(s_box);
// swap
auto tmp = s_box[i];
s_box[i] = s_box[j];
s_box[j] = tmp;
}
}
void spiceapi::RC4::crypt(uint8_t *data, size_t size) {
// iterate all bytes
for (size_t pos = 0; pos < size; pos++) {
// update
a = (a + 1) % sizeof(s_box);
b = (b + s_box[a]) % sizeof(s_box);
// swap
auto tmp = s_box[a];
s_box[a] = s_box[b];
s_box[b] = tmp;
// crypt
data[pos] ^= s_box[(s_box[a] + s_box[b]) % sizeof(s_box)];
}
}
#endif //SPICEAPI_RC4_H
+172 -172
View File
@@ -1,172 +1,172 @@
/*
* SpiceAPI Arduino Example Project
*
* To enable it in SpiceTools, use "-api 1337 -apipass changeme -apiserial COM1" or similar.
*/
/*
* SpiceAPI Wrapper Buffer Sizes
*
* They should be as big as possible to be able to create/parse
* some of the bigger requests/responses. Due to dynamic memory
* limitations of some weaker devices, if you set them too high
* you will probably experience crashes/bugs/problems, one
* example would be "Request ID is invalid" in the log.
*/
#define SPICEAPI_WRAPPER_BUFFER_SIZE 256
#define SPICEAPI_WRAPPER_BUFFER_SIZE_STR 256
/*
* WiFi Support
* Uncomment to enable the wireless API interface.
*/
//#define ENABLE_WIFI
/*
* WiFi Settings
* You can ignore these if you don't plan on using WiFi
*/
#ifdef ENABLE_WIFI
#include <ESP8266WiFi.h>
WiFiClient client;
#define SPICEAPI_INTERFACE client
#define SPICEAPI_INTERFACE_WIFICLIENT
#define SPICEAPI_INTERFACE_WIFICLIENT_HOST "192.168.178.143"
#define SPICEAPI_INTERFACE_WIFICLIENT_PORT 1337
#define WIFI_SSID "MySSID"
#define WIFI_PASS "MyWifiPassword"
#endif
/*
* This is the interface a serial connection will use.
* You can change this to another Serial port, e.g. with an
* Arduino Mega you can use Serial1/Serial2/Serial3.
*/
#ifndef ENABLE_WIFI
#define SPICEAPI_INTERFACE Serial
#endif
/*
* SpiceAPI Includes
*
* If you have the JSON strings beforehands or want to craft them
* manually, you don't have to import the wrappers at all and can
* use Connection::request to send and receive raw JSON strings.
*/
#include "connection.h"
#include "wrappers.h"
/*
* This global object represents the API connection.
* The first parameter is the buffer size of the JSON string
* we're receiving. So a size of 512 will only be able to
* hold a JSON of 512 characters maximum.
*
* An empty password string means no password is being used.
* This is the recommended when using Serial only.
*/
spiceapi::Connection CON(512, "changeme");
void setup() {
#ifdef ENABLE_WIFI
/*
* When using WiFi, we can use the Serial interface for debugging.
* You can open Serial Monitor and see what IP it gets assigned to.
*/
Serial.begin(57600);
// set WiFi mode to station (disables integrated AP)
WiFi.mode(WIFI_STA);
// now try connecting to our Router/AP
Serial.print("Connecting");
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// print debug info over serial
Serial.print("\nLocal IP: ");
Serial.println(WiFi.localIP());
#else
/*
* Since the API makes use of the Serial module, we need to
* set it up using our preferred baud rate manually.
*/
SPICEAPI_INTERFACE.begin(57600);
while (!SPICEAPI_INTERFACE);
#endif
}
void loop() {
/*
* Here's a few tests/examples on how to make use of the wrappers.
*/
// insert cards for P1/P2
spiceapi::card_insert(CON, 0, "E004012345678901");
spiceapi::card_insert(CON, 1, "E004012345678902");
// insert a single coin / multiple coins
spiceapi::coin_insert(CON);
spiceapi::coin_insert(CON, 3);
// get the IIDX led ticker text
char ticker[9];
if (spiceapi::iidx_ticker_get(CON, ticker)) {
// if a function returns true, that means success
// now we can do something with the ticker as if it was a string
//Serial1.println(ticker);
}
// get AVS info
spiceapi::InfoAvs avs_info {};
if (spiceapi::info_avs(CON, avs_info)) {
//Serial1.println(avs_info.model);
}
// enter some keys on P1 keypad (blocks until sequence is entered fully)
spiceapi::keypads_write(CON, 0, "1234");
// get light states
spiceapi::LightState lights[8];
size_t lights_size = spiceapi::lights_read(CON, lights, 8);
for (size_t i = 0; i < lights_size; i++) {
auto &light = lights[i];
//Serial1.println(light.name);
//Serial1.println(light.value);
// modify value to full bright
light.value = 1.f;
}
// send back modified light states
spiceapi::lights_write(CON, lights, lights_size);
// refresh session (generates new crypt key, not that important for serial)
spiceapi::control_session_refresh(CON);
// you can also manually send requests without the wrappers
// this avoids json generation, but you still need to parse it in some way
const char *answer_json = CON.request(
"{"
"\"id\": 0,"
"\"module\":\"coin\","
"\"function\":\"insert\","
"\"params\":[]"
"}"
);
/*
* For more functions/information, just check out wrappers.h yourself.
* Have fun :)
*/
delay(5000);
}
/*
* SpiceAPI Arduino Example Project
*
* To enable it in SpiceTools, use "-api 1337 -apipass changeme -apiserial COM1" or similar.
*/
/*
* SpiceAPI Wrapper Buffer Sizes
*
* They should be as big as possible to be able to create/parse
* some of the bigger requests/responses. Due to dynamic memory
* limitations of some weaker devices, if you set them too high
* you will probably experience crashes/bugs/problems, one
* example would be "Request ID is invalid" in the log.
*/
#define SPICEAPI_WRAPPER_BUFFER_SIZE 256
#define SPICEAPI_WRAPPER_BUFFER_SIZE_STR 256
/*
* WiFi Support
* Uncomment to enable the wireless API interface.
*/
//#define ENABLE_WIFI
/*
* WiFi Settings
* You can ignore these if you don't plan on using WiFi
*/
#ifdef ENABLE_WIFI
#include <ESP8266WiFi.h>
WiFiClient client;
#define SPICEAPI_INTERFACE client
#define SPICEAPI_INTERFACE_WIFICLIENT
#define SPICEAPI_INTERFACE_WIFICLIENT_HOST "192.168.178.143"
#define SPICEAPI_INTERFACE_WIFICLIENT_PORT 1337
#define WIFI_SSID "MySSID"
#define WIFI_PASS "MyWifiPassword"
#endif
/*
* This is the interface a serial connection will use.
* You can change this to another Serial port, e.g. with an
* Arduino Mega you can use Serial1/Serial2/Serial3.
*/
#ifndef ENABLE_WIFI
#define SPICEAPI_INTERFACE Serial
#endif
/*
* SpiceAPI Includes
*
* If you have the JSON strings beforehands or want to craft them
* manually, you don't have to import the wrappers at all and can
* use Connection::request to send and receive raw JSON strings.
*/
#include "connection.h"
#include "wrappers.h"
/*
* This global object represents the API connection.
* The first parameter is the buffer size of the JSON string
* we're receiving. So a size of 512 will only be able to
* hold a JSON of 512 characters maximum.
*
* An empty password string means no password is being used.
* This is the recommended when using Serial only.
*/
spiceapi::Connection CON(512, "changeme");
void setup() {
#ifdef ENABLE_WIFI
/*
* When using WiFi, we can use the Serial interface for debugging.
* You can open Serial Monitor and see what IP it gets assigned to.
*/
Serial.begin(57600);
// set WiFi mode to station (disables integrated AP)
WiFi.mode(WIFI_STA);
// now try connecting to our Router/AP
Serial.print("Connecting");
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// print debug info over serial
Serial.print("\nLocal IP: ");
Serial.println(WiFi.localIP());
#else
/*
* Since the API makes use of the Serial module, we need to
* set it up using our preferred baud rate manually.
*/
SPICEAPI_INTERFACE.begin(57600);
while (!SPICEAPI_INTERFACE);
#endif
}
void loop() {
/*
* Here's a few tests/examples on how to make use of the wrappers.
*/
// insert cards for P1/P2
spiceapi::card_insert(CON, 0, "E004012345678901");
spiceapi::card_insert(CON, 1, "E004012345678902");
// insert a single coin / multiple coins
spiceapi::coin_insert(CON);
spiceapi::coin_insert(CON, 3);
// get the IIDX led ticker text
char ticker[9];
if (spiceapi::iidx_ticker_get(CON, ticker)) {
// if a function returns true, that means success
// now we can do something with the ticker as if it was a string
//Serial1.println(ticker);
}
// get AVS info
spiceapi::InfoAvs avs_info {};
if (spiceapi::info_avs(CON, avs_info)) {
//Serial1.println(avs_info.model);
}
// enter some keys on P1 keypad (blocks until sequence is entered fully)
spiceapi::keypads_write(CON, 0, "1234");
// get light states
spiceapi::LightState lights[8];
size_t lights_size = spiceapi::lights_read(CON, lights, 8);
for (size_t i = 0; i < lights_size; i++) {
auto &light = lights[i];
//Serial1.println(light.name);
//Serial1.println(light.value);
// modify value to full bright
light.value = 1.f;
}
// send back modified light states
spiceapi::lights_write(CON, lights, lights_size);
// refresh session (generates new crypt key, not that important for serial)
spiceapi::control_session_refresh(CON);
// you can also manually send requests without the wrappers
// this avoids json generation, but you still need to parse it in some way
const char *answer_json = CON.request(
"{"
"\"id\": 0,"
"\"module\":\"coin\","
"\"function\":\"insert\","
"\"params\":[]"
"}"
);
/*
* For more functions/information, just check out wrappers.h yourself.
* Have fun :)
*/
delay(5000);
}
File diff suppressed because it is too large Load Diff
+8 -8
View File
@@ -1,8 +1,8 @@
# SpiceAPI C++ Library
This library is still a bit experimental and might contain bugs.
To include it into your project, it's recommended to just copy the
files into your source directory.
To use the wrappers, RapidJSON is required and you might need to
adjust the include paths for your project's build.
# SpiceAPI C++ Library
This library is still a bit experimental and might contain bugs.
To include it into your project, it's recommended to just copy the
files into your source directory.
To use the wrappers, RapidJSON is required and you might need to
adjust the include paths for your project's build.
+24 -24
View File
@@ -1,24 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
+181 -181
View File
@@ -1,181 +1,181 @@
#include <iostream>
#include <ws2tcpip.h>
#include "connection.h"
namespace spiceapi {
// settings
static const size_t RECEIVE_BUFFER_SIZE = 64 * 1024;
static const int RECEIVE_TIMEOUT = 1000;
}
spiceapi::Connection::Connection(std::string host, uint16_t port, std::string password) {
this->host = host;
this->port = port;
this->password = password;
this->socket = INVALID_SOCKET;
this->cipher = nullptr;
// WSA startup
WSADATA wsa_data;
int error = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (error) {
std::cerr << "Failed to start WSA: " << error << std::endl;
exit(1);
}
}
spiceapi::Connection::~Connection() {
// clean up
if (this->cipher != nullptr)
delete this->cipher;
// cleanup WSA
WSACleanup();
}
void spiceapi::Connection::cipher_alloc() {
// delete old cipher
if (this->cipher != nullptr) {
delete this->cipher;
this->cipher = nullptr;
}
// create new cipher if password is set
if (this->password.length() > 0) {
this->cipher = new RC4(
(uint8_t *) this->password.c_str(),
strlen(this->password.c_str()));
}
}
bool spiceapi::Connection::check() {
int result = 0;
// check if socket is invalid
if (this->socket == INVALID_SOCKET) {
// get all addresses
addrinfo *addr_list;
addrinfo hints{};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if ((result = getaddrinfo(
this->host.c_str(),
std::to_string(this->port).c_str(),
&hints,
&addr_list))) {
std::cerr << "getaddrinfo failed: " << result << std::endl;
return false;
}
// check all addresses
for (addrinfo *addr = addr_list; addr != NULL; addr = addr->ai_next) {
// try open socket
this->socket = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (this->socket == INVALID_SOCKET) {
std::cerr << "socket failed: " << WSAGetLastError() << std::endl;
freeaddrinfo(addr_list);
return false;
}
// try connect
result = connect(this->socket, addr->ai_addr, (int) addr->ai_addrlen);
if (result == SOCKET_ERROR) {
closesocket(this->socket);
this->socket = INVALID_SOCKET;
continue;
}
// configure socket
int opt_val;
opt_val = 1;
setsockopt(this->socket, IPPROTO_TCP, TCP_NODELAY, (const char*) &opt_val, sizeof(opt_val));
opt_val = RECEIVE_TIMEOUT;
setsockopt(this->socket, SOL_SOCKET, SO_RCVTIMEO, (const char*) &opt_val, sizeof(opt_val));
// connection successful
this->cipher_alloc();
break;
}
// check if successful
freeaddrinfo(addr_list);
if (this->socket == INVALID_SOCKET) {
return false;
}
}
// socket probably still valid
return true;
}
void spiceapi::Connection::change_pass(std::string password) {
this->password = password;
this->cipher_alloc();
}
std::string spiceapi::Connection::request(std::string json) {
// check connection
if (!this->check())
return "";
// crypt
auto json_len = strlen(json.c_str()) + 1;
uint8_t* json_data = new uint8_t[json_len];
memcpy(json_data, json.c_str(), json_len);
if (this->cipher != nullptr)
this->cipher->crypt(json_data, json_len);
// send
auto send_result = send(this->socket, (const char*) json_data, (int) json_len, 0);
delete[] json_data;
if (send_result == SOCKET_ERROR || send_result < (int) json_len) {
closesocket(this->socket);
this->socket = INVALID_SOCKET;
return "";
}
// receive
uint8_t receive_data[RECEIVE_BUFFER_SIZE];
size_t receive_data_len = 0;
int receive_result;
while ((receive_result = recv(
this->socket,
(char*) &receive_data[receive_data_len],
sizeof(receive_data) - receive_data_len, 0)) > 0) {
// check for buffer overflow
if (receive_data_len + receive_result >= sizeof(receive_data)) {
closesocket(this->socket);
this->socket = INVALID_SOCKET;
return "";
}
// crypt
if (this->cipher != nullptr)
this->cipher->crypt(&receive_data[receive_data_len], (size_t) receive_result);
// increase received data length
receive_data_len += receive_result;
// check for message end
if (receive_data[receive_data_len - 1] == 0)
break;
}
// return resulting json
if (receive_data_len > 0) {
return std::string((const char *) &receive_data[0], receive_data_len - 1);
} else {
// receive error
this->socket = INVALID_SOCKET;
return "";
}
}
#include <iostream>
#include <ws2tcpip.h>
#include "connection.h"
namespace spiceapi {
// settings
static const size_t RECEIVE_BUFFER_SIZE = 64 * 1024;
static const int RECEIVE_TIMEOUT = 1000;
}
spiceapi::Connection::Connection(std::string host, uint16_t port, std::string password) {
this->host = host;
this->port = port;
this->password = password;
this->socket = INVALID_SOCKET;
this->cipher = nullptr;
// WSA startup
WSADATA wsa_data;
int error = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (error) {
std::cerr << "Failed to start WSA: " << error << std::endl;
exit(1);
}
}
spiceapi::Connection::~Connection() {
// clean up
if (this->cipher != nullptr)
delete this->cipher;
// cleanup WSA
WSACleanup();
}
void spiceapi::Connection::cipher_alloc() {
// delete old cipher
if (this->cipher != nullptr) {
delete this->cipher;
this->cipher = nullptr;
}
// create new cipher if password is set
if (this->password.length() > 0) {
this->cipher = new RC4(
(uint8_t *) this->password.c_str(),
strlen(this->password.c_str()));
}
}
bool spiceapi::Connection::check() {
int result = 0;
// check if socket is invalid
if (this->socket == INVALID_SOCKET) {
// get all addresses
addrinfo *addr_list;
addrinfo hints{};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if ((result = getaddrinfo(
this->host.c_str(),
std::to_string(this->port).c_str(),
&hints,
&addr_list))) {
std::cerr << "getaddrinfo failed: " << result << std::endl;
return false;
}
// check all addresses
for (addrinfo *addr = addr_list; addr != NULL; addr = addr->ai_next) {
// try open socket
this->socket = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (this->socket == INVALID_SOCKET) {
std::cerr << "socket failed: " << WSAGetLastError() << std::endl;
freeaddrinfo(addr_list);
return false;
}
// try connect
result = connect(this->socket, addr->ai_addr, (int) addr->ai_addrlen);
if (result == SOCKET_ERROR) {
closesocket(this->socket);
this->socket = INVALID_SOCKET;
continue;
}
// configure socket
int opt_val;
opt_val = 1;
setsockopt(this->socket, IPPROTO_TCP, TCP_NODELAY, (const char*) &opt_val, sizeof(opt_val));
opt_val = RECEIVE_TIMEOUT;
setsockopt(this->socket, SOL_SOCKET, SO_RCVTIMEO, (const char*) &opt_val, sizeof(opt_val));
// connection successful
this->cipher_alloc();
break;
}
// check if successful
freeaddrinfo(addr_list);
if (this->socket == INVALID_SOCKET) {
return false;
}
}
// socket probably still valid
return true;
}
void spiceapi::Connection::change_pass(std::string password) {
this->password = password;
this->cipher_alloc();
}
std::string spiceapi::Connection::request(std::string json) {
// check connection
if (!this->check())
return "";
// crypt
auto json_len = strlen(json.c_str()) + 1;
uint8_t* json_data = new uint8_t[json_len];
memcpy(json_data, json.c_str(), json_len);
if (this->cipher != nullptr)
this->cipher->crypt(json_data, json_len);
// send
auto send_result = send(this->socket, (const char*) json_data, (int) json_len, 0);
delete[] json_data;
if (send_result == SOCKET_ERROR || send_result < (int) json_len) {
closesocket(this->socket);
this->socket = INVALID_SOCKET;
return "";
}
// receive
uint8_t receive_data[RECEIVE_BUFFER_SIZE];
size_t receive_data_len = 0;
int receive_result;
while ((receive_result = recv(
this->socket,
(char*) &receive_data[receive_data_len],
sizeof(receive_data) - receive_data_len, 0)) > 0) {
// check for buffer overflow
if (receive_data_len + receive_result >= sizeof(receive_data)) {
closesocket(this->socket);
this->socket = INVALID_SOCKET;
return "";
}
// crypt
if (this->cipher != nullptr)
this->cipher->crypt(&receive_data[receive_data_len], (size_t) receive_result);
// increase received data length
receive_data_len += receive_result;
// check for message end
if (receive_data[receive_data_len - 1] == 0)
break;
}
// return resulting json
if (receive_data_len > 0) {
return std::string((const char *) &receive_data[0], receive_data_len - 1);
} else {
// receive error
this->socket = INVALID_SOCKET;
return "";
}
}
+31 -31
View File
@@ -1,31 +1,31 @@
#ifndef SPICEAPI_CONNECTION_H
#define SPICEAPI_CONNECTION_H
#include <string>
#include <winsock2.h>
#include "rc4.h"
namespace spiceapi {
class Connection {
private:
std::string host;
uint16_t port;
std::string password;
SOCKET socket;
RC4* cipher;
void cipher_alloc();
public:
Connection(std::string host, uint16_t port, std::string password = "");
~Connection();
bool check();
void change_pass(std::string password);
std::string request(std::string json);
};
}
#endif //SPICEAPI_CONNECTION_H
#ifndef SPICEAPI_CONNECTION_H
#define SPICEAPI_CONNECTION_H
#include <string>
#include <winsock2.h>
#include "rc4.h"
namespace spiceapi {
class Connection {
private:
std::string host;
uint16_t port;
std::string password;
SOCKET socket;
RC4* cipher;
void cipher_alloc();
public:
Connection(std::string host, uint16_t port, std::string password = "");
~Connection();
bool check();
void change_pass(std::string password);
std::string request(std::string json);
};
}
#endif //SPICEAPI_CONNECTION_H
+45 -45
View File
@@ -1,45 +1,45 @@
#include "rc4.h"
#include <iterator>
spiceapi::RC4::RC4(uint8_t *key, size_t key_size) {
// initialize S-BOX
for (size_t i = 0; i < std::size(s_box); i++)
s_box[i] = (uint8_t) i;
// check key size
if (!key_size)
return;
// KSA
size_t j = 0;
for (size_t i = 0; i < std::size(s_box); i++) {
// update
j = (j + s_box[i] + key[i % key_size]) % std::size(s_box);
// swap
auto tmp = s_box[i];
s_box[i] = s_box[j];
s_box[j] = tmp;
}
}
void spiceapi::RC4::crypt(uint8_t *data, size_t size) {
// iterate all bytes
for (size_t pos = 0; pos < size; pos++) {
// update
a = (a + 1) % std::size(s_box);
b = (b + s_box[a]) % std::size(s_box);
// swap
auto tmp = s_box[a];
s_box[a] = s_box[b];
s_box[b] = tmp;
// crypt
data[pos] ^= s_box[(s_box[a] + s_box[b]) % std::size(s_box)];
}
}
#include "rc4.h"
#include <iterator>
spiceapi::RC4::RC4(uint8_t *key, size_t key_size) {
// initialize S-BOX
for (size_t i = 0; i < std::size(s_box); i++)
s_box[i] = (uint8_t) i;
// check key size
if (!key_size)
return;
// KSA
size_t j = 0;
for (size_t i = 0; i < std::size(s_box); i++) {
// update
j = (j + s_box[i] + key[i % key_size]) % std::size(s_box);
// swap
auto tmp = s_box[i];
s_box[i] = s_box[j];
s_box[j] = tmp;
}
}
void spiceapi::RC4::crypt(uint8_t *data, size_t size) {
// iterate all bytes
for (size_t pos = 0; pos < size; pos++) {
// update
a = (a + 1) % std::size(s_box);
b = (b + s_box[a]) % std::size(s_box);
// swap
auto tmp = s_box[a];
s_box[a] = s_box[b];
s_box[b] = tmp;
// crypt
data[pos] ^= s_box[(s_box[a] + s_box[b]) % std::size(s_box)];
}
}
+21 -21
View File
@@ -1,21 +1,21 @@
#ifndef SPICEAPI_RC4_H
#define SPICEAPI_RC4_H
#include <cstdint>
namespace spiceapi {
class RC4 {
private:
uint8_t s_box[256];
size_t a = 0, b = 0;
public:
RC4(uint8_t *key, size_t key_size);
void crypt(uint8_t *data, size_t size);
};
}
#endif //SPICEAPI_RC4_H
#ifndef SPICEAPI_RC4_H
#define SPICEAPI_RC4_H
#include <cstdint>
namespace spiceapi {
class RC4 {
private:
uint8_t s_box[256];
size_t a = 0, b = 0;
public:
RC4(uint8_t *key, size_t key_size);
void crypt(uint8_t *data, size_t size);
};
}
#endif //SPICEAPI_RC4_H
File diff suppressed because it is too large Load Diff
+104 -104
View File
@@ -1,104 +1,104 @@
#ifndef SPICEAPI_WRAPPERS_H
#define SPICEAPI_WRAPPERS_H
#include <vector>
#include <string>
#include "connection.h"
namespace spiceapi {
struct AnalogState {
std::string name;
float value;
};
struct ButtonState {
std::string name;
float value;
};
struct LightState {
std::string name;
float value;
};
struct InfoAvs {
std::string model, dest, spec, rev, ext;
};
struct InfoLauncher {
std::string version;
std::string compile_date, compile_time, system_time;
std::vector<std::string> args;
};
struct InfoMemory {
uint64_t mem_total, mem_total_used, mem_used;
uint64_t vmem_total, vmem_total_used, vmem_used;
};
struct TouchState {
uint64_t id;
int64_t x, y;
};
struct LCDInfo {
bool enabled;
std::string csm;
uint8_t bri, con, bl, red, green, blue;
};
uint64_t msg_gen_id();
bool analogs_read(Connection &con, std::vector<AnalogState> &states);
bool analogs_write(Connection &con, std::vector<AnalogState> &states);
bool analogs_write_reset(Connection &con, std::vector<AnalogState> &states);
bool buttons_read(Connection &con, std::vector<ButtonState> &states);
bool buttons_write(Connection &con, std::vector<ButtonState> &states);
bool buttons_write_reset(Connection &con, std::vector<ButtonState> &states);
bool card_insert(Connection &con, size_t index, const char *card_id);
bool coin_get(Connection &con, int &coins);
bool coin_set(Connection &con, int coins);
bool coin_insert(Connection &con, int coins=1);
bool coin_blocker_get(Connection &con, bool &closed);
bool control_raise(Connection &con, const char *signal);
bool control_exit(Connection &con);
bool control_exit(Connection &con, int exit_code);
bool control_restart(Connection &con);
bool control_session_refresh(Connection &con);
bool control_shutdown(Connection &con);
bool control_reboot(Connection &con);
bool iidx_ticker_get(Connection &con, char *ticker);
bool iidx_ticker_set(Connection &con, const char *ticker);
bool iidx_ticker_reset(Connection &con);
bool info_avs(Connection &con, InfoAvs &info);
bool info_launcher(Connection &con, InfoLauncher &info);
bool info_memory(Connection &con, InfoMemory &info);
bool keypads_write(Connection &con, unsigned int keypad, const char *input);
bool keypads_set(Connection &con, unsigned int keypad, std::vector<char> &keys);
bool keypads_get(Connection &con, unsigned int keypad, std::vector<char> &keys);
bool lights_read(Connection &con, std::vector<LightState> &states);
bool lights_write(Connection &con, std::vector<LightState> &states);
bool lights_write_reset(Connection &con, std::vector<LightState> &states);
bool memory_write(Connection &con, const char *dll_name, const char *hex, uint32_t offset);
bool memory_read(Connection &con, const char *dll_name, uint32_t offset, uint32_t size, std::string &hex);
bool memory_signature(Connection &con, const char *dll_name, const char *signature, const char *replacement,
uint32_t offset, uint32_t usage, uint32_t &file_offset);
bool touch_read(Connection &con, std::vector<TouchState> &states);
bool touch_write(Connection &con, std::vector<TouchState> &states);
bool touch_write_reset(Connection &con, std::vector<TouchState> &states);
bool lcd_info(Connection &con, LCDInfo &info);
}
#endif //SPICEAPI_WRAPPERS_H
#ifndef SPICEAPI_WRAPPERS_H
#define SPICEAPI_WRAPPERS_H
#include <vector>
#include <string>
#include "connection.h"
namespace spiceapi {
struct AnalogState {
std::string name;
float value;
};
struct ButtonState {
std::string name;
float value;
};
struct LightState {
std::string name;
float value;
};
struct InfoAvs {
std::string model, dest, spec, rev, ext;
};
struct InfoLauncher {
std::string version;
std::string compile_date, compile_time, system_time;
std::vector<std::string> args;
};
struct InfoMemory {
uint64_t mem_total, mem_total_used, mem_used;
uint64_t vmem_total, vmem_total_used, vmem_used;
};
struct TouchState {
uint64_t id;
int64_t x, y;
};
struct LCDInfo {
bool enabled;
std::string csm;
uint8_t bri, con, bl, red, green, blue;
};
uint64_t msg_gen_id();
bool analogs_read(Connection &con, std::vector<AnalogState> &states);
bool analogs_write(Connection &con, std::vector<AnalogState> &states);
bool analogs_write_reset(Connection &con, std::vector<AnalogState> &states);
bool buttons_read(Connection &con, std::vector<ButtonState> &states);
bool buttons_write(Connection &con, std::vector<ButtonState> &states);
bool buttons_write_reset(Connection &con, std::vector<ButtonState> &states);
bool card_insert(Connection &con, size_t index, const char *card_id);
bool coin_get(Connection &con, int &coins);
bool coin_set(Connection &con, int coins);
bool coin_insert(Connection &con, int coins=1);
bool coin_blocker_get(Connection &con, bool &closed);
bool control_raise(Connection &con, const char *signal);
bool control_exit(Connection &con);
bool control_exit(Connection &con, int exit_code);
bool control_restart(Connection &con);
bool control_session_refresh(Connection &con);
bool control_shutdown(Connection &con);
bool control_reboot(Connection &con);
bool iidx_ticker_get(Connection &con, char *ticker);
bool iidx_ticker_set(Connection &con, const char *ticker);
bool iidx_ticker_reset(Connection &con);
bool info_avs(Connection &con, InfoAvs &info);
bool info_launcher(Connection &con, InfoLauncher &info);
bool info_memory(Connection &con, InfoMemory &info);
bool keypads_write(Connection &con, unsigned int keypad, const char *input);
bool keypads_set(Connection &con, unsigned int keypad, std::vector<char> &keys);
bool keypads_get(Connection &con, unsigned int keypad, std::vector<char> &keys);
bool lights_read(Connection &con, std::vector<LightState> &states);
bool lights_write(Connection &con, std::vector<LightState> &states);
bool lights_write_reset(Connection &con, std::vector<LightState> &states);
bool memory_write(Connection &con, const char *dll_name, const char *hex, uint32_t offset);
bool memory_read(Connection &con, const char *dll_name, uint32_t offset, uint32_t size, std::string &hex);
bool memory_signature(Connection &con, const char *dll_name, const char *signature, const char *replacement,
uint32_t offset, uint32_t usage, uint32_t &file_offset);
bool touch_read(Connection &con, std::vector<TouchState> &states);
bool touch_write(Connection &con, std::vector<TouchState> &states);
bool touch_write_reset(Connection &con, std::vector<TouchState> &states);
bool lcd_info(Connection &con, LCDInfo &info);
}
#endif //SPICEAPI_WRAPPERS_H
+24 -24
View File
@@ -1,24 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
@@ -1,22 +1,22 @@
library spiceapi;
import 'dart:convert';
import 'dart:async';
import 'dart:math';
import 'dart:html';
import 'dart:typed_data';
part "src/connection.dart";
part "src/request.dart";
part "src/response.dart";
part "src/exceptions.dart";
part "src/rc4.dart";
part "src/wrappers/analogs.dart";
part "src/wrappers/buttons.dart";
part "src/wrappers/card.dart";
part "src/wrappers/coin.dart";
part "src/wrappers/control.dart";
part "src/wrappers/info.dart";
part "src/wrappers/keypads.dart";
part "src/wrappers/lights.dart";
part "src/wrappers/memory.dart";
part "src/wrappers/iidx.dart";
part "src/wrappers/touch.dart";
library spiceapi;
import 'dart:convert';
import 'dart:async';
import 'dart:math';
import 'dart:html';
import 'dart:typed_data';
part "src/connection.dart";
part "src/request.dart";
part "src/response.dart";
part "src/exceptions.dart";
part "src/rc4.dart";
part "src/wrappers/analogs.dart";
part "src/wrappers/buttons.dart";
part "src/wrappers/card.dart";
part "src/wrappers/coin.dart";
part "src/wrappers/control.dart";
part "src/wrappers/info.dart";
part "src/wrappers/keypads.dart";
part "src/wrappers/lights.dart";
part "src/wrappers/memory.dart";
part "src/wrappers/iidx.dart";
part "src/wrappers/touch.dart";
@@ -1,193 +1,193 @@
part of spiceapi;
class Connection {
// settings
static const _TIMEOUT = Duration(seconds: 2);
static const _BUFFER_SIZE = 1024 * 8;
// state
final String host, pass;
final int port;
var resource;
List<int> _dataBuffer;
StreamController<Response> _responses;
StreamController<Connection> _connections;
WebSocket _socket;
RC4 _cipher;
bool _disposed = false;
Connection(this.host, this.port, this.pass,
{this.resource, bool refreshSession=true}) {
// initialize
_dataBuffer = List<int>();
_responses = StreamController<Response>.broadcast();
_connections = StreamController<Connection>.broadcast();
if (pass.length > 0)
_cipher = RC4(utf8.encode(pass));
// initialize socket
this._socket = WebSocket("ws://$host:${port + 1}");
this._socket.binaryType = "arraybuffer";
// listen to events
this._socket.onOpen.listen((e) async {
// refresh session
bool error = false;
if (refreshSession) {
try {
await controlRefreshSession(this);
} on Error {
error = true;
} on TimeoutException {
error = true;
}
}
// mark as connected
if (!this._connections.isClosed)
this._connections.add(this);
if (error)
this.dispose();
});
this._socket.onMessage.listen((e) {
// get data
var data = e.data;
if (data is ByteBuffer)
data = data.asUint8List();
// check type
if (data is List<int>) {
// cipher
if (_cipher != null)
_cipher.crypt(data);
// add data to buffer
_dataBuffer.addAll(data);
// check buffer size
if (_dataBuffer.length > _BUFFER_SIZE) {
this.dispose();
return;
}
// check for completed message
for (int i = 0; i < _dataBuffer.length; i++) {
if (_dataBuffer[i] == 0) {
// get message data and remove from buffer
var msgData = List<int>.from(_dataBuffer.getRange(0, i));
_dataBuffer.removeRange(0, i + 1);
// check data length
if (msgData.length > 0) {
// convert to JSON
var msgStr = utf8.decode(msgData, allowMalformed: false);
// build response
var res = Response.fromJson(msgStr);
this._responses.add(res);
}
}
}
}
});
this._socket.onClose.listen((e) {
this.dispose();
});
this._socket.onError.listen((e) {
this.dispose();
});
}
void changePass(String pass) {
if (pass.length > 0)
_cipher = RC4(utf8.encode(pass));
else
_cipher = null;
}
void dispose() {
if (_socket != null)
_socket.close();
_socket = null;
if (_responses != null)
_responses.close();
if (_connections != null)
_connections.close();
this._disposed = true;
this.free();
}
bool isDisposed() {
return this._disposed;
}
void free() {
// release optional resource
if (this.resource != null) {
this.resource.release();
this.resource = null;
}
}
bool isFree() {
return this.resource == null;
}
Future<Connection> onConnect() {
return _connections.stream.first;
}
bool isValid() {
return this._socket != null && !this._disposed;
}
Future<Response> request(Request req) {
// add response listener
var res = _awaitResponse(req._id);
// write request
_writeRequest(req);
// return future response
return res.then((res) {
// validate first
res.validate();
// return it
return res;
});
}
void _writeRequest(Request req) async {
// convert to JSON
var json = req.toJson() + "\x00";
var jsonEncoded = utf8.encode(json);
// cipher
if (_cipher != null)
_cipher.crypt(jsonEncoded);
// write to socket
this._socket.sendByteBuffer(Int8List.fromList(jsonEncoded).buffer);
}
Future<Response> _awaitResponse(int id) {
return _responses.stream.timeout(_TIMEOUT).firstWhere(
(res) => res._id == id, orElse: null);
}
}
part of spiceapi;
class Connection {
// settings
static const _TIMEOUT = Duration(seconds: 2);
static const _BUFFER_SIZE = 1024 * 8;
// state
final String host, pass;
final int port;
var resource;
List<int> _dataBuffer;
StreamController<Response> _responses;
StreamController<Connection> _connections;
WebSocket _socket;
RC4 _cipher;
bool _disposed = false;
Connection(this.host, this.port, this.pass,
{this.resource, bool refreshSession=true}) {
// initialize
_dataBuffer = List<int>();
_responses = StreamController<Response>.broadcast();
_connections = StreamController<Connection>.broadcast();
if (pass.length > 0)
_cipher = RC4(utf8.encode(pass));
// initialize socket
this._socket = WebSocket("ws://$host:${port + 1}");
this._socket.binaryType = "arraybuffer";
// listen to events
this._socket.onOpen.listen((e) async {
// refresh session
bool error = false;
if (refreshSession) {
try {
await controlRefreshSession(this);
} on Error {
error = true;
} on TimeoutException {
error = true;
}
}
// mark as connected
if (!this._connections.isClosed)
this._connections.add(this);
if (error)
this.dispose();
});
this._socket.onMessage.listen((e) {
// get data
var data = e.data;
if (data is ByteBuffer)
data = data.asUint8List();
// check type
if (data is List<int>) {
// cipher
if (_cipher != null)
_cipher.crypt(data);
// add data to buffer
_dataBuffer.addAll(data);
// check buffer size
if (_dataBuffer.length > _BUFFER_SIZE) {
this.dispose();
return;
}
// check for completed message
for (int i = 0; i < _dataBuffer.length; i++) {
if (_dataBuffer[i] == 0) {
// get message data and remove from buffer
var msgData = List<int>.from(_dataBuffer.getRange(0, i));
_dataBuffer.removeRange(0, i + 1);
// check data length
if (msgData.length > 0) {
// convert to JSON
var msgStr = utf8.decode(msgData, allowMalformed: false);
// build response
var res = Response.fromJson(msgStr);
this._responses.add(res);
}
}
}
}
});
this._socket.onClose.listen((e) {
this.dispose();
});
this._socket.onError.listen((e) {
this.dispose();
});
}
void changePass(String pass) {
if (pass.length > 0)
_cipher = RC4(utf8.encode(pass));
else
_cipher = null;
}
void dispose() {
if (_socket != null)
_socket.close();
_socket = null;
if (_responses != null)
_responses.close();
if (_connections != null)
_connections.close();
this._disposed = true;
this.free();
}
bool isDisposed() {
return this._disposed;
}
void free() {
// release optional resource
if (this.resource != null) {
this.resource.release();
this.resource = null;
}
}
bool isFree() {
return this.resource == null;
}
Future<Connection> onConnect() {
return _connections.stream.first;
}
bool isValid() {
return this._socket != null && !this._disposed;
}
Future<Response> request(Request req) {
// add response listener
var res = _awaitResponse(req._id);
// write request
_writeRequest(req);
// return future response
return res.then((res) {
// validate first
res.validate();
// return it
return res;
});
}
void _writeRequest(Request req) async {
// convert to JSON
var json = req.toJson() + "\x00";
var jsonEncoded = utf8.encode(json);
// cipher
if (_cipher != null)
_cipher.crypt(jsonEncoded);
// write to socket
this._socket.sendByteBuffer(Int8List.fromList(jsonEncoded).buffer);
}
Future<Response> _awaitResponse(int id) {
return _responses.stream.timeout(_TIMEOUT).firstWhere(
(res) => res._id == id, orElse: null);
}
}
@@ -1,11 +1,11 @@
part of spiceapi;
class APIError implements Exception {
String cause;
APIError(this.cause);
@override
String toString() {
return this.cause;
}
}
part of spiceapi;
class APIError implements Exception {
String cause;
APIError(this.cause);
@override
String toString() {
return this.cause;
}
}
@@ -1,48 +1,48 @@
part of spiceapi;
class RC4 {
// state
int _a = 0;
int _b = 0;
List<int> _sBox = List<int>(256);
RC4(List<int> key) {
// init sBox
for (int i = 0; i < 256; i++) {
_sBox[i] = i;
}
// process key
int j = 0;
for (int i = 0; i < 256; i++) {
// update
j = (j + _sBox[i] + key[i % key.length]) % 256;
// swap
var tmp = _sBox[i];
_sBox[i] = _sBox[j];
_sBox[j] = tmp;
}
}
void crypt(List<int> inData) {
for (int i = 0; i < inData.length; i++) {
// update
_a = (_a + 1) % 256;
_b = (_b + _sBox[_a]) % 256;
// swap
var tmp = _sBox[_a];
_sBox[_a] = _sBox[_b];
_sBox[_b] = tmp;
// crypt
inData[i] ^= _sBox[(_sBox[_a] + _sBox[_b]) % 256];
}
}
}
part of spiceapi;
class RC4 {
// state
int _a = 0;
int _b = 0;
List<int> _sBox = List<int>(256);
RC4(List<int> key) {
// init sBox
for (int i = 0; i < 256; i++) {
_sBox[i] = i;
}
// process key
int j = 0;
for (int i = 0; i < 256; i++) {
// update
j = (j + _sBox[i] + key[i % key.length]) % 256;
// swap
var tmp = _sBox[i];
_sBox[i] = _sBox[j];
_sBox[j] = tmp;
}
}
void crypt(List<int> inData) {
for (int i = 0; i < inData.length; i++) {
// update
_a = (_a + 1) % 256;
_b = (_b + _sBox[_a]) % 256;
// swap
var tmp = _sBox[_a];
_sBox[_a] = _sBox[_b];
_sBox[_b] = tmp;
// crypt
inData[i] ^= _sBox[(_sBox[_a] + _sBox[_b]) % 256];
}
}
}
@@ -1,45 +1,45 @@
part of spiceapi;
class Request {
static int _lastID = 0;
// contents
int _id;
String _module;
String _function;
List _params;
Request(String module, String function, {id}) {
// automatic ID iteration
if (id == null) {
if (++_lastID >= pow(2, 32))
_lastID = 1;
id = _lastID;
} else
_lastID = id;
// build contents
this._id = id;
this._module = module;
this._function = function;
this._params = List();
}
String toJson() {
return jsonEncode(
{
"id": this._id,
"module": this._module,
"function": this._function,
"params": this._params,
}
);
}
void addParam(param) {
this._params.add(param);
}
}
part of spiceapi;
class Request {
static int _lastID = 0;
// contents
int _id;
String _module;
String _function;
List _params;
Request(String module, String function, {id}) {
// automatic ID iteration
if (id == null) {
if (++_lastID >= pow(2, 32))
_lastID = 1;
id = _lastID;
} else
_lastID = id;
// build contents
this._id = id;
this._module = module;
this._function = function;
this._params = List();
}
String toJson() {
return jsonEncode(
{
"id": this._id,
"module": this._module,
"function": this._function,
"params": this._params,
}
);
}
void addParam(param) {
this._params.add(param);
}
}
@@ -1,35 +1,35 @@
part of spiceapi;
class Response {
String _json;
int _id;
List _errors;
List _data;
Response.fromJson(String json) {
this._json = json;
var obj = jsonDecode(json);
this._id = obj["id"];
this._errors = obj["errors"];
this._data = obj["data"];
}
void validate() {
// check for errors
if (_errors.length > 0) {
// TODO: add all errors
throw APIError(_errors[0].toString());
}
}
List getData() {
return _data;
}
String toJson() {
return _json;
}
}
part of spiceapi;
class Response {
String _json;
int _id;
List _errors;
List _data;
Response.fromJson(String json) {
this._json = json;
var obj = jsonDecode(json);
this._id = obj["id"];
this._errors = obj["errors"];
this._data = obj["data"];
}
void validate() {
// check for errors
if (_errors.length > 0) {
// TODO: add all errors
throw APIError(_errors[0].toString());
}
}
List getData() {
return _data;
}
String toJson() {
return _json;
}
}
@@ -1,54 +1,54 @@
part of spiceapi;
class AnalogState {
String name;
double state;
bool active;
AnalogState(this.name, this.state);
AnalogState._fromRead(this.name, this.state, this.active);
}
Future<List<AnalogState>> analogsRead(Connection con) {
var req = Request("analogs", "read");
return con.request(req).then((res) {
// build states list
List<AnalogState> states = [];
for (List state in res.getData()) {
states.add(AnalogState._fromRead(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> analogsWrite(Connection con, List<AnalogState> states) {
var req = Request("analogs", "write");
// add params
for (var state in states) {
var obj = [
state.name,
state.state
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> analogsWriteReset(Connection con, List<String> names) {
var req = Request("analogs", "write_reset");
// add params
for (var name in names)
req.addParam(name);
return con.request(req);
}
part of spiceapi;
class AnalogState {
String name;
double state;
bool active;
AnalogState(this.name, this.state);
AnalogState._fromRead(this.name, this.state, this.active);
}
Future<List<AnalogState>> analogsRead(Connection con) {
var req = Request("analogs", "read");
return con.request(req).then((res) {
// build states list
List<AnalogState> states = [];
for (List state in res.getData()) {
states.add(AnalogState._fromRead(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> analogsWrite(Connection con, List<AnalogState> states) {
var req = Request("analogs", "write");
// add params
for (var state in states) {
var obj = [
state.name,
state.state
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> analogsWriteReset(Connection con, List<String> names) {
var req = Request("analogs", "write_reset");
// add params
for (var name in names)
req.addParam(name);
return con.request(req);
}
@@ -1,54 +1,54 @@
part of spiceapi;
class ButtonState {
String name;
double state;
bool active;
ButtonState(this.name, this.state);
ButtonState._fromRead(this.name, this.state, this.active);
}
Future<List<ButtonState>> buttonsRead(Connection con) {
var req = Request("buttons", "read");
return con.request(req).then((res) {
// build states list
List<ButtonState> states = [];
for (List state in res.getData()) {
states.add(ButtonState._fromRead(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> buttonsWrite(Connection con, List<ButtonState> states) {
var req = Request("buttons", "write");
// add params
for (var state in states) {
var obj = [
state.name,
state.state
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> buttonsWriteReset(Connection con, List<String> names) {
var req = Request("buttons", "write_reset");
// add params
for (var name in names)
req.addParam(name);
return con.request(req);
}
part of spiceapi;
class ButtonState {
String name;
double state;
bool active;
ButtonState(this.name, this.state);
ButtonState._fromRead(this.name, this.state, this.active);
}
Future<List<ButtonState>> buttonsRead(Connection con) {
var req = Request("buttons", "read");
return con.request(req).then((res) {
// build states list
List<ButtonState> states = [];
for (List state in res.getData()) {
states.add(ButtonState._fromRead(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> buttonsWrite(Connection con, List<ButtonState> states) {
var req = Request("buttons", "write");
// add params
for (var state in states) {
var obj = [
state.name,
state.state
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> buttonsWriteReset(Connection con, List<String> names) {
var req = Request("buttons", "write_reset");
// add params
for (var name in names)
req.addParam(name);
return con.request(req);
}
@@ -1,8 +1,8 @@
part of spiceapi;
Future<void> cardInsert(Connection con, int unit, String cardID) {
var req = Request("card", "insert");
req.addParam(unit);
req.addParam(cardID);
return con.request(req);
}
part of spiceapi;
Future<void> cardInsert(Connection con, int unit, String cardID) {
var req = Request("card", "insert");
req.addParam(unit);
req.addParam(cardID);
return con.request(req);
}
@@ -1,21 +1,21 @@
part of spiceapi;
Future<int> coinGet(Connection con) {
var req = Request("coin", "get");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<void> coinSet(Connection con, int amount) {
var req = Request("coin", "set");
req.addParam(amount);
return con.request(req);
}
Future<void> coinInsert(Connection con, [int amount=1]) {
var req = Request("coin", "insert");
if (amount != 1)
req.addParam(amount);
return con.request(req);
}
part of spiceapi;
Future<int> coinGet(Connection con) {
var req = Request("coin", "get");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<void> coinSet(Connection con, int amount) {
var req = Request("coin", "set");
req.addParam(amount);
return con.request(req);
}
Future<void> coinInsert(Connection con, [int amount=1]) {
var req = Request("coin", "insert");
if (amount != 1)
req.addParam(amount);
return con.request(req);
}
@@ -1,36 +1,36 @@
part of spiceapi;
Future<void> controlRaise(Connection con, String signal) {
var req = Request("control", "raise");
req.addParam(signal);
return con.request(req);
}
Future<void> controlExit(Connection con, int code) {
var req = Request("control", "exit");
req.addParam(code);
return con.request(req);
}
Future<void> controlRestart(Connection con) {
var req = Request("control", "restart");
return con.request(req);
}
Future<void> controlRefreshSession(Connection con) {
var rnd = new Random();
var req = Request("control", "session_refresh", id: rnd.nextInt(pow(2, 32)));
return con.request(req).then((res) {
con.changePass(res.getData()[0]);
});
}
Future<void> controlShutdown(Connection con) {
var req = Request("control", "shutdown");
return con.request(req);
}
Future<void> controlReboot(Connection con) {
var req = Request("control", "reboot");
return con.request(req);
}
part of spiceapi;
Future<void> controlRaise(Connection con, String signal) {
var req = Request("control", "raise");
req.addParam(signal);
return con.request(req);
}
Future<void> controlExit(Connection con, int code) {
var req = Request("control", "exit");
req.addParam(code);
return con.request(req);
}
Future<void> controlRestart(Connection con) {
var req = Request("control", "restart");
return con.request(req);
}
Future<void> controlRefreshSession(Connection con) {
var rnd = new Random();
var req = Request("control", "session_refresh", id: rnd.nextInt(pow(2, 32)));
return con.request(req).then((res) {
con.changePass(res.getData()[0]);
});
}
Future<void> controlShutdown(Connection con) {
var req = Request("control", "shutdown");
return con.request(req);
}
Future<void> controlReboot(Connection con) {
var req = Request("control", "reboot");
return con.request(req);
}
@@ -1,19 +1,19 @@
part of spiceapi;
Future<String> iidxTickerGet(Connection con) {
var req = Request("iidx", "ticker_get");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<void> iidxTickerSet(Connection con, String text) {
var req = Request("iidx", "ticker_set");
req.addParam(text);
return con.request(req);
}
Future<void> iidxTickerReset(Connection con) {
var req = Request("iidx", "ticker_reset");
return con.request(req);
}
part of spiceapi;
Future<String> iidxTickerGet(Connection con) {
var req = Request("iidx", "ticker_get");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<void> iidxTickerSet(Connection con, String text) {
var req = Request("iidx", "ticker_set");
req.addParam(text);
return con.request(req);
}
Future<void> iidxTickerReset(Connection con) {
var req = Request("iidx", "ticker_reset");
return con.request(req);
}
@@ -1,22 +1,22 @@
part of spiceapi;
Future<Map> infoAVS(Connection con) {
var req = Request("info", "avs");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<Map> infoLauncher(Connection con) {
var req = Request("info", "launcher");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<Map> infoMemory(Connection con) {
var req = Request("info", "memory");
return con.request(req).then((res) {
return res.getData()[0];
});
}
part of spiceapi;
Future<Map> infoAVS(Connection con) {
var req = Request("info", "avs");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<Map> infoLauncher(Connection con) {
var req = Request("info", "launcher");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<Map> infoMemory(Connection con) {
var req = Request("info", "memory");
return con.request(req).then((res) {
return res.getData()[0];
});
}
@@ -1,28 +1,28 @@
part of spiceapi;
Future<void> keypadsWrite(Connection con, int unit, String input) {
var req = Request("keypads", "write");
req.addParam(unit);
req.addParam(input);
return con.request(req);
}
Future<void> keypadsSet(Connection con, int unit, String buttons) {
var req = Request("keypads", "set");
req.addParam(unit);
for (int i = 0; i < buttons.length; i++)
req.addParam(buttons[i]);
return con.request(req);
}
Future<String> keypadsGet(Connection con, int unit) {
var req = Request("keypads", "get");
req.addParam(unit);
return con.request(req).then((res) {
String buttons = "";
for (var obj in res.getData()) {
buttons += obj;
}
return buttons;
});
}
part of spiceapi;
Future<void> keypadsWrite(Connection con, int unit, String input) {
var req = Request("keypads", "write");
req.addParam(unit);
req.addParam(input);
return con.request(req);
}
Future<void> keypadsSet(Connection con, int unit, String buttons) {
var req = Request("keypads", "set");
req.addParam(unit);
for (int i = 0; i < buttons.length; i++)
req.addParam(buttons[i]);
return con.request(req);
}
Future<String> keypadsGet(Connection con, int unit) {
var req = Request("keypads", "get");
req.addParam(unit);
return con.request(req).then((res) {
String buttons = "";
for (var obj in res.getData()) {
buttons += obj;
}
return buttons;
});
}
@@ -1,54 +1,54 @@
part of spiceapi;
class LightState {
String name;
double state;
bool active;
LightState(this.name, this.state);
LightState._fromRead(this.name, this.state, this.active);
}
Future<List<LightState>> lightsRead(Connection con) {
var req = Request("lights", "read");
return con.request(req).then((res) {
// build states list
List<LightState> states = [];
for (List state in res.getData()) {
states.add(LightState._fromRead(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> lightsWrite(Connection con, List<LightState> states) {
var req = Request("lights", "write");
// add params
for (var state in states) {
var obj = [
state.name,
state.state
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> lightsWriteReset(Connection con, List<String> names) {
var req = Request("lights", "write_reset");
// add params
for (var name in names)
req.addParam(name);
return con.request(req);
}
part of spiceapi;
class LightState {
String name;
double state;
bool active;
LightState(this.name, this.state);
LightState._fromRead(this.name, this.state, this.active);
}
Future<List<LightState>> lightsRead(Connection con) {
var req = Request("lights", "read");
return con.request(req).then((res) {
// build states list
List<LightState> states = [];
for (List state in res.getData()) {
states.add(LightState._fromRead(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> lightsWrite(Connection con, List<LightState> states) {
var req = Request("lights", "write");
// add params
for (var state in states) {
var obj = [
state.name,
state.state
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> lightsWriteReset(Connection con, List<String> names) {
var req = Request("lights", "write_reset");
// add params
for (var name in names)
req.addParam(name);
return con.request(req);
}
@@ -1,35 +1,35 @@
part of spiceapi;
Future<void> memoryWrite(Connection con,
String dllName, String data, int offset) {
var req = Request("memory", "write");
req.addParam(dllName);
req.addParam(data);
req.addParam(offset);
return con.request(req);
}
Future<String> memoryRead(Connection con,
String dllName, int offset, int size) {
var req = Request("memory", "read");
req.addParam(dllName);
req.addParam(offset);
req.addParam(size);
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<int> memorySignature(Connection con,
String dllName, String signature, String replacement,
int offset, int usage) {
var req = Request("memory", "signature");
req.addParam(dllName);
req.addParam(signature);
req.addParam(replacement);
req.addParam(offset);
req.addParam(usage);
return con.request(req).then((res) {
return res.getData()[0];
});
}
part of spiceapi;
Future<void> memoryWrite(Connection con,
String dllName, String data, int offset) {
var req = Request("memory", "write");
req.addParam(dllName);
req.addParam(data);
req.addParam(offset);
return con.request(req);
}
Future<String> memoryRead(Connection con,
String dllName, int offset, int size) {
var req = Request("memory", "read");
req.addParam(dllName);
req.addParam(offset);
req.addParam(size);
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<int> memorySignature(Connection con,
String dllName, String signature, String replacement,
int offset, int usage) {
var req = Request("memory", "signature");
req.addParam(dllName);
req.addParam(signature);
req.addParam(replacement);
req.addParam(offset);
req.addParam(usage);
return con.request(req).then((res) {
return res.getData()[0];
});
}
@@ -1,53 +1,53 @@
part of spiceapi;
class TouchState {
int id;
int x, y;
TouchState(this.id, this.x, this.y);
}
Future<List<TouchState>> touchRead(Connection con) {
var req = Request("touch", "read");
return con.request(req).then((res) {
// build states list
List<TouchState> states = [];
for (List state in res.getData()) {
states.add(TouchState(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> touchWrite(Connection con, List<TouchState> states) {
var req = Request("touch", "write");
// add params
for (var state in states) {
var obj = [
state.id,
state.x,
state.y
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> touchWriteReset(Connection con, List<int> touchIDs) {
var req = Request("touch", "write_reset");
// add params
for (var id in touchIDs)
req.addParam(id);
return con.request(req);
}
part of spiceapi;
class TouchState {
int id;
int x, y;
TouchState(this.id, this.x, this.y);
}
Future<List<TouchState>> touchRead(Connection con) {
var req = Request("touch", "read");
return con.request(req).then((res) {
// build states list
List<TouchState> states = [];
for (List state in res.getData()) {
states.add(TouchState(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> touchWrite(Connection con, List<TouchState> states) {
var req = Request("touch", "write");
// add params
for (var state in states) {
var obj = [
state.id,
state.x,
state.y
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> touchWriteReset(Connection con, List<int> touchIDs) {
var req = Request("touch", "write_reset");
// add params
for (var id in touchIDs)
req.addParam(id);
return con.request(req);
}
+24 -24
View File
@@ -1,24 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
+23 -23
View File
@@ -1,23 +1,23 @@
library spiceapi;
import 'dart:io';
import 'dart:convert';
import 'dart:async';
import 'dart:math';
import 'dart:typed_data';
part "src/connection.dart";
part "src/request.dart";
part "src/response.dart";
part "src/exceptions.dart";
part "src/rc4.dart";
part "src/wrappers/analogs.dart";
part "src/wrappers/buttons.dart";
part "src/wrappers/capture.dart";
part "src/wrappers/card.dart";
part "src/wrappers/coin.dart";
part "src/wrappers/control.dart";
part "src/wrappers/info.dart";
part "src/wrappers/keypads.dart";
part "src/wrappers/lights.dart";
part "src/wrappers/memory.dart";
part "src/wrappers/iidx.dart";
part "src/wrappers/touch.dart";
library spiceapi;
import 'dart:io';
import 'dart:convert';
import 'dart:async';
import 'dart:math';
import 'dart:typed_data';
part "src/connection.dart";
part "src/request.dart";
part "src/response.dart";
part "src/exceptions.dart";
part "src/rc4.dart";
part "src/wrappers/analogs.dart";
part "src/wrappers/buttons.dart";
part "src/wrappers/capture.dart";
part "src/wrappers/card.dart";
part "src/wrappers/coin.dart";
part "src/wrappers/control.dart";
part "src/wrappers/info.dart";
part "src/wrappers/keypads.dart";
part "src/wrappers/lights.dart";
part "src/wrappers/memory.dart";
part "src/wrappers/iidx.dart";
part "src/wrappers/touch.dart";
+192 -192
View File
@@ -1,192 +1,192 @@
part of spiceapi;
class Connection {
// settings
static const _TIMEOUT = Duration(seconds: 3);
static const _BUFFER_SIZE = 1024 * 1024 * 8;
// state
final String host, pass;
final int port;
var resource;
List<int> _dataBuffer;
StreamController<Response> _responses;
StreamController<Connection> _connections;
Socket _socket;
RC4 _cipher;
bool _disposed = false;
Connection(this.host, this.port, this.pass,
{this.resource, bool refreshSession=true}) {
// initialize
_dataBuffer = List<int>();
_responses = StreamController<Response>.broadcast();
_connections = StreamController<Connection>.broadcast();
if (pass.length > 0)
_cipher = RC4(utf8.encode(pass));
// connect
Socket.connect(host, port, timeout: _TIMEOUT).then((socket) async {
// remember socket
this._socket = socket;
// listen to data
socket.listen((data) {
// cipher
if (_cipher != null)
_cipher.crypt(data);
// add data to buffer
_dataBuffer.addAll(data);
// check buffer size
if (_dataBuffer.length > _BUFFER_SIZE) {
socket.destroy();
return;
}
// check for completed message
for (int i = 0; i < _dataBuffer.length; i++) {
if (_dataBuffer[i] == 0) {
// get message data and remove from buffer
var msgData = List<int>.from(_dataBuffer.getRange(0, i));
_dataBuffer.removeRange(0, i + 1);
// check data length
if (msgData.length > 0) {
// convert to JSON
var msgStr = utf8.decode(msgData, allowMalformed: false);
// build response
var res = Response.fromJson(msgStr);
this._responses.add(res);
}
}
}
}, onError: (e) {
// dispose on listen error
this.dispose();
}, onDone: () {
// dispose on listen done
this.dispose();
});
// refresh session
bool error = false;
if (refreshSession) {
try {
await controlRefreshSession(this);
} on Error {
error = true;
} on TimeoutException {
error = true;
}
}
// mark as connected
if (!this._connections.isClosed)
this._connections.add(this);
if (error)
this.dispose();
}, onError: (e) {
// dispose on connection error
this.dispose();
});
}
void changePass(String pass) {
if (pass.length > 0)
_cipher = RC4(utf8.encode(pass));
else
_cipher = null;
}
void dispose() {
if (_socket != null)
_socket.destroy();
if (_responses != null)
_responses.close();
if (_connections != null)
_connections.close();
this._disposed = true;
this.free();
}
bool isDisposed() {
return this._disposed;
}
void free() {
// release optional resource
if (this.resource != null) {
this.resource.release();
this.resource = null;
}
}
bool isFree() {
return this.resource == null;
}
Future<Connection> onConnect() {
return _connections.stream.first;
}
bool isValid() {
return this._socket != null && !this._disposed;
}
Future<Response> request(Request req) {
// add response listener
var res = _awaitResponse(req._id);
// write request
_writeRequest(req);
// return future response
return res.then((res) {
// validate first
res.validate();
// return it
return res;
});
}
void _writeRequest(Request req) async {
// convert to JSON
var json = req.toJson() + "\x00";
var jsonEncoded = utf8.encode(json);
// cipher
if (_cipher != null)
_cipher.crypt(jsonEncoded);
// write to socket
this._socket.add(jsonEncoded);
}
Future<Response> _awaitResponse(int id) {
return _responses.stream.timeout(_TIMEOUT).firstWhere(
(res) => res._id == id, orElse: null);
}
}
part of spiceapi;
class Connection {
// settings
static const _TIMEOUT = Duration(seconds: 3);
static const _BUFFER_SIZE = 1024 * 1024 * 8;
// state
final String host, pass;
final int port;
var resource;
List<int> _dataBuffer;
StreamController<Response> _responses;
StreamController<Connection> _connections;
Socket _socket;
RC4 _cipher;
bool _disposed = false;
Connection(this.host, this.port, this.pass,
{this.resource, bool refreshSession=true}) {
// initialize
_dataBuffer = List<int>();
_responses = StreamController<Response>.broadcast();
_connections = StreamController<Connection>.broadcast();
if (pass.length > 0)
_cipher = RC4(utf8.encode(pass));
// connect
Socket.connect(host, port, timeout: _TIMEOUT).then((socket) async {
// remember socket
this._socket = socket;
// listen to data
socket.listen((data) {
// cipher
if (_cipher != null)
_cipher.crypt(data);
// add data to buffer
_dataBuffer.addAll(data);
// check buffer size
if (_dataBuffer.length > _BUFFER_SIZE) {
socket.destroy();
return;
}
// check for completed message
for (int i = 0; i < _dataBuffer.length; i++) {
if (_dataBuffer[i] == 0) {
// get message data and remove from buffer
var msgData = List<int>.from(_dataBuffer.getRange(0, i));
_dataBuffer.removeRange(0, i + 1);
// check data length
if (msgData.length > 0) {
// convert to JSON
var msgStr = utf8.decode(msgData, allowMalformed: false);
// build response
var res = Response.fromJson(msgStr);
this._responses.add(res);
}
}
}
}, onError: (e) {
// dispose on listen error
this.dispose();
}, onDone: () {
// dispose on listen done
this.dispose();
});
// refresh session
bool error = false;
if (refreshSession) {
try {
await controlRefreshSession(this);
} on Error {
error = true;
} on TimeoutException {
error = true;
}
}
// mark as connected
if (!this._connections.isClosed)
this._connections.add(this);
if (error)
this.dispose();
}, onError: (e) {
// dispose on connection error
this.dispose();
});
}
void changePass(String pass) {
if (pass.length > 0)
_cipher = RC4(utf8.encode(pass));
else
_cipher = null;
}
void dispose() {
if (_socket != null)
_socket.destroy();
if (_responses != null)
_responses.close();
if (_connections != null)
_connections.close();
this._disposed = true;
this.free();
}
bool isDisposed() {
return this._disposed;
}
void free() {
// release optional resource
if (this.resource != null) {
this.resource.release();
this.resource = null;
}
}
bool isFree() {
return this.resource == null;
}
Future<Connection> onConnect() {
return _connections.stream.first;
}
bool isValid() {
return this._socket != null && !this._disposed;
}
Future<Response> request(Request req) {
// add response listener
var res = _awaitResponse(req._id);
// write request
_writeRequest(req);
// return future response
return res.then((res) {
// validate first
res.validate();
// return it
return res;
});
}
void _writeRequest(Request req) async {
// convert to JSON
var json = req.toJson() + "\x00";
var jsonEncoded = utf8.encode(json);
// cipher
if (_cipher != null)
_cipher.crypt(jsonEncoded);
// write to socket
this._socket.add(jsonEncoded);
}
Future<Response> _awaitResponse(int id) {
return _responses.stream.timeout(_TIMEOUT).firstWhere(
(res) => res._id == id, orElse: null);
}
}
+11 -11
View File
@@ -1,11 +1,11 @@
part of spiceapi;
class APIError implements Exception {
String cause;
APIError(this.cause);
@override
String toString() {
return this.cause;
}
}
part of spiceapi;
class APIError implements Exception {
String cause;
APIError(this.cause);
@override
String toString() {
return this.cause;
}
}
+48 -48
View File
@@ -1,48 +1,48 @@
part of spiceapi;
class RC4 {
// state
int _a = 0;
int _b = 0;
List<int> _sBox = List<int>(256);
RC4(List<int> key) {
// init sBox
for (int i = 0; i < 256; i++) {
_sBox[i] = i;
}
// process key
int j = 0;
for (int i = 0; i < 256; i++) {
// update
j = (j + _sBox[i] + key[i % key.length]) % 256;
// swap
var tmp = _sBox[i];
_sBox[i] = _sBox[j];
_sBox[j] = tmp;
}
}
void crypt(List<int> inData) {
for (int i = 0; i < inData.length; i++) {
// update
_a = (_a + 1) % 256;
_b = (_b + _sBox[_a]) % 256;
// swap
var tmp = _sBox[_a];
_sBox[_a] = _sBox[_b];
_sBox[_b] = tmp;
// crypt
inData[i] ^= _sBox[(_sBox[_a] + _sBox[_b]) % 256];
}
}
}
part of spiceapi;
class RC4 {
// state
int _a = 0;
int _b = 0;
List<int> _sBox = List<int>(256);
RC4(List<int> key) {
// init sBox
for (int i = 0; i < 256; i++) {
_sBox[i] = i;
}
// process key
int j = 0;
for (int i = 0; i < 256; i++) {
// update
j = (j + _sBox[i] + key[i % key.length]) % 256;
// swap
var tmp = _sBox[i];
_sBox[i] = _sBox[j];
_sBox[j] = tmp;
}
}
void crypt(List<int> inData) {
for (int i = 0; i < inData.length; i++) {
// update
_a = (_a + 1) % 256;
_b = (_b + _sBox[_a]) % 256;
// swap
var tmp = _sBox[_a];
_sBox[_a] = _sBox[_b];
_sBox[_b] = tmp;
// crypt
inData[i] ^= _sBox[(_sBox[_a] + _sBox[_b]) % 256];
}
}
}
+45 -45
View File
@@ -1,45 +1,45 @@
part of spiceapi;
class Request {
static int _lastID = 0;
// contents
int _id;
String _module;
String _function;
List _params;
Request(String module, String function, {id}) {
// automatic ID iteration
if (id == null) {
if (++_lastID >= pow(2, 32))
_lastID = 1;
id = _lastID;
} else
_lastID = id;
// build contents
this._id = id;
this._module = module;
this._function = function;
this._params = List();
}
String toJson() {
return jsonEncode(
{
"id": this._id,
"module": this._module,
"function": this._function,
"params": this._params,
}
);
}
void addParam(param) {
this._params.add(param);
}
}
part of spiceapi;
class Request {
static int _lastID = 0;
// contents
int _id;
String _module;
String _function;
List _params;
Request(String module, String function, {id}) {
// automatic ID iteration
if (id == null) {
if (++_lastID >= pow(2, 32))
_lastID = 1;
id = _lastID;
} else
_lastID = id;
// build contents
this._id = id;
this._module = module;
this._function = function;
this._params = List();
}
String toJson() {
return jsonEncode(
{
"id": this._id,
"module": this._module,
"function": this._function,
"params": this._params,
}
);
}
void addParam(param) {
this._params.add(param);
}
}
+35 -35
View File
@@ -1,35 +1,35 @@
part of spiceapi;
class Response {
String _json;
int _id;
List _errors;
List _data;
Response.fromJson(String json) {
this._json = json;
var obj = jsonDecode(json);
this._id = obj["id"];
this._errors = obj["errors"];
this._data = obj["data"];
}
void validate() {
// check for errors
if (_errors.length > 0) {
// TODO: add all errors
throw APIError(_errors[0].toString());
}
}
List getData() {
return _data;
}
String toJson() {
return _json;
}
}
part of spiceapi;
class Response {
String _json;
int _id;
List _errors;
List _data;
Response.fromJson(String json) {
this._json = json;
var obj = jsonDecode(json);
this._id = obj["id"];
this._errors = obj["errors"];
this._data = obj["data"];
}
void validate() {
// check for errors
if (_errors.length > 0) {
// TODO: add all errors
throw APIError(_errors[0].toString());
}
}
List getData() {
return _data;
}
String toJson() {
return _json;
}
}
@@ -1,54 +1,54 @@
part of spiceapi;
class AnalogState {
String name;
double state;
bool active;
AnalogState(this.name, this.state);
AnalogState._fromRead(this.name, this.state, this.active);
}
Future<List<AnalogState>> analogsRead(Connection con) {
var req = Request("analogs", "read");
return con.request(req).then((res) {
// build states list
List<AnalogState> states = [];
for (List state in res.getData()) {
states.add(AnalogState._fromRead(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> analogsWrite(Connection con, List<AnalogState> states) {
var req = Request("analogs", "write");
// add params
for (var state in states) {
var obj = [
state.name,
state.state
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> analogsWriteReset(Connection con, List<String> names) {
var req = Request("analogs", "write_reset");
// add params
for (var name in names)
req.addParam(name);
return con.request(req);
}
part of spiceapi;
class AnalogState {
String name;
double state;
bool active;
AnalogState(this.name, this.state);
AnalogState._fromRead(this.name, this.state, this.active);
}
Future<List<AnalogState>> analogsRead(Connection con) {
var req = Request("analogs", "read");
return con.request(req).then((res) {
// build states list
List<AnalogState> states = [];
for (List state in res.getData()) {
states.add(AnalogState._fromRead(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> analogsWrite(Connection con, List<AnalogState> states) {
var req = Request("analogs", "write");
// add params
for (var state in states) {
var obj = [
state.name,
state.state
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> analogsWriteReset(Connection con, List<String> names) {
var req = Request("analogs", "write_reset");
// add params
for (var name in names)
req.addParam(name);
return con.request(req);
}
@@ -1,54 +1,54 @@
part of spiceapi;
class ButtonState {
String name;
double state;
bool active;
ButtonState(this.name, this.state);
ButtonState._fromRead(this.name, this.state, this.active);
}
Future<List<ButtonState>> buttonsRead(Connection con) {
var req = Request("buttons", "read");
return con.request(req).then((res) {
// build states list
List<ButtonState> states = [];
for (List state in res.getData()) {
states.add(ButtonState._fromRead(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> buttonsWrite(Connection con, List<ButtonState> states) {
var req = Request("buttons", "write");
// add params
for (var state in states) {
var obj = [
state.name,
state.state
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> buttonsWriteReset(Connection con, List<String> names) {
var req = Request("buttons", "write_reset");
// add params
for (var name in names)
req.addParam(name);
return con.request(req);
}
part of spiceapi;
class ButtonState {
String name;
double state;
bool active;
ButtonState(this.name, this.state);
ButtonState._fromRead(this.name, this.state, this.active);
}
Future<List<ButtonState>> buttonsRead(Connection con) {
var req = Request("buttons", "read");
return con.request(req).then((res) {
// build states list
List<ButtonState> states = [];
for (List state in res.getData()) {
states.add(ButtonState._fromRead(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> buttonsWrite(Connection con, List<ButtonState> states) {
var req = Request("buttons", "write");
// add params
for (var state in states) {
var obj = [
state.name,
state.state
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> buttonsWriteReset(Connection con, List<String> names) {
var req = Request("buttons", "write_reset");
// add params
for (var name in names)
req.addParam(name);
return con.request(req);
}
@@ -1,38 +1,38 @@
part of spiceapi;
class CaptureData {
int timestamp;
int width, height;
Uint8List data;
}
var _base64DecoderInstance = Base64Decoder();
Future<List> captureGetScreens(Connection con) {
var req = Request("capture", "get_screens");
return con.request(req).then((res) {
return res.getData();
});
}
Future<CaptureData> captureGetJPG(Connection con, {
int screen = 0,
int quality = 60,
int divide = 1,
}) {
var req = Request("capture", "get_jpg");
req.addParam(screen);
req.addParam(quality);
req.addParam(divide);
return con.request(req).then((res) {
var captureData = CaptureData();
var data = res.getData();
if (data.length > 0) captureData.timestamp = data[0];
if (data.length > 1) captureData.width = data[1];
if (data.length > 2) captureData.height = data[2];
if (data.length > 3) {
captureData.data = _base64DecoderInstance.convert(data[3]);
}
return captureData;
});
}
part of spiceapi;
class CaptureData {
int timestamp;
int width, height;
Uint8List data;
}
var _base64DecoderInstance = Base64Decoder();
Future<List> captureGetScreens(Connection con) {
var req = Request("capture", "get_screens");
return con.request(req).then((res) {
return res.getData();
});
}
Future<CaptureData> captureGetJPG(Connection con, {
int screen = 0,
int quality = 60,
int divide = 1,
}) {
var req = Request("capture", "get_jpg");
req.addParam(screen);
req.addParam(quality);
req.addParam(divide);
return con.request(req).then((res) {
var captureData = CaptureData();
var data = res.getData();
if (data.length > 0) captureData.timestamp = data[0];
if (data.length > 1) captureData.width = data[1];
if (data.length > 2) captureData.height = data[2];
if (data.length > 3) {
captureData.data = _base64DecoderInstance.convert(data[3]);
}
return captureData;
});
}
@@ -1,8 +1,8 @@
part of spiceapi;
Future<void> cardInsert(Connection con, int unit, String cardID) {
var req = Request("card", "insert");
req.addParam(unit);
req.addParam(cardID);
return con.request(req);
}
part of spiceapi;
Future<void> cardInsert(Connection con, int unit, String cardID) {
var req = Request("card", "insert");
req.addParam(unit);
req.addParam(cardID);
return con.request(req);
}
@@ -1,21 +1,21 @@
part of spiceapi;
Future<int> coinGet(Connection con) {
var req = Request("coin", "get");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<void> coinSet(Connection con, int amount) {
var req = Request("coin", "set");
req.addParam(amount);
return con.request(req);
}
Future<void> coinInsert(Connection con, [int amount=1]) {
var req = Request("coin", "insert");
if (amount != 1)
req.addParam(amount);
return con.request(req);
}
part of spiceapi;
Future<int> coinGet(Connection con) {
var req = Request("coin", "get");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<void> coinSet(Connection con, int amount) {
var req = Request("coin", "set");
req.addParam(amount);
return con.request(req);
}
Future<void> coinInsert(Connection con, [int amount=1]) {
var req = Request("coin", "insert");
if (amount != 1)
req.addParam(amount);
return con.request(req);
}
@@ -1,36 +1,36 @@
part of spiceapi;
Future<void> controlRaise(Connection con, String signal) {
var req = Request("control", "raise");
req.addParam(signal);
return con.request(req);
}
Future<void> controlExit(Connection con, int code) {
var req = Request("control", "exit");
req.addParam(code);
return con.request(req);
}
Future<void> controlRestart(Connection con) {
var req = Request("control", "restart");
return con.request(req);
}
Future<void> controlRefreshSession(Connection con) {
var rnd = new Random();
var req = Request("control", "session_refresh", id: rnd.nextInt(pow(2, 32)));
return con.request(req).then((res) {
con.changePass(res.getData()[0]);
});
}
Future<void> controlShutdown(Connection con) {
var req = Request("control", "shutdown");
return con.request(req);
}
Future<void> controlReboot(Connection con) {
var req = Request("control", "reboot");
return con.request(req);
}
part of spiceapi;
Future<void> controlRaise(Connection con, String signal) {
var req = Request("control", "raise");
req.addParam(signal);
return con.request(req);
}
Future<void> controlExit(Connection con, int code) {
var req = Request("control", "exit");
req.addParam(code);
return con.request(req);
}
Future<void> controlRestart(Connection con) {
var req = Request("control", "restart");
return con.request(req);
}
Future<void> controlRefreshSession(Connection con) {
var rnd = new Random();
var req = Request("control", "session_refresh", id: rnd.nextInt(pow(2, 32)));
return con.request(req).then((res) {
con.changePass(res.getData()[0]);
});
}
Future<void> controlShutdown(Connection con) {
var req = Request("control", "shutdown");
return con.request(req);
}
Future<void> controlReboot(Connection con) {
var req = Request("control", "reboot");
return con.request(req);
}
@@ -1,19 +1,19 @@
part of spiceapi;
Future<String> iidxTickerGet(Connection con) {
var req = Request("iidx", "ticker_get");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<void> iidxTickerSet(Connection con, String text) {
var req = Request("iidx", "ticker_set");
req.addParam(text);
return con.request(req);
}
Future<void> iidxTickerReset(Connection con) {
var req = Request("iidx", "ticker_reset");
return con.request(req);
}
part of spiceapi;
Future<String> iidxTickerGet(Connection con) {
var req = Request("iidx", "ticker_get");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<void> iidxTickerSet(Connection con, String text) {
var req = Request("iidx", "ticker_set");
req.addParam(text);
return con.request(req);
}
Future<void> iidxTickerReset(Connection con) {
var req = Request("iidx", "ticker_reset");
return con.request(req);
}
@@ -1,22 +1,22 @@
part of spiceapi;
Future<Map> infoAVS(Connection con) {
var req = Request("info", "avs");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<Map> infoLauncher(Connection con) {
var req = Request("info", "launcher");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<Map> infoMemory(Connection con) {
var req = Request("info", "memory");
return con.request(req).then((res) {
return res.getData()[0];
});
}
part of spiceapi;
Future<Map> infoAVS(Connection con) {
var req = Request("info", "avs");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<Map> infoLauncher(Connection con) {
var req = Request("info", "launcher");
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<Map> infoMemory(Connection con) {
var req = Request("info", "memory");
return con.request(req).then((res) {
return res.getData()[0];
});
}
@@ -1,28 +1,28 @@
part of spiceapi;
Future<void> keypadsWrite(Connection con, int unit, String input) {
var req = Request("keypads", "write");
req.addParam(unit);
req.addParam(input);
return con.request(req);
}
Future<void> keypadsSet(Connection con, int unit, String buttons) {
var req = Request("keypads", "set");
req.addParam(unit);
for (int i = 0; i < buttons.length; i++)
req.addParam(buttons[i]);
return con.request(req);
}
Future<String> keypadsGet(Connection con, int unit) {
var req = Request("keypads", "get");
req.addParam(unit);
return con.request(req).then((res) {
String buttons = "";
for (var obj in res.getData()) {
buttons += obj;
}
return buttons;
});
}
part of spiceapi;
Future<void> keypadsWrite(Connection con, int unit, String input) {
var req = Request("keypads", "write");
req.addParam(unit);
req.addParam(input);
return con.request(req);
}
Future<void> keypadsSet(Connection con, int unit, String buttons) {
var req = Request("keypads", "set");
req.addParam(unit);
for (int i = 0; i < buttons.length; i++)
req.addParam(buttons[i]);
return con.request(req);
}
Future<String> keypadsGet(Connection con, int unit) {
var req = Request("keypads", "get");
req.addParam(unit);
return con.request(req).then((res) {
String buttons = "";
for (var obj in res.getData()) {
buttons += obj;
}
return buttons;
});
}
@@ -1,54 +1,54 @@
part of spiceapi;
class LightState {
String name;
double state;
bool active;
LightState(this.name, this.state);
LightState._fromRead(this.name, this.state, this.active);
}
Future<List<LightState>> lightsRead(Connection con) {
var req = Request("lights", "read");
return con.request(req).then((res) {
// build states list
List<LightState> states = [];
for (List state in res.getData()) {
states.add(LightState._fromRead(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> lightsWrite(Connection con, List<LightState> states) {
var req = Request("lights", "write");
// add params
for (var state in states) {
var obj = [
state.name,
state.state
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> lightsWriteReset(Connection con, List<String> names) {
var req = Request("lights", "write_reset");
// add params
for (var name in names)
req.addParam(name);
return con.request(req);
}
part of spiceapi;
class LightState {
String name;
double state;
bool active;
LightState(this.name, this.state);
LightState._fromRead(this.name, this.state, this.active);
}
Future<List<LightState>> lightsRead(Connection con) {
var req = Request("lights", "read");
return con.request(req).then((res) {
// build states list
List<LightState> states = [];
for (List state in res.getData()) {
states.add(LightState._fromRead(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> lightsWrite(Connection con, List<LightState> states) {
var req = Request("lights", "write");
// add params
for (var state in states) {
var obj = [
state.name,
state.state
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> lightsWriteReset(Connection con, List<String> names) {
var req = Request("lights", "write_reset");
// add params
for (var name in names)
req.addParam(name);
return con.request(req);
}
@@ -1,35 +1,35 @@
part of spiceapi;
Future<void> memoryWrite(Connection con,
String dllName, String data, int offset) {
var req = Request("memory", "write");
req.addParam(dllName);
req.addParam(data);
req.addParam(offset);
return con.request(req);
}
Future<String> memoryRead(Connection con,
String dllName, int offset, int size) {
var req = Request("memory", "read");
req.addParam(dllName);
req.addParam(offset);
req.addParam(size);
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<int> memorySignature(Connection con,
String dllName, String signature, String replacement,
int offset, int usage) {
var req = Request("memory", "signature");
req.addParam(dllName);
req.addParam(signature);
req.addParam(replacement);
req.addParam(offset);
req.addParam(usage);
return con.request(req).then((res) {
return res.getData()[0];
});
}
part of spiceapi;
Future<void> memoryWrite(Connection con,
String dllName, String data, int offset) {
var req = Request("memory", "write");
req.addParam(dllName);
req.addParam(data);
req.addParam(offset);
return con.request(req);
}
Future<String> memoryRead(Connection con,
String dllName, int offset, int size) {
var req = Request("memory", "read");
req.addParam(dllName);
req.addParam(offset);
req.addParam(size);
return con.request(req).then((res) {
return res.getData()[0];
});
}
Future<int> memorySignature(Connection con,
String dllName, String signature, String replacement,
int offset, int usage) {
var req = Request("memory", "signature");
req.addParam(dllName);
req.addParam(signature);
req.addParam(replacement);
req.addParam(offset);
req.addParam(usage);
return con.request(req).then((res) {
return res.getData()[0];
});
}
@@ -1,68 +1,68 @@
part of spiceapi;
class TouchState {
int id;
int x, y;
bool active = true;
bool updated = true;
TouchState(this.id, this.x, this.y);
}
Future<List<TouchState>> touchRead(Connection con) {
var req = Request("touch", "read");
return con.request(req).then((res) {
// build states list
List<TouchState> states = [];
for (List state in res.getData()) {
states.add(TouchState(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> touchWrite(Connection con, List<TouchState> states) async {
if (states.isEmpty) return;
var req = Request("touch", "write");
// add params
for (var state in states) {
var obj = [
state.id,
state.x,
state.y
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> touchWriteReset(Connection con, List<TouchState> states) async {
if (states.isEmpty) return;
var req = Request("touch", "write_reset");
// add params
for (var state in states)
req.addParam(state.id);
return con.request(req);
}
Future<void> touchWriteResetIDs(Connection con, List<int> touchIDs) async {
if (touchIDs.isEmpty) return;
var req = Request("touch", "write_reset");
// add params
for (var id in touchIDs)
req.addParam(id);
return con.request(req);
}
part of spiceapi;
class TouchState {
int id;
int x, y;
bool active = true;
bool updated = true;
TouchState(this.id, this.x, this.y);
}
Future<List<TouchState>> touchRead(Connection con) {
var req = Request("touch", "read");
return con.request(req).then((res) {
// build states list
List<TouchState> states = [];
for (List state in res.getData()) {
states.add(TouchState(
state[0],
state[1],
state[2],
));
}
// return it
return states;
});
}
Future<void> touchWrite(Connection con, List<TouchState> states) async {
if (states.isEmpty) return;
var req = Request("touch", "write");
// add params
for (var state in states) {
var obj = [
state.id,
state.x,
state.y
];
req.addParam(obj);
}
return con.request(req);
}
Future<void> touchWriteReset(Connection con, List<TouchState> states) async {
if (states.isEmpty) return;
var req = Request("touch", "write_reset");
// add params
for (var state in states)
req.addParam(state.id);
return con.request(req);
}
Future<void> touchWriteResetIDs(Connection con, List<int> touchIDs) async {
if (touchIDs.isEmpty) return;
var req = Request("touch", "write_reset");
// add params
for (var id in touchIDs)
req.addParam(id);
return con.request(req);
}
+116 -116
View File
@@ -1,116 +1,116 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
+24 -24
View File
@@ -1,24 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
+14 -14
View File
@@ -1,14 +1,14 @@
from .connection import Connection
from .request import Request
from .analogs import *
from .buttons import *
from .card import *
from .coin import *
from .control import *
from .exceptions import *
from .iidx import *
from .info import *
from .keypads import *
from .lights import *
from .memory import *
from .touch import *
from .connection import Connection
from .request import Request
from .analogs import *
from .buttons import *
from .card import *
from .coin import *
from .control import *
from .exceptions import *
from .iidx import *
from .info import *
from .keypads import *
from .lights import *
from .memory import *
from .touch import *
+28 -28
View File
@@ -1,28 +1,28 @@
from .connection import Connection
from .request import Request
def analogs_read(con: Connection):
res = con.request(Request("analogs", "read"))
return res.get_data()
def analogs_write(con: Connection, analog_state_list):
req = Request("analogs", "write")
for state in analog_state_list:
req.add_param(state)
con.request(req)
def analogs_write_reset(con: Connection, analog_names=None):
req = Request("analogs", "write_reset")
# reset all analogs
if not analog_names:
con.request(req)
return
# reset specified analogs
for analog_name in analog_names:
req.add_param(analog_name)
con.request(req)
from .connection import Connection
from .request import Request
def analogs_read(con: Connection):
res = con.request(Request("analogs", "read"))
return res.get_data()
def analogs_write(con: Connection, analog_state_list):
req = Request("analogs", "write")
for state in analog_state_list:
req.add_param(state)
con.request(req)
def analogs_write_reset(con: Connection, analog_names=None):
req = Request("analogs", "write_reset")
# reset all analogs
if not analog_names:
con.request(req)
return
# reset specified analogs
for analog_name in analog_names:
req.add_param(analog_name)
con.request(req)
+28 -28
View File
@@ -1,28 +1,28 @@
from .connection import Connection
from .request import Request
def buttons_read(con: Connection):
res = con.request(Request("buttons", "read"))
return res.get_data()
def buttons_write(con: Connection, button_state_list):
req = Request("buttons", "write")
for state in button_state_list:
req.add_param(state)
con.request(req)
def buttons_write_reset(con: Connection, button_names=None):
req = Request("buttons", "write_reset")
# reset all buttons
if not button_names:
con.request(req)
return
# reset specified buttons
for button_name in button_names:
req.add_param(button_name)
con.request(req)
from .connection import Connection
from .request import Request
def buttons_read(con: Connection):
res = con.request(Request("buttons", "read"))
return res.get_data()
def buttons_write(con: Connection, button_state_list):
req = Request("buttons", "write")
for state in button_state_list:
req.add_param(state)
con.request(req)
def buttons_write_reset(con: Connection, button_names=None):
req = Request("buttons", "write_reset")
# reset all buttons
if not button_names:
con.request(req)
return
# reset specified buttons
for button_name in button_names:
req.add_param(button_name)
con.request(req)
+9 -9
View File
@@ -1,9 +1,9 @@
from .connection import Connection
from .request import Request
def card_insert(con: Connection, unit: int, card_id: str):
req = Request("card", "insert")
req.add_param(unit)
req.add_param(card_id)
con.request(req)
from .connection import Connection
from .request import Request
def card_insert(con: Connection, unit: int, card_id: str):
req = Request("card", "insert")
req.add_param(unit)
req.add_param(card_id)
con.request(req)
+20 -20
View File
@@ -1,20 +1,20 @@
from .connection import Connection
from .request import Request
def coin_get(con: Connection):
res = con.request(Request("coin", "get"))
return res.get_data()[0]
def coin_set(con: Connection, amount: int):
req = Request("coin", "set")
req.add_param(amount)
con.request(req)
def coin_insert(con: Connection, amount=1):
req = Request("coin", "insert")
if amount != 1:
req.add_param(amount)
con.request(req)
from .connection import Connection
from .request import Request
def coin_get(con: Connection):
res = con.request(Request("coin", "get"))
return res.get_data()[0]
def coin_set(con: Connection, amount: int):
req = Request("coin", "set")
req.add_param(amount)
con.request(req)
def coin_insert(con: Connection, amount=1):
req = Request("coin", "insert")
if amount != 1:
req.add_param(amount)
con.request(req)
+139 -139
View File
@@ -1,139 +1,139 @@
import os
import socket
from .request import Request
from .response import Response
from .rc4 import rc4
from .exceptions import MalformedRequestException, APIError
class Connection:
""" Container for managing a single connection to the API server.
"""
def __init__(self, host: str, port: int, password: str):
"""Default constructor.
:param host: the host string to connect to
:param port: the port of the host
:param password: the connection password string
"""
self.host = host
self.port = port
self.password = password
self.socket = None
self.cipher = None
self.reconnect()
def reconnect(self, refresh_session=True):
"""Reconnect to the server.
This opens a new connection and closes the previous one, if existing.
"""
# close old socket
self.close()
# create new socket
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.settimeout(3)
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
self.socket.connect((self.host, self.port))
# cipher
self.change_password(self.password)
# refresh session
if refresh_session:
from .control import control_session_refresh
control_session_refresh(self)
def change_password(self, password):
"""Allows to change the password on the fly.
The cipher will be rebuilt.
"""
if len(password) > 0:
self.cipher = rc4(password.encode("UTF-8"))
else:
self.cipher = None
def close(self):
"""Close the active connection, if existing."""
# check if socket is existing
if self.socket:
# close and delete socket
self.socket.close()
self.socket = None
def request(self, request: Request):
"""Send a request to the server and receive the answer.
:param request: request object
:return: response object
"""
# check if disconnected
if not self.socket:
raise RuntimeError("No active connection.")
# build data
data = request.to_json().encode("UTF-8") + b"\x00"
if self.cipher:
data_list = list(data)
data_cipher = []
for b in data_list:
data_cipher.append(b ^ next(self.cipher))
data = bytes(data_cipher)
# send request
if os.name != 'nt':
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_QUICKACK, 1)
self.socket.send(data)
# get answer
answer_data = []
while not len(answer_data) or answer_data[-1] != 0:
# receive data
if os.name != 'nt':
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_QUICKACK, 1)
receive_data = self.socket.recv(4096)
# check length
if len(receive_data):
# check cipher
if self.cipher:
# add decrypted data
for b in receive_data:
answer_data.append(int(b ^ next(self.cipher)))
else:
# add plaintext
for b in receive_data:
answer_data.append(int(b))
else:
raise RuntimeError("Connection was closed.")
# check for empty response
if len(answer_data) <= 1:
# empty response means the JSON couldn't be parsed
raise MalformedRequestException()
# build response
response = Response(bytes(answer_data[:-1]).decode("UTF-8"))
if len(response.get_errors()):
raise APIError(response.get_errors())
# check ID
req_id = request.get_id()
res_id = response.get_id()
if req_id != res_id:
raise RuntimeError(f"Unexpected response ID: {res_id} (expected {req_id})")
# return response object
return response
import os
import socket
from .request import Request
from .response import Response
from .rc4 import rc4
from .exceptions import MalformedRequestException, APIError
class Connection:
""" Container for managing a single connection to the API server.
"""
def __init__(self, host: str, port: int, password: str):
"""Default constructor.
:param host: the host string to connect to
:param port: the port of the host
:param password: the connection password string
"""
self.host = host
self.port = port
self.password = password
self.socket = None
self.cipher = None
self.reconnect()
def reconnect(self, refresh_session=True):
"""Reconnect to the server.
This opens a new connection and closes the previous one, if existing.
"""
# close old socket
self.close()
# create new socket
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.settimeout(3)
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
self.socket.connect((self.host, self.port))
# cipher
self.change_password(self.password)
# refresh session
if refresh_session:
from .control import control_session_refresh
control_session_refresh(self)
def change_password(self, password):
"""Allows to change the password on the fly.
The cipher will be rebuilt.
"""
if len(password) > 0:
self.cipher = rc4(password.encode("UTF-8"))
else:
self.cipher = None
def close(self):
"""Close the active connection, if existing."""
# check if socket is existing
if self.socket:
# close and delete socket
self.socket.close()
self.socket = None
def request(self, request: Request):
"""Send a request to the server and receive the answer.
:param request: request object
:return: response object
"""
# check if disconnected
if not self.socket:
raise RuntimeError("No active connection.")
# build data
data = request.to_json().encode("UTF-8") + b"\x00"
if self.cipher:
data_list = list(data)
data_cipher = []
for b in data_list:
data_cipher.append(b ^ next(self.cipher))
data = bytes(data_cipher)
# send request
if os.name != 'nt':
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_QUICKACK, 1)
self.socket.send(data)
# get answer
answer_data = []
while not len(answer_data) or answer_data[-1] != 0:
# receive data
if os.name != 'nt':
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_QUICKACK, 1)
receive_data = self.socket.recv(4096)
# check length
if len(receive_data):
# check cipher
if self.cipher:
# add decrypted data
for b in receive_data:
answer_data.append(int(b ^ next(self.cipher)))
else:
# add plaintext
for b in receive_data:
answer_data.append(int(b))
else:
raise RuntimeError("Connection was closed.")
# check for empty response
if len(answer_data) <= 1:
# empty response means the JSON couldn't be parsed
raise MalformedRequestException()
# build response
response = Response(bytes(answer_data[:-1]).decode("UTF-8"))
if len(response.get_errors()):
raise APIError(response.get_errors())
# check ID
req_id = request.get_id()
res_id = response.get_id()
if req_id != res_id:
raise RuntimeError(f"Unexpected response ID: {res_id} (expected {req_id})")
# return response object
return response
+51 -51
View File
@@ -1,51 +1,51 @@
import random
from .connection import Connection
from .request import Request
def control_raise(con: Connection, signal: str):
req = Request("control", "raise")
req.add_param(signal)
con.request(req)
def control_exit(con: Connection, code=None):
req = Request("control", "exit")
if code:
req.add_param(code)
try:
con.request(req)
except RuntimeError:
pass # we expect the connection to get killed
def control_restart(con: Connection):
req = Request("control", "restart")
try:
con.request(req)
except RuntimeError:
pass # we expect the connection to get killed
def control_session_refresh(con: Connection):
res = con.request(Request("control", "session_refresh", req_id=random.randint(1, 2**64)))
# apply new password
password = res.get_data()[0]
con.change_password(password)
def control_shutdown(con: Connection):
req = Request("control", "shutdown")
try:
con.request(req)
except RuntimeError:
pass # we expect the connection to get killed
def control_reboot(con: Connection):
req = Request("control", "reboot")
try:
con.request(req)
except RuntimeError:
pass # we expect the connection to get killed
import random
from .connection import Connection
from .request import Request
def control_raise(con: Connection, signal: str):
req = Request("control", "raise")
req.add_param(signal)
con.request(req)
def control_exit(con: Connection, code=None):
req = Request("control", "exit")
if code:
req.add_param(code)
try:
con.request(req)
except RuntimeError:
pass # we expect the connection to get killed
def control_restart(con: Connection):
req = Request("control", "restart")
try:
con.request(req)
except RuntimeError:
pass # we expect the connection to get killed
def control_session_refresh(con: Connection):
res = con.request(Request("control", "session_refresh", req_id=random.randint(1, 2**64)))
# apply new password
password = res.get_data()[0]
con.change_password(password)
def control_shutdown(con: Connection):
req = Request("control", "shutdown")
try:
con.request(req)
except RuntimeError:
pass # we expect the connection to get killed
def control_reboot(con: Connection):
req = Request("control", "reboot")
try:
con.request(req)
except RuntimeError:
pass # we expect the connection to get killed
+10 -10
View File
@@ -1,10 +1,10 @@
class APIError(Exception):
def __init__(self, errors):
super().__init__("\r\n".join(errors))
class MalformedRequestException(Exception):
pass
class APIError(Exception):
def __init__(self, errors):
super().__init__("\r\n".join(errors))
class MalformedRequestException(Exception):
pass
+18 -18
View File
@@ -1,18 +1,18 @@
from .connection import Connection
from .request import Request
def iidx_ticker_get(con: Connection):
res = con.request(Request("iidx", "ticker_get"))
return res.get_data()
def iidx_ticker_set(con: Connection, text: str):
req = Request("iidx", "ticker_set")
req.add_param(text)
con.request(req)
def iidx_ticker_reset(con: Connection):
req = Request("iidx", "ticker_reset")
con.request(req)
from .connection import Connection
from .request import Request
def iidx_ticker_get(con: Connection):
res = con.request(Request("iidx", "ticker_get"))
return res.get_data()
def iidx_ticker_set(con: Connection, text: str):
req = Request("iidx", "ticker_set")
req.add_param(text)
con.request(req)
def iidx_ticker_reset(con: Connection):
req = Request("iidx", "ticker_reset")
con.request(req)
+17 -17
View File
@@ -1,17 +1,17 @@
from .connection import Connection
from .request import Request
def info_avs(con: Connection):
res = con.request(Request("info", "avs"))
return res.get_data()[0]
def info_launcher(con: Connection):
res = con.request(Request("info", "launcher"))
return res.get_data()[0]
def info_memory(con: Connection):
res = con.request(Request("info", "memory"))
return res.get_data()[0]
from .connection import Connection
from .request import Request
def info_avs(con: Connection):
res = con.request(Request("info", "avs"))
return res.get_data()[0]
def info_launcher(con: Connection):
res = con.request(Request("info", "launcher"))
return res.get_data()[0]
def info_memory(con: Connection):
res = con.request(Request("info", "memory"))
return res.get_data()[0]
+24 -24
View File
@@ -1,24 +1,24 @@
from .connection import Connection
from .request import Request
def keypads_write(con: Connection, keypad: int, input_values: str):
req = Request("keypads", "write")
req.add_param(keypad)
req.add_param(input_values)
con.request(req)
def keypads_set(con: Connection, keypad: int, input_values: str):
req = Request("keypads", "set")
req.add_param(keypad)
for value in input_values:
req.add_param(value)
con.request(req)
def keypads_get(con: Connection, keypad: int):
req = Request("keypads", "get")
req.add_param(keypad)
res = con.request(req)
return res.get_data()
from .connection import Connection
from .request import Request
def keypads_write(con: Connection, keypad: int, input_values: str):
req = Request("keypads", "write")
req.add_param(keypad)
req.add_param(input_values)
con.request(req)
def keypads_set(con: Connection, keypad: int, input_values: str):
req = Request("keypads", "set")
req.add_param(keypad)
for value in input_values:
req.add_param(value)
con.request(req)
def keypads_get(con: Connection, keypad: int):
req = Request("keypads", "get")
req.add_param(keypad)
res = con.request(req)
return res.get_data()
+28 -28
View File
@@ -1,28 +1,28 @@
from .connection import Connection
from .request import Request
def lights_read(con: Connection):
res = con.request(Request("lights", "read"))
return res.get_data()
def lights_write(con: Connection, light_state_list):
req = Request("lights", "write")
for state in light_state_list:
req.add_param(state)
con.request(req)
def lights_write_reset(con: Connection, light_names=None):
req = Request("lights", "write_reset")
# reset all lights
if not light_names:
con.request(req)
return
# reset specified lights
for light_name in light_names:
req.add_param(light_name)
con.request(req)
from .connection import Connection
from .request import Request
def lights_read(con: Connection):
res = con.request(Request("lights", "read"))
return res.get_data()
def lights_write(con: Connection, light_state_list):
req = Request("lights", "write")
for state in light_state_list:
req.add_param(state)
con.request(req)
def lights_write_reset(con: Connection, light_names=None):
req = Request("lights", "write_reset")
# reset all lights
if not light_names:
con.request(req)
return
# reset specified lights
for light_name in light_names:
req.add_param(light_name)
con.request(req)
+31 -31
View File
@@ -1,31 +1,31 @@
from .connection import Connection
from .request import Request
def memory_write(con: Connection, dll_name: str, data: str, offset: int):
req = Request("memory", "write")
req.add_param(dll_name)
req.add_param(data)
req.add_param(offset)
con.request(req)
def memory_read(con: Connection, dll_name: str, offset: int, size: int):
req = Request("memory", "read")
req.add_param(dll_name)
req.add_param(offset)
req.add_param(size)
res = con.request(req)
return res.get_data()[0]
def memory_signature(con: Connection, dll_name: str, signature: str,
replacement: str, offset: int, usage: int):
req = Request("memory", "signature")
req.add_param(dll_name)
req.add_param(signature)
req.add_param(replacement)
req.add_param(offset)
req.add_param(usage)
res = con.request(req)
return res.get_data()[0]
from .connection import Connection
from .request import Request
def memory_write(con: Connection, dll_name: str, data: str, offset: int):
req = Request("memory", "write")
req.add_param(dll_name)
req.add_param(data)
req.add_param(offset)
con.request(req)
def memory_read(con: Connection, dll_name: str, offset: int, size: int):
req = Request("memory", "read")
req.add_param(dll_name)
req.add_param(offset)
req.add_param(size)
res = con.request(req)
return res.get_data()[0]
def memory_signature(con: Connection, dll_name: str, signature: str,
replacement: str, offset: int, usage: int):
req = Request("memory", "signature")
req.add_param(dll_name)
req.add_param(signature)
req.add_param(replacement)
req.add_param(offset)
req.add_param(usage)
res = con.request(req)
return res.get_data()[0]
+24 -24
View File
@@ -1,24 +1,24 @@
def rc4_ksa(key):
n = len(key)
j = 0
s_box = list(range(256))
for i in range(256):
j = (j + s_box[i] + key[i % n]) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
return s_box
def rc4_prga(s_box):
i = 0
j = 0
while True:
i = (i + 1) % 256
j = (j + s_box[i]) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
yield s_box[(s_box[i] + s_box[j]) % 256]
def rc4(key):
return rc4_prga(rc4_ksa(key))
def rc4_ksa(key):
n = len(key)
j = 0
s_box = list(range(256))
for i in range(256):
j = (j + s_box[i] + key[i % n]) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
return s_box
def rc4_prga(s_box):
i = 0
j = 0
while True:
i = (i + 1) % 256
j = (j + s_box[i]) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
yield s_box[(s_box[i] + s_box[j]) % 256]
def rc4(key):
return rc4_prga(rc4_ksa(key))
+63 -63
View File
@@ -1,63 +1,63 @@
import json
from threading import Lock
class Request:
# global ID pool
GLOBAL_ID = 1
GLOBAL_ID_LOCK = Lock()
def __init__(self, module: str, function: str, req_id=None):
# use global ID
with Request.GLOBAL_ID_LOCK:
if req_id is None:
# reset at max value
Request.GLOBAL_ID += 1
if Request.GLOBAL_ID >= 2 ** 64:
Request.GLOBAL_ID = 1
# get ID and increase by one
req_id = Request.GLOBAL_ID
else:
# carry over ID
Request.GLOBAL_ID = req_id
# remember ID
self._id = req_id
# build data dict
self.data = {
"id": req_id,
"module": module,
"function": function,
"params": []
}
@staticmethod
def from_json(request_json: str):
req = Request("", "", 0)
req.data = json.loads(request_json)
req._id = req.data["id"]
return req
def get_id(self):
return self._id
def to_json(self):
return json.dumps(
self.data,
ensure_ascii=False,
check_circular=False,
allow_nan=False,
indent=None,
separators=(",", ":"),
sort_keys=False
)
def add_param(self, param):
self.data["params"].append(param)
import json
from threading import Lock
class Request:
# global ID pool
GLOBAL_ID = 1
GLOBAL_ID_LOCK = Lock()
def __init__(self, module: str, function: str, req_id=None):
# use global ID
with Request.GLOBAL_ID_LOCK:
if req_id is None:
# reset at max value
Request.GLOBAL_ID += 1
if Request.GLOBAL_ID >= 2 ** 64:
Request.GLOBAL_ID = 1
# get ID and increase by one
req_id = Request.GLOBAL_ID
else:
# carry over ID
Request.GLOBAL_ID = req_id
# remember ID
self._id = req_id
# build data dict
self.data = {
"id": req_id,
"module": module,
"function": function,
"params": []
}
@staticmethod
def from_json(request_json: str):
req = Request("", "", 0)
req.data = json.loads(request_json)
req._id = req.data["id"]
return req
def get_id(self):
return self._id
def to_json(self):
return json.dumps(
self.data,
ensure_ascii=False,
check_circular=False,
allow_nan=False,
indent=None,
separators=(",", ":"),
sort_keys=False
)
def add_param(self, param):
self.data["params"].append(param)
+30 -30
View File
@@ -1,30 +1,30 @@
import json
class Response:
def __init__(self, response_json: str):
self._res = json.loads(response_json)
self._id = self._res["id"]
self._errors = self._res["errors"]
self._data = self._res["data"]
def to_json(self):
return json.dumps(
self._res,
ensure_ascii=True,
check_circular=False,
allow_nan=False,
indent=2,
separators=(",", ": "),
sort_keys=False
)
def get_id(self):
return self._id
def get_errors(self):
return self._errors
def get_data(self):
return self._data
import json
class Response:
def __init__(self, response_json: str):
self._res = json.loads(response_json)
self._id = self._res["id"]
self._errors = self._res["errors"]
self._data = self._res["data"]
def to_json(self):
return json.dumps(
self._res,
ensure_ascii=True,
check_circular=False,
allow_nan=False,
indent=2,
separators=(",", ": "),
sort_keys=False
)
def get_id(self):
return self._id
def get_errors(self):
return self._errors
def get_data(self):
return self._data
+21 -21
View File
@@ -1,21 +1,21 @@
from .connection import Connection
from .request import Request
def touch_read(con: Connection):
res = con.request(Request("touch", "read"))
return res.get_data()
def touch_write(con: Connection, touch_points):
req = Request("touch", "write")
for state in touch_points:
req.add_param(state)
con.request(req)
def touch_write_reset(con: Connection, touch_ids):
req = Request("touch", "write_reset")
for touch_id in touch_ids:
req.add_param(touch_id)
con.request(req)
from .connection import Connection
from .request import Request
def touch_read(con: Connection):
res = con.request(Request("touch", "read"))
return res.get_data()
def touch_write(con: Connection, touch_points):
req = Request("touch", "write")
for state in touch_points:
req.add_param(state)
con.request(req)
def touch_write_reset(con: Connection, touch_ids):
req = Request("touch", "write_reset")
for touch_id in touch_ids:
req.add_param(touch_id)
con.request(req)
File diff suppressed because it is too large Load Diff
+52 -52
View File
@@ -1,52 +1,52 @@
#!/usr/bin/env python3
import binascii
import spiceapi
import argparse
def patch_string(con, dll_name: str, find: str, replace: str):
while True:
try:
# replace first result
address = spiceapi.memory_signature(
con, dll_name,
binascii.hexlify(bytes(find, "utf-8")).decode("utf-8"),
binascii.hexlify(bytes(replace, "utf-8")).decode("utf-8"),
0, 0)
# print findings
print("{}: {} = {} => {}".format(
dll_name,
hex(address),
find,
replace))
except spiceapi.APIError:
# this happens when the signature wasn't found anymore
break
def main():
# parse args
parser = argparse.ArgumentParser(description="SpiceAPI string replacer")
parser.add_argument("host", type=str, help="The host to connect to")
parser.add_argument("port", type=int, help="The port the host is using")
parser.add_argument("password", type=str, help="The pass the host is using")
parser.add_argument("dll", type=str, help="The DLL to patch")
parser.add_argument("find", type=str, help="The string to find")
parser.add_argument("replace", type=str, help="The string to replace with")
args = parser.parse_args()
# connect
con = spiceapi.Connection(host=args.host, port=args.port, password=args.password)
# replace the string
patch_string(con, args.dll, args.find, args.replace)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
import binascii
import spiceapi
import argparse
def patch_string(con, dll_name: str, find: str, replace: str):
while True:
try:
# replace first result
address = spiceapi.memory_signature(
con, dll_name,
binascii.hexlify(bytes(find, "utf-8")).decode("utf-8"),
binascii.hexlify(bytes(replace, "utf-8")).decode("utf-8"),
0, 0)
# print findings
print("{}: {} = {} => {}".format(
dll_name,
hex(address),
find,
replace))
except spiceapi.APIError:
# this happens when the signature wasn't found anymore
break
def main():
# parse args
parser = argparse.ArgumentParser(description="SpiceAPI string replacer")
parser.add_argument("host", type=str, help="The host to connect to")
parser.add_argument("port", type=int, help="The port the host is using")
parser.add_argument("password", type=str, help="The pass the host is using")
parser.add_argument("dll", type=str, help="The DLL to patch")
parser.add_argument("find", type=str, help="The string to find")
parser.add_argument("replace", type=str, help="The string to replace with")
args = parser.parse_args()
# connect
con = spiceapi.Connection(host=args.host, port=args.port, password=args.password)
# replace the string
patch_string(con, args.dll, args.find, args.replace)
if __name__ == "__main__":
main()
+51 -51
View File
@@ -1,51 +1,51 @@
#include "external/rapidjson/document.h"
#include "external/rapidjson/writer.h"
#include "external/rapidjson/prettywriter.h"
#include "util/logging.h"
#include "response.h"
using namespace api;
Response::Response(uint64_t id) {
// load template
document.Parse(
"{"
"\"id\": -1,"
"\"errors\": [],"
"\"data\": []"
"}"
);
// check for error
auto error = document.GetParseError();
if (error)
log_warning("api", "response template parse error: {}", error);
// set ID
document["id"].SetUint64(id);
// get fields
this->errors = document["errors"];
this->data = document["data"];
}
std::string Response::get_string(bool pretty) {
// apply errors and data
this->document["errors"] = this->errors;
this->document["data"] = this->data;
// generate string
rapidjson::StringBuffer sb;
if (pretty) {
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb);
this->document.Accept(writer);
} else {
rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
this->document.Accept(writer);
}
return std::string(sb.GetString());
}
#include "external/rapidjson/document.h"
#include "external/rapidjson/writer.h"
#include "external/rapidjson/prettywriter.h"
#include "util/logging.h"
#include "response.h"
using namespace api;
Response::Response(uint64_t id) {
// load template
document.Parse(
"{"
"\"id\": -1,"
"\"errors\": [],"
"\"data\": []"
"}"
);
// check for error
auto error = document.GetParseError();
if (error)
log_warning("api", "response template parse error: {}", error);
// set ID
document["id"].SetUint64(id);
// get fields
this->errors = document["errors"];
this->data = document["data"];
}
std::string Response::get_string(bool pretty) {
// apply errors and data
this->document["errors"] = this->errors;
this->document["data"] = this->data;
// generate string
rapidjson::StringBuffer sb;
if (pretty) {
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb);
this->document.Accept(writer);
} else {
rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
this->document.Accept(writer);
}
return std::string(sb.GetString());
}
+37 -37
View File
@@ -1,37 +1,37 @@
#pragma once
#include "external/rapidjson/document.h"
namespace api {
class Response {
private:
rapidjson::Document document;
rapidjson::Value errors;
rapidjson::Value data;
public:
std::string password;
bool password_changed = false;
Response(uint64_t id);
template <class T> void add_error(T& error) {
this->errors.PushBack(error, document.GetAllocator());
};
template <class T> void add_data(T& data) {
this->data.PushBack(data, document.GetAllocator());
}
std::string get_string(bool pretty=false);
inline rapidjson::Document* doc() {
return &document;
}
inline void password_change(std::string password) {
this->password = password;
this->password_changed = true;
}
};
}
#pragma once
#include "external/rapidjson/document.h"
namespace api {
class Response {
private:
rapidjson::Document document;
rapidjson::Value errors;
rapidjson::Value data;
public:
std::string password;
bool password_changed = false;
Response(uint64_t id);
template <class T> void add_error(T& error) {
this->errors.PushBack(error, document.GetAllocator());
};
template <class T> void add_data(T& data) {
this->data.PushBack(data, document.GetAllocator());
}
std::string get_string(bool pretty=false);
inline rapidjson::Document* doc() {
return &document;
}
inline void password_change(std::string password) {
this->password = password;
this->password_changed = true;
}
};
}
+30 -30
View File
@@ -1,30 +1,30 @@
#pragma once
#include <string>
#include <thread>
#include <windows.h>
namespace api {
class Controller;
struct ClientState;
class SerialController {
public:
SerialController(Controller *controller, std::string port, DWORD baud);
~SerialController();
void open_port();
void free_port();
private:
Controller *controller = nullptr;
std::string port = "";
DWORD baud = 0;
HANDLE handle = INVALID_HANDLE_VALUE;
std::thread *thread = nullptr;
ClientState *state = nullptr;
bool running = true;
};
}
#pragma once
#include <string>
#include <thread>
#include <windows.h>
namespace api {
class Controller;
struct ClientState;
class SerialController {
public:
SerialController(Controller *controller, std::string port, DWORD baud);
~SerialController();
void open_port();
void free_port();
private:
Controller *controller = nullptr;
std::string port = "";
DWORD baud = 0;
HANDLE handle = INVALID_HANDLE_VALUE;
std::thread *thread = nullptr;
ClientState *state = nullptr;
bool running = true;
};
}
+169 -169
View File
@@ -1,169 +1,169 @@
#define HEADSOCKET_IMPLEMENTATION
#include "external/headsocket.h"
#include "websocket.h"
#include "util/utils.h"
#include "util/rc4.h"
#include "util/logging.h"
#include "controller.h"
using namespace headsocket;
namespace api {
/*
* Client class declaration
*/
class WebSocketClient : public web_socket_client {
// required class header
HEADSOCKET_CLIENT(WebSocketClient, web_socket_client);
private:
ClientState *state = nullptr;
protected:
bool async_received_data(const data_block &db, uint8_t *ptr, size_t length) override;
void on_accept() override;
void on_disconnect() override;
};
/*
* Server class declaration
*/
class WebSocketServer : public web_socket_server<WebSocketClient> {
HEADSOCKET_SERVER(WebSocketServer, web_socket_server);
public:
WebSocketController *websocket;
};
void api::WebSocketServer::init() {}
/*
* Controller state so we don't have to import headsocket stuff in our header
*/
struct WebSocketControllerState {
std::shared_ptr<WebSocketServer> server;
};
WebSocketController::WebSocketController(Controller *controller, uint16_t port) {
this->controller = controller;
// create state
this->state = new WebSocketControllerState();
// start server
this->state->server = WebSocketServer::create(port);
this->state->server->websocket = this;
if (this->state->server->is_running()) {
log_info("api::websocket", "server listening on port: {}", port);
} else {
log_warning("api::websocket", "server failed to listen on port: {}", port);
}
}
WebSocketController::~WebSocketController() {
// stop server
this->state->server->stop();
// delete state
delete this->state;
}
void WebSocketController::free_socket() {
this->state->server->stop();
}
void WebSocketClient::on_accept() {
web_socket_client::on_accept();
// get pointer to server
auto srv = reinterpret_cast<WebSocketServer *>(server().get());
if (!srv || !srv->websocket) {
log_fatal("api::websocket", "on_accept has no server");
}
// check for init
state = new ClientState();
srv->websocket->controller->init_state(state);
// log connection
log_info("api::websocket", "client connected");
}
void WebSocketClient::on_disconnect() {
// log disconnection
log_info("api::websocket", "client disconnected");
// get pointer to server
auto srv = reinterpret_cast<WebSocketServer *>(server().get());
if (!srv || !srv->websocket) {
log_fatal("api::websocket", "on_disconnect has no server");
}
// clean up state
srv->websocket->controller->free_state(state);
delete state;
state = nullptr;
// call super
web_socket_client::on_disconnect();
}
/*
* This is where business actually happens, gets called on every datablock receive
*/
bool WebSocketClient::async_received_data(const data_block &db, uint8_t *ptr, size_t length) {
// get pointer to server
auto srv = reinterpret_cast<WebSocketServer *>(server().get());
if (!srv || !srv->websocket) {
log_fatal("api::websocket", "received datablock without server");
}
// check state
if (!state) {
log_fatal("api::websocket", "client with no state received datablock");
}
// check datablock type
switch (db.op) {
case opcode::binary: {
// allocate buffers
std::vector<char> in(ptr, ptr + length);
std::vector<char> out;
// crypt in-data
if (state->cipher) {
state->cipher->crypt(reinterpret_cast<uint8_t *>(in.data()), in.size());
}
// process request
srv->websocket->controller->process_request(state, &in, &out);
// crypt out-data
if (state->cipher) {
state->cipher->crypt(reinterpret_cast<uint8_t *>(out.data()), out.size());
}
// send answer
push(out.data(), out.size());
// check for password change
srv->websocket->controller->process_password_change(state);
break;
}
default:
log_warning("api::websocket", "datablock received with non-binary type");
break;
}
// always consume the datablock, nomnom
return true;
}
}
#define HEADSOCKET_IMPLEMENTATION
#include "external/headsocket.h"
#include "websocket.h"
#include "util/utils.h"
#include "util/rc4.h"
#include "util/logging.h"
#include "controller.h"
using namespace headsocket;
namespace api {
/*
* Client class declaration
*/
class WebSocketClient : public web_socket_client {
// required class header
HEADSOCKET_CLIENT(WebSocketClient, web_socket_client);
private:
ClientState *state = nullptr;
protected:
bool async_received_data(const data_block &db, uint8_t *ptr, size_t length) override;
void on_accept() override;
void on_disconnect() override;
};
/*
* Server class declaration
*/
class WebSocketServer : public web_socket_server<WebSocketClient> {
HEADSOCKET_SERVER(WebSocketServer, web_socket_server);
public:
WebSocketController *websocket;
};
void api::WebSocketServer::init() {}
/*
* Controller state so we don't have to import headsocket stuff in our header
*/
struct WebSocketControllerState {
std::shared_ptr<WebSocketServer> server;
};
WebSocketController::WebSocketController(Controller *controller, uint16_t port) {
this->controller = controller;
// create state
this->state = new WebSocketControllerState();
// start server
this->state->server = WebSocketServer::create(port);
this->state->server->websocket = this;
if (this->state->server->is_running()) {
log_info("api::websocket", "server listening on port: {}", port);
} else {
log_warning("api::websocket", "server failed to listen on port: {}", port);
}
}
WebSocketController::~WebSocketController() {
// stop server
this->state->server->stop();
// delete state
delete this->state;
}
void WebSocketController::free_socket() {
this->state->server->stop();
}
void WebSocketClient::on_accept() {
web_socket_client::on_accept();
// get pointer to server
auto srv = reinterpret_cast<WebSocketServer *>(server().get());
if (!srv || !srv->websocket) {
log_fatal("api::websocket", "on_accept has no server");
}
// check for init
state = new ClientState();
srv->websocket->controller->init_state(state);
// log connection
log_info("api::websocket", "client connected");
}
void WebSocketClient::on_disconnect() {
// log disconnection
log_info("api::websocket", "client disconnected");
// get pointer to server
auto srv = reinterpret_cast<WebSocketServer *>(server().get());
if (!srv || !srv->websocket) {
log_fatal("api::websocket", "on_disconnect has no server");
}
// clean up state
srv->websocket->controller->free_state(state);
delete state;
state = nullptr;
// call super
web_socket_client::on_disconnect();
}
/*
* This is where business actually happens, gets called on every datablock receive
*/
bool WebSocketClient::async_received_data(const data_block &db, uint8_t *ptr, size_t length) {
// get pointer to server
auto srv = reinterpret_cast<WebSocketServer *>(server().get());
if (!srv || !srv->websocket) {
log_fatal("api::websocket", "received datablock without server");
}
// check state
if (!state) {
log_fatal("api::websocket", "client with no state received datablock");
}
// check datablock type
switch (db.op) {
case opcode::binary: {
// allocate buffers
std::vector<char> in(ptr, ptr + length);
std::vector<char> out;
// crypt in-data
if (state->cipher) {
state->cipher->crypt(reinterpret_cast<uint8_t *>(in.data()), in.size());
}
// process request
srv->websocket->controller->process_request(state, &in, &out);
// crypt out-data
if (state->cipher) {
state->cipher->crypt(reinterpret_cast<uint8_t *>(out.data()), out.size());
}
// send answer
push(out.data(), out.size());
// check for password change
srv->websocket->controller->process_password_change(state);
break;
}
default:
log_warning("api::websocket", "datablock received with non-binary type");
break;
}
// always consume the datablock, nomnom
return true;
}
}
+21 -21
View File
@@ -1,21 +1,21 @@
#pragma once
#include <cstdint>
#include <thread>
namespace api {
struct WebSocketControllerState;
class Controller;
class WebSocketController {
public:
WebSocketController(Controller *controller, uint16_t port);
~WebSocketController();
void free_socket();
Controller *controller = nullptr;
WebSocketControllerState *state = nullptr;
};
}
#pragma once
#include <cstdint>
#include <thread>
namespace api {
struct WebSocketControllerState;
class Controller;
class WebSocketController {
public:
WebSocketController(Controller *controller, uint16_t port);
~WebSocketController();
void free_socket();
Controller *controller = nullptr;
WebSocketControllerState *state = nullptr;
};
}