bool isOrderComplete(CURL *curl, Parameters params, int orderId) { bool isComplete; if (orderId == 0) { return true; } std::ostringstream oss; oss << "\"order_id\":" << orderId; std::string options = oss.str(); json_t *root = authRequest(curl, params, "https://api.bitfinex.com/v1/order/status", "order/status", options); isComplete = !json_boolean_value(json_object_get(root, "is_live")); json_decref(root); return isComplete; }
int read_cfg_bool(json_t *root, const char *key, bool *val, bool required, bool default_val) { json_t *node = json_object_get(root, key); if (!node) { if (required) { return -__LINE__; } else { *val = default_val; return 0; } } if (!json_is_boolean(node)) return -__LINE__; *val = json_boolean_value(node); return 0; }
int borrowBtc(Parameters& params, double amount) { int borrowId = 0; bool isBorrowAccepted = false; std::ostringstream oss; oss << "api_key=" << params.okcoinApi << "&symbol=btc_usd&days=fifteen&amount=" << 1 << "&rate=0.0001&secret_key=" << params.okcoinSecret; std::string signature = oss.str(); oss.clear(); oss.str(""); oss << "api_key=" << params.okcoinApi << "&symbol=btc_usd&days=fifteen&amount=" << 1 << "&rate=0.0001"; std::string content = oss.str(); json_t* root = authRequest(params, "https://www.okcoin.com/api/v1/borrow_money.do", signature, content); std::cout << "<OKCoin> Borrow " << amount << " BTC:\n" << json_dumps(root, 0) << std::endl; isBorrowAccepted = json_boolean_value(json_object_get(root, "result")); if (isBorrowAccepted) { borrowId = json_integer_value(json_object_get(root, "borrow_id")); } json_decref(root); return borrowId; }
static inline int device_set_boolean(setter_boolean fn, struct Device *device, json_t *value, const char *context, struct MbDeviceJsonError *error) { int ret; if (!json_is_boolean(value)) { json_error_set_mismatched_type( error, context, value->type, JSON_BOOLEAN); return -1; } ret = fn(device, json_boolean_value(value)); if (ret < 0) { json_error_set_standard_error(error, ret); return -1; } return 0; }
// gets a json value from a key int json_object_get_bool(json_t *object, char *key, int **value) { int *value_return = NULL; int exit_code = 0; check_not_null(object); check_not_null(key); check_not_null(value); json_t *json_boolean_peek = json_object_get(object, key); if (json_boolean_peek == NULL) { *value = NULL; goto cleanup; } int json_typeof_result = json_typeof(json_boolean_peek); if (json_typeof_result != JSON_TRUE && json_typeof_result != JSON_FALSE) { *value = NULL; goto cleanup; } int value_peek = json_boolean_value(json_boolean_peek); check_result(malloc_memcpy_int(&value_return, &value_peek), 0); *value = value_return; goto cleanup; error: if (value_return != NULL) { free(value_return); } exit_code = -1; cleanup: return exit_code; }
static void buf_appendjson(struct buf *buf, json_t *jvalue) { switch (json_typeof(jvalue)) { case JSON_ARRAY: { size_t i, n = json_array_size(jvalue); const char *sep = ""; for (i = 0; i < n; i++, sep = ",") { buf_appendcstr(buf, sep); buf_appendjson(buf, json_array_get(jvalue, i)); } break; } case JSON_STRING: buf_appendcstr(buf, json_string_value(jvalue)); break; case JSON_INTEGER: buf_printf(buf, "%" JSON_INTEGER_FORMAT, json_integer_value(jvalue)); break; case JSON_REAL: buf_printf(buf, "%f", json_real_value(jvalue)); break; case JSON_TRUE: case JSON_FALSE: buf_printf(buf, "%d", json_boolean_value(jvalue)); break; default: /* Shouldn't get here - ignore object */ break; } }
int broker_start_server(json_t *config) { json_incref(config); const char *httpHost = NULL; char httpPort[8]; memset(httpPort, 0, sizeof(httpPort)); { json_t *http = json_object_get(config, "http"); if (http) { json_t *enabled = json_object_get(http, "enabled"); if (!(enabled && json_boolean_value(enabled))) { json_decref(config); return 0; } httpHost = json_string_value(json_object_get(http, "host")); json_t *jsonPort = json_object_get(http, "port"); if (jsonPort) { json_int_t p = json_integer_value(jsonPort); int len = snprintf(httpPort, sizeof(httpPort) - 1, "%" JSON_INTEGER_FORMAT, p); httpPort[len] = '\0'; } } } int httpActive = 0; Server httpServer; uv_poll_t httpPoll; if (httpHost && httpPort[0] != '\0') { mbedtls_net_init(&httpServer.srv); httpServer.data_ready = broker_on_data_callback; httpActive = start_http_server(&httpServer, httpHost, httpPort, mainLoop, &httpPoll); } uv_signal_t sigInt; uv_signal_init(mainLoop, &sigInt); uv_signal_start(&sigInt, stop_server_handler, SIGINT); uv_signal_t sigTerm; uv_signal_init(mainLoop, &sigTerm); uv_signal_start(&sigTerm, stop_server_handler, SIGTERM); // upstream_connect_conn(&loop, "http://10.0.1.158:8080/conn", "dartbroker", "cbroker"); if (httpActive) { uv_run(mainLoop, UV_RUN_DEFAULT); } uv_signal_stop(&sigInt); uv_signal_stop(&sigTerm); if (httpActive) { uv_poll_stop(&httpPoll); } uv_loop_close(mainLoop); #if defined(__unix__) || defined(__APPLE__) if (mainLoop && mainLoop->watchers) { uv__free(mainLoop->watchers); } #endif json_decref(config); return 0; }
/* Call the simple functions not covered by other tests of the public API */ static void run_tests() { json_t *value; value = json_boolean(1); if(!json_is_true(value)) fail("json_boolean(1) failed"); json_decref(value); value = json_boolean(-123); if(!json_is_true(value)) fail("json_boolean(-123) failed"); json_decref(value); value = json_boolean(0); if(!json_is_false(value)) fail("json_boolean(0) failed"); if(json_boolean_value(value) != 0) fail("json_boolean_value failed"); json_decref(value); value = json_integer(1); if(json_typeof(value) != JSON_INTEGER) fail("json_typeof failed"); if(json_is_object(value)) fail("json_is_object failed"); if(json_is_array(value)) fail("json_is_array failed"); if(json_is_string(value)) fail("json_is_string failed"); if(!json_is_integer(value)) fail("json_is_integer failed"); if(json_is_real(value)) fail("json_is_real failed"); if(!json_is_number(value)) fail("json_is_number failed"); if(json_is_true(value)) fail("json_is_true failed"); if(json_is_false(value)) fail("json_is_false failed"); if(json_is_boolean(value)) fail("json_is_boolean failed"); if(json_is_null(value)) fail("json_is_null failed"); json_decref(value); value = json_string("foo"); if(!value) fail("json_string failed"); if(strcmp(json_string_value(value), "foo")) fail("invalid string value"); if (json_string_length(value) != 3) fail("invalid string length"); if(json_string_set(value, "barr")) fail("json_string_set failed"); if(strcmp(json_string_value(value), "barr")) fail("invalid string value"); if (json_string_length(value) != 4) fail("invalid string length"); if(json_string_setn(value, "hi\0ho", 5)) fail("json_string_set failed"); if(memcmp(json_string_value(value), "hi\0ho\0", 6)) fail("invalid string value"); if (json_string_length(value) != 5) fail("invalid string length"); json_decref(value); value = json_string(NULL); if(value) fail("json_string(NULL) failed"); /* invalid UTF-8 */ value = json_string("a\xefz"); if(value) fail("json_string(<invalid utf-8>) failed"); value = json_string_nocheck("foo"); if(!value) fail("json_string_nocheck failed"); if(strcmp(json_string_value(value), "foo")) fail("invalid string value"); if (json_string_length(value) != 3) fail("invalid string length"); if(json_string_set_nocheck(value, "barr")) fail("json_string_set_nocheck failed"); if(strcmp(json_string_value(value), "barr")) fail("invalid string value"); if (json_string_length(value) != 4) fail("invalid string length"); if(json_string_setn_nocheck(value, "hi\0ho", 5)) fail("json_string_set failed"); if(memcmp(json_string_value(value), "hi\0ho\0", 6)) fail("invalid string value"); if (json_string_length(value) != 5) fail("invalid string length"); json_decref(value); /* invalid UTF-8 */ value = json_string_nocheck("qu\xff"); if(!value) fail("json_string_nocheck failed"); if(strcmp(json_string_value(value), "qu\xff")) fail("invalid string value"); if (json_string_length(value) != 3) fail("invalid string length"); if(json_string_set_nocheck(value, "\xfd\xfe\xff")) fail("json_string_set_nocheck failed"); if(strcmp(json_string_value(value), "\xfd\xfe\xff")) fail("invalid string value"); if (json_string_length(value) != 3) fail("invalid string length"); json_decref(value); value = json_integer(123); if(!value) fail("json_integer failed"); if(json_integer_value(value) != 123) fail("invalid integer value"); if(json_number_value(value) != 123.0) fail("invalid number value"); if(json_integer_set(value, 321)) fail("json_integer_set failed"); if(json_integer_value(value) != 321) fail("invalid integer value"); if(json_number_value(value) != 321.0) fail("invalid number value"); json_decref(value); value = json_real(123.123); if(!value) fail("json_real failed"); if(json_real_value(value) != 123.123) fail("invalid integer value"); if(json_number_value(value) != 123.123) fail("invalid number value"); if(json_real_set(value, 321.321)) fail("json_real_set failed"); if(json_real_value(value) != 321.321) fail("invalid real value"); if(json_number_value(value) != 321.321) fail("invalid number value"); json_decref(value); value = json_true(); if(!value) fail("json_true failed"); json_decref(value); value = json_false(); if(!value) fail("json_false failed"); json_decref(value); value = json_null(); if(!value) fail("json_null failed"); json_decref(value); /* Test reference counting on singletons (true, false, null) */ value = json_true(); if(value->refcount != (size_t)-1) fail("refcounting true works incorrectly"); json_decref(value); if(value->refcount != (size_t)-1) fail("refcounting true works incorrectly"); json_incref(value); if(value->refcount != (size_t)-1) fail("refcounting true works incorrectly"); value = json_false(); if(value->refcount != (size_t)-1) fail("refcounting false works incorrectly"); json_decref(value); if(value->refcount != (size_t)-1) fail("refcounting false works incorrectly"); json_incref(value); if(value->refcount != (size_t)-1) fail("refcounting false works incorrectly"); value = json_null(); if(value->refcount != (size_t)-1) fail("refcounting null works incorrectly"); json_decref(value); if(value->refcount != (size_t)-1) fail("refcounting null works incorrectly"); json_incref(value); if(value->refcount != (size_t)-1) fail("refcounting null works incorrectly"); }
int main(int argc, char **argv) { // header information std::cout << "Blackbird Bitcoin Arbitrage\nVersion 0.0.2" << std::endl; std::cout << "DISCLAIMER: USE THE SOFTWARE AT YOUR OWN RISK.\n" << std::endl; // read the config file (config.json) json_error_t error; json_t *root = json_load_file("config.json", 0, &error); if (!root) { std::cout << "ERROR: config.json incorrect (" << error.text << ")\n" << std::endl; return 1; } // get config variables int gapSec = json_integer_value(json_object_get(root, "GapSec")); unsigned debugMaxIteration = json_integer_value(json_object_get(root, "DebugMaxIteration")); bool useFullCash = json_boolean_value(json_object_get(root, "UseFullCash")); double untouchedCash = json_real_value(json_object_get(root, "UntouchedCash")); double cashForTesting = json_real_value(json_object_get(root, "CashForTesting")); if (!useFullCash && cashForTesting < 15.0) { std::cout << "ERROR: Minimum test cash is $15.00.\n" << std::endl; return 1; } // function arrays getQuoteType getQuote[] = {Bitfinex::getQuote, OkCoin::getQuote, Bitstamp::getQuote, Kraken::getQuote}; getAvailType getAvail[] = {Bitfinex::getAvail, OkCoin::getAvail, Bitstamp::getAvail, Kraken::getAvail}; sendOrderType sendOrder[] = {Bitfinex::sendOrder, OkCoin::sendOrder, Bitstamp::sendOrder}; isOrderCompleteType isOrderComplete[] = {Bitfinex::isOrderComplete, OkCoin::isOrderComplete, Bitstamp::isOrderComplete}; getActivePosType getActivePos[] = {Bitfinex::getActivePos, OkCoin::getActivePos, Bitstamp::getActivePos, Kraken::getActivePos}; getLimitPriceType getLimitPrice[] = {Bitfinex::getLimitPrice, OkCoin::getLimitPrice, Bitstamp::getLimitPrice, Kraken::getLimitPrice}; // thousand separator std::locale mylocale(""); std::cout.imbue(mylocale); // print precision of two digits std::cout.precision(2); std::cout << std::fixed; // create a parameters structure Parameters params(root); params.addExchange("Bitfinex", 0.0020, true); params.addExchange("OKCoin", 0.0020, false); params.addExchange("Bitstamp", 0.0025, false); params.addExchange("Kraken", 0.0025, true); // CSV file std::string csvFileName; csvFileName = "result_" + printDateTimeFileName() + ".csv"; std::ofstream csvFile; csvFile.open(csvFileName.c_str(), std::ofstream::trunc); // CSV header csvFile << "TRADE_ID,EXCHANGE_LONG,EXHANGE_SHORT,ENTRY_TIME,EXIT_TIME,DURATION,TOTAL_EXPOSURE,BALANCE_BEFORE,BALANCE_AFTER,RETURN\n"; csvFile.flush(); // time structure time_t rawtime; rawtime = time(NULL); struct tm * timeinfo; timeinfo = localtime(&rawtime); bool inMarket = false; int resultId = 0; Result res; res.clear(); // Vector of Bitcoin std::vector<Bitcoin*> btcVec; // create Bitcoin objects for (unsigned i = 0; i < params.nbExch(); ++i) { btcVec.push_back(new Bitcoin(i, params.exchName[i], params.fees[i], params.hasShort[i])); } // cURL CURL* curl; curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); std::cout << "[ Targets ]" << std::endl; std::cout << " Spread to enter: " << params.spreadEntry * 100.0 << "%" << std::endl; std::cout << " Spread to exit: " << params.spreadExit * 100.0 << "%" << std::endl; std::cout << std::endl; // store current balances std::cout << "[ Current balances ]" << std::endl; std::vector<double> balanceUsd; std::vector<double> balanceBtc; for (unsigned i = 0; i < params.nbExch(); ++i) { balanceUsd.push_back(getAvail[i](curl, params, "usd")); balanceBtc.push_back(getAvail[i](curl, params, "btc")); } // vectors that contains balances after a completed trade std::vector<double> newBalUsd(params.nbExch(), 0.0); std::vector<double> newBalBtc(params.nbExch(), 0.0); for (unsigned i = 0; i < params.nbExch(); ++i) { std::cout << " " << params.exchName[i] << ":\t"; std::cout << balanceUsd[i] << " USD\t" << std::setprecision(6) << balanceBtc[i] << std::setprecision(2) << " BTC" << std::endl; } std::cout << std::endl; std::cout << "[ Cash exposure ]" << std::endl; if (useFullCash) { std::cout << " FULL cash used!" << std::endl; } else { std::cout << " TEST cash used\n Value: $" << cashForTesting << std::endl; } std::cout << std::endl; // wait the next gapSec seconds before starting time(&rawtime); timeinfo = localtime(&rawtime); while ((int)timeinfo->tm_sec % gapSec != 0) { sleep(0.01); time(&rawtime); timeinfo = localtime(&rawtime); } // main loop if (!params.verbose) { std::cout << "Running..." << std::endl; } unsigned currIteration = 0; bool stillRunning = true; while (stillRunning) { time_t currTime = mktime(timeinfo); time(&rawtime); // check if we are already too late if (difftime(rawtime, currTime) > 0) { std::cout << "WARNING: " << difftime(rawtime, currTime) << " second(s) too late at " << printDateTime(currTime) << std::endl; unsigned skip = (unsigned)ceil(difftime(rawtime, currTime) / gapSec); for (unsigned i = 0; i < skip; ++i) { // std::cout << " Skipped iteration " << printDateTime(currTime) << std::endl; for (unsigned e = 0; e < params.nbExch(); ++e) { btcVec[e]->addData(currTime, btcVec[e]->getLastBid(), btcVec[e]->getLastAsk(), 0.0); } // go to next iteration timeinfo->tm_sec = timeinfo->tm_sec + gapSec; currTime = mktime(timeinfo); } std::cout << std::endl; } // wait for the next iteration while (difftime(rawtime, currTime) != 0) { sleep(0.01); time(&rawtime); } if (params.verbose) { if (!inMarket) { std::cout << "[ " << printDateTime(currTime) << " ]" << std::endl; } else { std::cout << "[ " << printDateTime(currTime) << " IN MARKET: Long " << res.exchNameLong << " / Short " << res.exchNameShort << " ]" << std::endl; } } // download the exchanges prices for (unsigned e = 0; e < params.nbExch(); ++e) { double bid = getQuote[e](curl, true); double ask = getQuote[e](curl, false); // add previous price if bid or ask is 0.0 if (bid == 0.0) { bid = btcVec[e]->getLastBid(); std::cout << " WARNING: " << params.exchName[e] << " bid is null, use previous one" << std::endl; } if (ask == 0.0) { ask = btcVec[e]->getLastAsk(); std::cout << " WARNING: " << params.exchName[e] << " ask is null, use previous one" << std::endl; } if (params.verbose) { std::cout << " " << params.exchName[e] << ": \t" << bid << " / " << ask << std::endl; } btcVec[e]->addData(currTime, bid, ask, 0.0); curl_easy_reset(curl); } // load data terminated if (params.verbose) { std::cout << " ----------------------------" << std::endl; } // compute entry point if (!inMarket) { for (unsigned i = 0; i < params.nbExch(); ++i) { for (unsigned j = 0; j < params.nbExch(); ++j) { if (i != j) { if (checkEntry(btcVec[i], btcVec[j], res, params)) { // entry opportunity found // compute exposure res.exposure = std::min(balanceUsd[res.idExchLong], balanceUsd[res.idExchShort]); if (res.exposure == 0.0) { std::cout << " WARNING: Opportunity found but no cash available. Trade canceled." << std::endl; break; } if (useFullCash == false && res.exposure <= cashForTesting) { std::cout << " WARNING: Opportunity found but no enough cash. Need more than TEST cash (min. $" << cashForTesting << "). Trade canceled." << std::endl; break; } if (useFullCash) { // leave untouchedCash res.exposure -= untouchedCash * res.exposure; } else { // use test money res.exposure = cashForTesting; } // check volumes double volumeLong = res.exposure / btcVec[res.idExchLong]->getLastAsk(); double volumeShort = res.exposure / btcVec[res.idExchShort]->getLastBid(); double limPriceLong = getLimitPrice[res.idExchLong](curl, volumeLong, false); double limPriceShort = getLimitPrice[res.idExchShort](curl, volumeShort, true); if (limPriceLong - res.priceLongIn > 0.30 || res.priceShortIn - limPriceShort > 0.30) { std::cout << " WARNING: Opportunity found but not enough volume. Trade canceled." << std::endl; break; } inMarket = true; resultId++; // update result res.id = resultId; res.entryTime = currTime; res.printEntry(); res.maxSpread[res.idExchLong][res.idExchShort] = -1.0; res.minSpread[res.idExchLong][res.idExchShort] = 1.0; int longOrderId = 0; int shortOrderId = 0; // send Long order longOrderId = sendOrder[res.idExchLong](curl, params, "buy", volumeLong, btcVec[res.idExchLong]->getLastAsk()); // send Short order shortOrderId = sendOrder[res.idExchShort](curl, params, "sell", volumeShort, btcVec[res.idExchShort]->getLastBid()); // wait for the orders to be filled sleep(3.0); std::cout << "Waiting for the two orders to be filled..." << std::endl; while (!isOrderComplete[res.idExchLong](curl, params, longOrderId) || !isOrderComplete[res.idExchShort](curl, params, shortOrderId)) { sleep(3.0); } std::cout << "Done" << std::endl; longOrderId = 0; shortOrderId = 0; break; } } } if (inMarket) { break; } } if (params.verbose) { std::cout << std::endl; } } // in market, looking to exit else if (inMarket) { if (checkExit(btcVec[res.idExchLong], btcVec[res.idExchShort], res, params, currTime)) { // exit opportunity found // check current exposure std::vector<double> btcUsed; for (unsigned i = 0; i < params.nbExch(); ++i) { btcUsed.push_back(getActivePos[i](curl, params)); } // check volumes double volumeLong = btcUsed[res.idExchLong]; double volumeShort = btcUsed[res.idExchShort]; double limPriceLong = getLimitPrice[res.idExchLong](curl, volumeLong, true); double limPriceShort = getLimitPrice[res.idExchShort](curl, volumeShort, false); if (res.priceLongOut - limPriceLong > 0.30 || limPriceShort - res.priceShortOut > 0.30) { std::cout << " WARNING: Opportunity found but not enough volume. Trade canceled." << std::endl; } else { res.exitTime = currTime; res.printExit(); // send orders int longOrderId = 0; int shortOrderId = 0; std::cout << std::setprecision(6) << "BTC exposure on " << params.exchName[res.idExchLong] << ": " << volumeLong << std::setprecision(2) << std::endl; std::cout << std::setprecision(6) << "BTC exposure on " << params.exchName[res.idExchShort] << ": " << volumeShort << std::setprecision(2) << std::endl; std::cout << std::endl; // Close Long longOrderId = sendOrder[res.idExchLong](curl, params, "sell", fabs(btcUsed[res.idExchLong]), btcVec[res.idExchLong]->getLastBid()); // Close Short shortOrderId = sendOrder[res.idExchShort](curl, params, "buy", fabs(btcUsed[res.idExchShort]), btcVec[res.idExchShort]->getLastAsk()); // wait for the orders to be filled sleep(3.0); std::cout << "Waiting for the two orders to be filled..." << std::endl; while (!isOrderComplete[res.idExchLong](curl, params, longOrderId) || !isOrderComplete[res.idExchShort](curl, params, shortOrderId)) { sleep(3.0); } std::cout << "Done\n" << std::endl; longOrderId = 0; shortOrderId = 0; // market exited inMarket = false; // new balances for (unsigned i = 0; i < params.nbExch(); ++i) { newBalUsd[i] = getAvail[i](curl, params, "usd"); newBalBtc[i] = getAvail[i](curl, params, "btc"); } for (unsigned i = 0; i < params.nbExch(); ++i) { std::cout << "New balance on " << params.exchName[i] << ": \t"; std::cout << newBalUsd[i] << " USD (perf $" << newBalUsd[i] - balanceUsd[i] << "), "; std::cout << std::setprecision(6) << newBalBtc[i] << std::setprecision(2) << " BTC" << std::endl; } std::cout << std::endl; // update res with total balance res.befBalUsd = std::accumulate(balanceUsd.begin(), balanceUsd.end(), 0.0); res.aftBalUsd = std::accumulate(newBalUsd.begin(), newBalUsd.end(), 0.0); // update current balances with new values for (unsigned i = 0; i < params.nbExch(); ++i) { balanceUsd[i] = newBalUsd[i]; balanceBtc[i] = newBalBtc[i]; } // display performance std::cout << "ACTUAL PERFORMANCE: " << "$" << res.aftBalUsd - res.befBalUsd << " (" << res.totPerf() * 100.0 << "%)\n" << std::endl; // new csv line with result csvFile << res.id << "," << res.exchNameLong << "," << res.exchNameShort << "," << printDateTimeCsv(res.entryTime) << "," << printDateTimeCsv(res.exitTime); csvFile << "," << res.getLength() << "," << res.exposure * 2.0 << "," << res.befBalUsd << "," << res.aftBalUsd << "," << res.totPerf() << "\n"; csvFile.flush(); // send email if (params.sendEmail) { sendEmail(res, params); std::cout << "Email sent" << std::endl; } // delete result information res.clear(); // if "stop_after_exit" file exists then return std::ifstream infile("stop_after_exit"); if (infile.good()) { std::cout << "Exit after last trade (file stop_after_exit found)" << std::endl; stillRunning = false; } } } if (params.verbose) { std::cout << std::endl; } } // activities for this iteration terminated timeinfo->tm_sec = timeinfo->tm_sec + gapSec; currIteration++; if (currIteration >= debugMaxIteration) { std::cout << "Max iteration reached (" << debugMaxIteration << ")" <<std::endl; stillRunning = false; } } // delete Bitcoin objects for (unsigned i = 0; i < params.nbExch(); ++i) { delete(btcVec[i]); } json_decref(root); // close cURL curl_easy_cleanup(curl); curl_global_cleanup(); // close csv file csvFile.close(); return 0; }
static void twitch_parse_followers() { struct AudienceMember { const char *name; bool isFollower; bool isInChat; bool isMod; bool exists; bool shouldTrack; }; std::vector<AudienceMember> members; http_json_response *jsonResponse = _twitchJsonResponse; if (json_is_array(jsonResponse->root)) { int audienceCount = json_array_size(jsonResponse->root); for (int i = 0; i < audienceCount; i++) { json_t *audienceMember = json_array_get(jsonResponse->root, i); if (!json_is_object(audienceMember)) continue; json_t *name = json_object_get(audienceMember, "name"); json_t *isFollower = json_object_get(audienceMember, "isFollower"); json_t *isInChat = json_object_get(audienceMember, "inChat"); json_t *isMod = json_object_get(audienceMember, "isMod"); AudienceMember member; member.name = json_string_value(name); member.isFollower = json_boolean_value(isFollower); member.isInChat = json_boolean_value(isInChat); member.isMod = json_boolean_value(isMod); member.exists = false; member.shouldTrack = false; if (member.name == NULL || member.name[0] == 0) continue; if (member.isInChat && gConfigTwitch.enable_chat_peep_tracking) member.shouldTrack = true; else if (member.isFollower && gConfigTwitch.enable_follower_peep_tracking) member.shouldTrack = true; if (gConfigTwitch.enable_chat_peep_names && member.isInChat) members.push_back(member); else if (gConfigTwitch.enable_follower_peep_names && member.isFollower) members.push_back(member); } uint16 spriteIndex; rct_peep *peep; char buffer[256]; // Check what followers are already in the park FOR_ALL_GUESTS(spriteIndex, peep) { if (is_user_string_id(peep->name_string_idx)) { format_string(buffer, peep->name_string_idx, NULL); AudienceMember *member = NULL; for (size_t i = 0; i < members.size(); i++) { if (_strcmpi(buffer, members[i].name) == 0) { member = &members[i]; members[i].exists = true; break; } } if (peep->peep_flags & PEEP_FLAGS_TWITCH) { if (member == NULL) { // Member no longer peep name worthy peep->peep_flags &= ~(PEEP_FLAGS_TRACKING | PEEP_FLAGS_TWITCH); // TODO set peep name back to number / real name } else { if (member->shouldTrack) peep->peep_flags |= (PEEP_FLAGS_TRACKING); else if (!member->shouldTrack) peep->peep_flags &= ~(PEEP_FLAGS_TRACKING); } } else if (member != NULL && !(peep->peep_flags & PEEP_FLAGS_LEAVING_PARK)) { // Peep with same name already exists but not twitch peep->peep_flags |= PEEP_FLAGS_TWITCH; if (member->shouldTrack) peep->peep_flags |= PEEP_FLAGS_TRACKING; } } } // Rename non-named peeps to followers that aren't currently in the park. if (members.size() > 0) { int memberIndex = -1; FOR_ALL_GUESTS(spriteIndex, peep) { int originalMemberIndex = memberIndex; for (size_t i = memberIndex + 1; i < members.size(); i++) { if (!members[i].exists) { memberIndex = i; break; } } if (originalMemberIndex == memberIndex) break; AudienceMember *member = &members[memberIndex]; if (!is_user_string_id(peep->name_string_idx) && !(peep->peep_flags & PEEP_FLAGS_LEAVING_PARK)) { // Rename peep and add flags rct_string_id newStringId = user_string_allocate(4, member->name); if (newStringId != 0) { peep->name_string_idx = newStringId; peep->peep_flags |= PEEP_FLAGS_TWITCH; if (member->shouldTrack) peep->peep_flags |= PEEP_FLAGS_TRACKING; } } else { // Peep still yet to be found for member memberIndex--; } }
json_t *broker_handshake_handle_conn(Broker *broker, const char *dsId, const char *token, json_t *handshake) { if (dslink_map_contains(&broker->client_connecting, (void *) dsId)) { ref_t *ref = dslink_map_remove_get(&broker->client_connecting, (void *) dsId); RemoteDSLink *link = ref->data; dslink_map_remove(&broker->client_connecting, (void *) link->name); broker_remote_dslink_free(link); dslink_free(link); dslink_decref(ref); } RemoteDSLink *link = dslink_calloc(1, sizeof(RemoteDSLink)); json_t *resp = json_object(); if (!(link && resp)) { goto fail; } if (broker_remote_dslink_init(link) != 0) { goto fail; } link->broker = broker; link->auth = dslink_calloc(1, sizeof(RemoteAuth)); if (!link->auth) { goto fail; } if (dslink_handshake_generate_key_pair(&link->auth->tempKey) != 0) { log_err("Failed to create temporary key for DSLink\n"); goto fail; } { json_t *jsonPubKey = json_object_get(handshake, "publicKey"); if (!jsonPubKey) { goto fail; } const char *tmp = json_string_value(jsonPubKey); if (!tmp) { goto fail; } tmp = dslink_strdup(tmp); if (!tmp) { goto fail; } link->auth->pubKey = tmp; } char tempKey[90]; size_t tempKeyLen = 0; if (dslink_handshake_encode_pub_key(&link->auth->tempKey, tempKey, sizeof(tempKey), &tempKeyLen) != 0) { goto fail; } if (generate_salt((unsigned char *) link->auth->salt, sizeof(link->auth->salt)) != 0) { goto fail; } json_object_set_new_nocheck(resp, "wsUri", json_string_nocheck("/ws")); json_object_set_new_nocheck(resp, "tempKey", json_string_nocheck(tempKey)); json_object_set_new_nocheck(resp, "salt", json_string_nocheck(link->auth->salt)); if (json_boolean_value(json_object_get(handshake, "isResponder"))) { link->isResponder = 1; } if (json_boolean_value(json_object_get(handshake, "isRequester"))) { link->isRequester = 1; } json_t *linkData = json_object_get(handshake, "linkData"); if (json_is_object(linkData)) { json_incref(linkData); link->linkData = linkData; } { char buf[512] = {0}; snprintf(buf, sizeof(buf), "/downstream/"); char *name = buf + sizeof("/downstream/")-1; size_t dsIdLen = strlen(dsId); if (dsIdLen < 44) { goto fail; } size_t nameLen = dsIdLen - 43; if (dsId[nameLen - 1] == '-') { nameLen--; } int nodeExists = 0; // find a valid name from broker->client_names memcpy(name, dsId, nameLen); while (1) { ref_t *ref = dslink_map_get(&broker->client_connecting, name); if (ref) { RemoteDSLink *l = ref->data; if (l && l->dsId && strcmp(l->dsId->data, dsId) == 0) { dslink_map_remove(&broker->client_connecting, name); broker_remote_dslink_free(l); break; } else { name[nameLen] = dsId[nameLen]; nameLen++; } } ref = dslink_map_get(broker->downstream->children, (void *) name); if (ref == NULL) { break; } if (!((DownstreamNode *) ref->data)->dsId || strcmp(dsId, ((DownstreamNode *) ref->data)->dsId->data) == 0) { nodeExists = 1; break; } name[nameLen] = dsId[nameLen]; nameLen++; } if (!nodeExists && broker_enable_token) { if (!token) { log_err("Failed to connet, need token\n"); goto fail; } BrokerNode* tokenNode = get_token_node(token, dsId); if (tokenNode) { DownstreamNode *node = broker_init_downstream_node(broker->downstream, name); if (json_is_true(json_object_get(node->meta, "$$managed"))) { json_object_set_new_nocheck(node->meta, "$$token", json_string_nocheck(tokenNode->name)); } node->dsId = dslink_str_ref(dsId); if (broker->downstream->list_stream) { update_list_child(broker->downstream, broker->downstream->list_stream, link->name); } json_t *group = json_object_get(tokenNode->meta, "$$group"); if (json_is_string(group)) { json_object_set_nocheck(node->meta, "$$group", group); } token_used(tokenNode); broker_downstream_nodes_changed(broker); } else { log_err("Invalid token: %s\n", token); goto fail; } } json_object_set_new_nocheck(resp, "path", json_string_nocheck(buf)); link->path = dslink_strdup(buf); if (!link->path) { goto fail; } link->name = link->path + sizeof("/downstream/") - 1; // add to connecting map with the name if (dslink_map_set(&broker->client_connecting, dslink_ref((void *) link->name, NULL), dslink_ref(link, NULL)) != 0) { dslink_free((void *) link->path); goto fail; } } { ref_t *tmp = dslink_ref(dslink_strdup(dsId), dslink_free); if (!tmp) { goto fail; } // add to connecting map with dsId if (dslink_map_set(&broker->client_connecting, tmp, dslink_ref(link, NULL)) != 0) { dslink_free(tmp); goto fail; } } return resp; fail: if (link) { broker_remote_dslink_free(link); dslink_free((void *) link->path); dslink_free(link); } DSLINK_CHECKED_EXEC(json_decref, resp); return NULL; }
vita_imports_t *vita_imports_loads(FILE *text, int verbose) { json_t *libs, *lib_data; json_error_t error; const char *lib_name, *mod_name, *target_name; libs = json_loadf(text, 0, &error); if (libs == NULL) { fprintf(stderr, "error: on line %d: %s\n", error.line, error.text); return NULL; } if (!json_is_object(libs)) { fprintf(stderr, "error: modules is not an object\n"); json_decref(libs); return NULL; } vita_imports_t *imports = vita_imports_new(json_object_size(libs)); int i, j, k; i = -1; json_object_foreach(libs, lib_name, lib_data) { json_t *nid, *modules, *mod_data; i++; if (!json_is_object(lib_data)) { fprintf(stderr, "error: library %s is not an object\n", lib_name); json_decref(libs); return NULL; } nid = json_object_get(lib_data, "nid"); if (!json_is_integer(nid)) { fprintf(stderr, "error: library %s: nid is not an integer\n", lib_name); json_decref(libs); return NULL; } modules = json_object_get(lib_data, "modules"); if (!json_is_object(modules)) { fprintf(stderr, "error: library %s: module is not an object\n", lib_name); json_decref(libs); return NULL; } imports->libs[i] = vita_imports_lib_new( lib_name, json_integer_value(nid), json_object_size(modules)); if (verbose) printf("Lib: %s\n", lib_name); j = -1; json_object_foreach(modules, mod_name, mod_data) { json_t *nid, *kernel, *functions, *variables, *target_nid; int has_variables = 1; j++; if (!json_is_object(mod_data)) { fprintf(stderr, "error: module %s is not an object\n", mod_name); json_decref(libs); return NULL; } nid = json_object_get(mod_data, "nid"); if (!json_is_integer(nid)) { fprintf(stderr, "error: module %s: nid is not an integer\n", mod_name); json_decref(libs); return NULL; } kernel = json_object_get(mod_data, "kernel"); if (!json_is_boolean(kernel)) { fprintf(stderr, "error: module %s: kernel is not a boolean\n", mod_name); json_decref(libs); return NULL; } functions = json_object_get(mod_data, "functions"); if (!json_is_object(functions)) { fprintf(stderr, "error: module %s: functions is not an array\n", mod_name); json_decref(libs); return NULL; } variables = json_object_get(mod_data, "variables"); if (variables == NULL) { has_variables = 0; } if (has_variables && !json_is_object(variables)) { fprintf(stderr, "error: module %s: variables is not an array\n", mod_name); json_decref(libs); return NULL; } if (verbose) printf("\tModule: %s\n", mod_name); imports->libs[i]->modules[j] = vita_imports_module_new( mod_name, json_boolean_value(kernel), json_integer_value(nid), json_object_size(functions), json_object_size(variables)); k = -1; json_object_foreach(functions, target_name, target_nid) { k++; if (!json_is_integer(target_nid)) { fprintf(stderr, "error: function %s: nid is not an integer\n", target_name); json_decref(libs); return NULL; } if (verbose) printf("\t\tFunction: %s\n", target_name); imports->libs[i]->modules[j]->functions[k] = vita_imports_stub_new( target_name, json_integer_value(target_nid)); }