diff --git a/Makefile b/Makefile index a04311d32..30c3e52a0 100644 --- a/Makefile +++ b/Makefile @@ -12,20 +12,18 @@ V_CURL := 7.55.1 V_NCUR := 6.0 V_JSON := v2.1.1 V_UWS := 0.14.4 -V_UV := 1.15.0 V_SQL := 3200100 V_QF := v.1.14.4 V_PVS := 6.19.23789.1731 -KZIP = 3916a5af67afc112c8c273c24c7b5842af2b40ed +KZIP = 0b57ac8dc50c7fe025e6a8418e6e300d2677e668 KARGS = -Wextra -std=c++11 -O3 -I$(KLOCAL)/include \ - src/server/K.cxx -pthread -rdynamic -DUSE_LIBUV \ + src/server/K.cxx -pthread -rdynamic -DUWS_THREADSAFE \ -DK_STAMP='"$(shell date --rfc-3339=seconds | cut -f1 -d+)"' \ -DK_BUILD='"$(CHOST)"' $(KLOCAL)/include/uWS/*.cpp \ $(KLOCAL)/lib/K-$(CHOST).a $(KLOCAL)/lib/libquickfix.a \ $(KLOCAL)/lib/libsqlite3.a $(KLOCAL)/lib/libz.a \ $(KLOCAL)/lib/libcurl.a $(KLOCAL)/lib/libssl.a \ - $(KLOCAL)/lib/libcrypto.a $(KLOCAL)/lib/libncurses.a \ - $(KLOCAL)/lib/libuv.a -ldl + $(KLOCAL)/lib/libcrypto.a $(KLOCAL)/lib/libncurses.a -ldl all: K @@ -70,7 +68,6 @@ help: # make pvs - download pvs src files # # make zlib - download zlib src files # # make curl - download curl src files # - # make libuv - download libuv src files # # make ncurses - download ncurses src files # # make sqlite - download sqlite src files # # make openssl - download openssl src files # @@ -98,7 +95,7 @@ ifdef KALL unset KALL && echo -n $(CARCH) | xargs -I % -d ' ' $(MAKE) CHOST=% $@ else mkdir -p build-$(CHOST) - CHOST=$(CHOST) $(MAKE) zlib openssl curl sqlite ncurses libuv json uws quickfix + CHOST=$(CHOST) $(MAKE) zlib openssl curl sqlite ncurses json uws quickfix test -f /sbin/ldconfig && sudo ldconfig || : endif @@ -150,12 +147,6 @@ ncurses: build-$(CHOST) --prefix=$(PWD)/$(KLOCAL) --with-fallbacks=linux,screen,vt100,xterm,xterm-256color,putty-256color \ && make && make install ) -libuv: build-$(CHOST) - test -d build-$(CHOST)/libuv-$(V_UV) || ( \ - curl -L https://github.com/libuv/libuv/archive/v$(V_UV).tar.gz | tar xz -C build-$(CHOST) \ - && cd build-$(CHOST)/libuv-$(V_UV) && sh autogen.sh && CC=$(CC) ./configure --host=$(CHOST) \ - --prefix=$(PWD)/$(KLOCAL) && make && make install ) - json: build-$(CHOST) test -f $(KLOCAL)/include/json.h || (mkdir -p $(KLOCAL)/include \ && curl -L https://github.com/nlohmann/json/releases/download/$(V_JSON)/json.hpp \ @@ -195,7 +186,7 @@ cleandb: /data/db/K* packages: test -n "`command -v apt-get`" && sudo apt-get -y install g++ build-essential automake autoconf libtool libxml2 libxml2-dev zlib1g-dev openssl stunnel python curl gzip imagemagick screen \ || (test -n "`command -v yum`" && sudo yum -y install gcc-c++ automake autoconf libtool libxml2 libxml2-devel openssl stunnel python curl gzip ImageMagick screen) \ - || (test -n "`command -v brew`" && (xcode-select --install || :) && (brew install automake autoconf libxml2 sqlite openssl zlib libuv stunnel python curl gzip imagemagick || brew upgrade || :)) \ + || (test -n "`command -v brew`" && (xcode-select --install || :) && (brew install automake autoconf libxml2 sqlite openssl zlib stunnel python curl gzip imagemagick || brew upgrade || :)) \ || (test -n "`command -v pacman`" && sudo pacman --noconfirm -S --needed base-devel libxml2 zlib sqlite curl libcurl-compat openssl stunnel python gzip imagemagick screen) sudo mkdir -p /data/db/ sudo chown $(shell id -u) /data/db @@ -362,4 +353,4 @@ md5: src asandwich: @test `whoami` = 'root' && echo OK || echo make it yourself! -.PHONY: K dist link Linux Darwin build zlib openssl curl ncurses libuv quickfix uws json pvs clean cleandb list screen start stop restart startall stopall restartall gdax packages install docker travis reinstall client www bundle diff latest changelog test test-cov send-cov png png-check release md5 asandwich +.PHONY: K dist link Linux Darwin build zlib openssl curl ncurses quickfix uws json pvs clean cleandb list screen start stop restart startall stopall restartall gdax packages install docker travis reinstall client www bundle diff latest changelog test test-cov send-cov png png-check release md5 asandwich diff --git a/README.md b/README.md index ce78e5d8d..d856f0338 100644 --- a/README.md +++ b/README.md @@ -375,8 +375,6 @@ or donate your time with programming or financial suggestions in the topical IRC - https://github.com/michaelgrosner/tribeca (https://github.com/michaelgrosner) - https://www.sqlite.org - https://github.com/michaelgrosner/tribeca (https://github.com/michaelgrosner) -- http://libuv.org -- https://github.com/michaelgrosner/tribeca (https://github.com/michaelgrosner) ### Help diff --git a/src/client/models.ts b/src/client/models.ts index 28211beb1..3ab53e824 100644 --- a/src/client/models.ts +++ b/src/client/models.ts @@ -185,16 +185,16 @@ export enum SOP { Off, Trades, Size, TradesSize } export enum STDEV { Off, OnFV, OnFVAPROff, OnTops, OnTopsAPROff, OnTop, OnTopAPROff } export interface QuotingParameters { - widthPing?: number; + widthPing?: any; widthPingPercentage?: number; - widthPong?: number; + widthPong?: any; widthPongPercentage?: number; widthPercentage?: boolean; bestWidth?: boolean; - buySize?: number; + buySize?: any; buySizePercentage?: number; buySizeMax?: boolean; - sellSize?: number; + sellSize?: any; sellSizePercentage?: number; sellSizeMax?: boolean; pingAt?: PingAt; diff --git a/src/client/pair.ts b/src/client/pair.ts index 837de9216..c6936fc35 100644 --- a/src/client/pair.ts +++ b/src/client/pair.ts @@ -25,11 +25,16 @@ class FormViewModel { this.display = JSON.parse(JSON.stringify(defaultParameter)); } + public cleanDecimal = (p: T) => { + return p; + } + public reset = () => { this.display = JSON.parse(JSON.stringify(this.master)); }; public update = (p: T) => { + p = this.cleanDecimal(p); this.master = JSON.parse(JSON.stringify(p)); this.display = JSON.parse(JSON.stringify(p)); this.pending = false; @@ -70,7 +75,13 @@ class DisplayQuotingParameters extends FormViewModel { constructor(sub: Subscribe.ISubscribe, fire: Subscribe.IFire) { - super({}, sub, fire); + super({}, sub, fire, (d: any) => { + d.widthPing = parseFloat(d.widthPing); + d.widthPong = parseFloat(d.widthPong); + d.buySize = parseFloat(d.buySize); + d.sellSize = parseFloat(d.sellSize); + return d; + }); this.availableQuotingModes = DisplayQuotingParameters.getMapping(Models.QuotingMode); this.availableQuotingSafeties = DisplayQuotingParameters.getMapping(Models.QuotingSafety); @@ -84,6 +95,14 @@ class DisplayQuotingParameters extends FormViewModel { this.availableSTDEV = DisplayQuotingParameters.getMapping(Models.STDEV); } + public cleanDecimal = (d: any) => { + d.widthPing = parseFloat(d.widthPing).toFixed(13).replace(/0+$/,'').replace(/\.$/,''); + d.widthPong = parseFloat(d.widthPong).toFixed(13).replace(/0+$/,'').replace(/\.$/,''); + d.buySize = parseFloat(d.buySize).toFixed(13).replace(/0+$/,'').replace(/\.$/,''); + d.sellSize = parseFloat(d.sellSize).toFixed(13).replace(/0+$/,'').replace(/\.$/,''); + return d; + } + private static getMapping(enumObject: T) { let names = []; for (let mem in enumObject) { diff --git a/src/server/K.cxx b/src/server/K.cxx index ca4b09f0c..7713b477a 100644 --- a/src/server/K.cxx +++ b/src/server/K.cxx @@ -21,7 +21,6 @@ using namespace std; -#include "uv.h" #include "json.h" #include "sqlite3.h" #include "uWS/uWS.h" diff --git a/src/server/ev.h b/src/server/ev.h index fdc7e5bc8..b29fdbc3c 100644 --- a/src/server/ev.h +++ b/src/server/ev.h @@ -5,15 +5,13 @@ namespace K { class EV: public Klass { private: uWS::Hub *hub = nullptr; - int eCode = EXIT_FAILURE; public: - mutex hubMutex; uWS::Group *uiGroup = nullptr; - uv_timer_t *tCalcs = nullptr, - *tStart = nullptr, - *tDelay = nullptr, - *tWallet = nullptr, - *tCancel = nullptr; + Timer *tCalcs = nullptr, + *tStart = nullptr, + *tDelay = nullptr, + *tWallet = nullptr, + *tCancel = nullptr; function ogOrder; function ogTrade; function mgLevels, @@ -32,14 +30,13 @@ namespace K { gw->hub = hub = new uWS::Hub(0, true); }; void waitTime() { - uv_timer_init(hub->getLoop(), tCalcs = new uv_timer_t()); - uv_timer_init(hub->getLoop(), tStart = new uv_timer_t()); - uv_timer_init(hub->getLoop(), tDelay = new uv_timer_t()); - uv_timer_init(hub->getLoop(), tWallet = new uv_timer_t()); - uv_timer_init(hub->getLoop(), tCancel = new uv_timer_t()); + tCalcs = new Timer(hub->getLoop()); + tStart = new Timer(hub->getLoop()); + tDelay = new Timer(hub->getLoop()); + tWallet = new Timer(hub->getLoop()); + tCancel = new Timer(hub->getLoop()); }; void waitData() { - gw->hubMutex = &hubMutex; gw->gwGroup = hub->createGroup(); }; void waitUser() { @@ -57,23 +54,17 @@ namespace K { public: void start() { hub->run(); - halt(eCode); }; void stop(int code, function gwCancelAll) { - eCode = code; - if (uv_loop_alive(hub->getLoop())) { - uv_timer_stop(tCancel); - uv_timer_stop(tWallet); - uv_timer_stop(tCalcs); - uv_timer_stop(tStart); - uv_timer_stop(tDelay); - gw->close(); - gw->gwGroup->close(); - gwCancelAll(); - uiGroup->close(); - FN::close(hub->getLoop()); - hub->getLoop()->destroy(); - } + tCancel->stop(); + tWallet->stop(); + tCalcs->stop(); + tStart->stop(); + tDelay->stop(); + gw->close(); + gw->gwGroup->close(); + gwCancelAll(); + uiGroup->close(); halt(code); }; void listen(int port) { @@ -97,7 +88,7 @@ namespace K { cout << FN::uiT(); for(unsigned int i = 0; i < 21; ++i) cout << "THE END IS NEVER "; - cout << "THE END" << '\n'; + cout << "THE END." << '\n'; halt(code); }; static void quit(int sig) { @@ -105,7 +96,7 @@ namespace K { cout << '\n'; json k = FN::wJet("https://api.icndb.com/jokes/random?escape=javascript&limitTo=[nerdy]"); cout << FN::uiT() << "Excellent decision! " - << ((k.is_null() || !k["/value/joke"_json_pointer].is_string()) + << ((k.is_null() or !k["/value/joke"_json_pointer].is_string()) ? "let's plant a tree instead.." : k["/value/joke"_json_pointer].get() ) << '\n'; (*evExit)(EXIT_SUCCESS); diff --git a/src/server/fn.h b/src/server/fn.h index da628187f..48cd32be7 100644 --- a/src/server/fn.h +++ b/src/server/fn.h @@ -652,7 +652,7 @@ namespace K { signal(SIGWINCH, screen_resize); thread([&]() { int ch; - while ((ch = wgetch(wBorder)) != 'q') { + while ((ch = wgetch(wBorder)) != 'q' and ch != 'Q') { switch (ch) { case ERR: continue; // case KEY_PPAGE: wscrl(wLog, -3); wrefresh(wLog); break; @@ -768,14 +768,6 @@ namespace K { redrawwin(wLog); wrefresh(wLog); }; - static void close(uv_loop_t* loop) { - uv_walk(loop, close_walk_cb, NULL); - uv_run(loop, UV_RUN_DEFAULT); - }; - static void close_walk_cb(uv_handle_t* handle, void* arg) { - if (!uv_is_closing(handle)) - uv_close(handle, NULL); - }; }; class B64 { public: diff --git a/src/server/gw.h b/src/server/gw.h index 1fcf4c750..701ca7a46 100644 --- a/src/server/gw.h +++ b/src/server/gw.h @@ -16,14 +16,14 @@ namespace K { handshake(gw->exchange); }; void waitTime() { - ((EV*)events)->tWallet->data = (void*)this; - uv_timer_start(((EV*)events)->tWallet, [](uv_timer_t *handle) { + ((EV*)events)->tWallet->setData(this); + ((EV*)events)->tWallet->start([](Timer *handle) { GW *k = (GW*)handle->data; if (((CF*)k->config)->argDebugEvents) FN::log("DEBUG", "EV GW tWallet timer"); k->gw->wallet(); }, 0, 15e+3); - ((EV*)events)->tCancel->data = (void*)this; - uv_timer_start(((EV*)events)->tCancel, [](uv_timer_t *handle) { + ((EV*)events)->tCancel->setData(this); + ((EV*)events)->tCancel->start([](Timer *handle) { GW *k = (GW*)handle->data; if (((CF*)k->config)->argDebugEvents) FN::log("DEBUG", "EV GW tCancel timer"); if (k->qp->cancelOrdersAuto) @@ -135,7 +135,7 @@ namespace K { string _price_ = price_.str(); for (string::iterator it=_price_.begin(); it!=_price_.end();) if (*it == '+' or *it == '-') break; else it = _price_.erase(it); - stringstream os(string("1e").append(to_string(stod(_price_)-4))); + stringstream os(string("1e").append(to_string(fmax(stod(_price_),-4)-4))); os >> gw->minTick; } k = FN::wJet(string(gw->http).append("/symbols_details")); diff --git a/src/server/km.h b/src/server/km.h index 1631ae003..124f01ab8 100644 --- a/src/server/km.h +++ b/src/server/km.h @@ -389,6 +389,21 @@ namespace K { mOrder(string o, mExchange e, mPair P, mSide S, double q, mOrderType t, bool i, double p, mTimeInForce F, mORS s, bool O): orderId(o), exchangeId(""), exchange(e), pair(P), side(S), quantity(q), type(t), isPong(i), price(p), timeInForce(F), orderStatus(s), preferPostOnly(O), lastQuantity(0), time(0), computationalLatency(0) {}; + string quantity2str() { + stringstream ss; + ss << setprecision(8) << fixed << quantity; + return ss.str(); + }; + string lastQuantity2str() { + stringstream ss; + ss << setprecision(8) << fixed << lastQuantity; + return ss.str(); + }; + string price2str() { + stringstream ss; + ss << setprecision(8) << fixed << price; + return ss.str(); + }; }; static void to_json(json& j, const mOrder& k) { j = { @@ -508,7 +523,6 @@ namespace K { function evDataLevels; function evConnectOrder, evConnectMarket; - mutex *hubMutex = nullptr; uWS::Hub *hub = nullptr; uWS::Group *gwGroup = nullptr; mExchange exchange = mExchange::Null; @@ -523,7 +537,7 @@ namespace K { virtual string A() = 0; virtual void wallet() = 0, levels() = 0, - send(string oI, mSide oS, double oP, double oQ, mOrderType oLM, mTimeInForce oTIF, bool oPO, unsigned long oT) = 0, + send(string oI, mSide oS, string oP, string oQ, mOrderType oLM, mTimeInForce oTIF, bool oPO, unsigned long oT) = 0, cancel(string oI, string oE, mSide oS, unsigned long oT) = 0, cancelAll() = 0, close() = 0; diff --git a/src/server/og.h b/src/server/og.h index fedf9e8c0..1f0ee5129 100644 --- a/src/server/og.h +++ b/src/server/og.h @@ -36,7 +36,7 @@ namespace K { void waitData() { gw->evDataOrder = [&](mOrder k) { if (((CF*)config)->argDebugEvents) FN::log("DEBUG", "EV OG evDataOrder"); - if (((CF*)config)->argDebugOrders) FN::log("DEBUG", string("OG reply ") + k.orderId + "::" + k.exchangeId + " [" + to_string((int)k.orderStatus) + "]: " + to_string(k.quantity) + "/" + to_string(k.lastQuantity) + " at price " + to_string(k.price)); + if (((CF*)config)->argDebugOrders) FN::log("DEBUG", string("OG reply ") + k.orderId + "::" + k.exchangeId + " [" + to_string((int)k.orderStatus) + "]: " + k.quantity2str() + "/" + k.lastQuantity2str() + " at price " + k.price2str()); updateOrderState(k); }; }; @@ -53,8 +53,8 @@ namespace K { public: void sendOrder(mSide oS, double oP, double oQ, mOrderType oLM, mTimeInForce oTIF, bool oIP, bool oPO) { mOrder o = updateOrderState(mOrder(gw->randId(), gw->exchange, mPair(gw->base, gw->quote), oS, oQ, oLM, oIP, FN::roundSide(oP, gw->minTick, oS), oTIF, mORS::New, oPO)); - if (((CF*)config)->argDebugOrders) FN::log("DEBUG", string("OG send ") + (o.side == mSide::Bid ? "BID id " : "ASK id ") + o.orderId + ": " + to_string(o.quantity) + " " + o.pair.base + " at price " + to_string(o.price) + " " + o.pair.quote); - gw->send(o.orderId, o.side, o.price, o.quantity, o.type, o.timeInForce, o.preferPostOnly, o.time); + if (((CF*)config)->argDebugOrders) FN::log("DEBUG", string("OG send ") + (o.side == mSide::Bid ? "BID id " : "ASK id ") + o.orderId + ": " + o.quantity2str() + " " + o.pair.base + " at price " + o.price2str() + " " + o.pair.quote); + gw->send(o.orderId, o.side, o.price2str(), o.quantity2str(), o.type, o.timeInForce, o.preferPostOnly, o.time); ++((UI*)client)->orders60sec; }; void cancelOrder(string k) { @@ -334,7 +334,7 @@ namespace K { allOrdersIds[k.exchangeId] = k.orderId; allOrders[k.orderId] = k; ogMutex.unlock(); - if (((CF*)config)->argDebugOrders) FN::log("DEBUG", string("OG save ") + (k.side == mSide::Bid ? "BID id " : "ASK id ") + k.orderId + "::" + k.exchangeId + " [" + to_string((int)k.orderStatus) + "]: " + to_string(k.quantity) + " " + k.pair.base + " at price " + to_string(k.price) + " " + k.pair.quote); + if (((CF*)config)->argDebugOrders) FN::log("DEBUG", string("OG save ") + (k.side == mSide::Bid ? "BID id " : "ASK id ") + k.orderId + "::" + k.exchangeId + " [" + to_string((int)k.orderStatus) + "]: " + k.quantity2str() + " " + k.pair.base + " at price " + k.price2str() + " " + k.pair.quote); } else cleanOrder(k.orderId, k.exchangeId); if (((CF*)config)->argDebugOrders) FN::log("DEBUG", string("OG memory ") + to_string(allOrders.size()) + "/" + to_string(allOrdersIds.size())); }; diff --git a/src/server/qe.h b/src/server/qe.h index 5f5c1c5bd..4b08344ee 100644 --- a/src/server/qe.h +++ b/src/server/qe.h @@ -24,9 +24,9 @@ namespace K { quotingMode[mQuotingMode::Depth] = &calcDepthOfMarket; }; void waitTime() { - ((EV*)events)->tStart->data = (void*)this; - ((EV*)events)->tCalcs->data = (void*)this; - uv_timer_start(((EV*)events)->tCalcs, [](uv_timer_t *handle) { + ((EV*)events)->tStart->setData(this); + ((EV*)events)->tCalcs->setData(this); + ((EV*)events)->tCalcs->start([](Timer *handle) { QE *k = (QE*)handle->data; if (((CF*)k->config)->argDebugEvents) FN::log("DEBUG", "EV GW tCalcs timer"); if (((MG*)k->market)->fairValue) { @@ -545,10 +545,10 @@ namespace K { nextStart[side] = q; nextIsPong = isPong; if (tStarted) { - uv_timer_stop(((EV*)events)->tStart); + ((EV*)events)->tStart->stop(); tStarted = 0; } - uv_timer_start(((EV*)events)->tStart, [](uv_timer_t *handle) { + ((EV*)events)->tStart->start([](Timer *handle) { QE *k = (QE*)handle->data; if (((CF*)k->config)->argDebugEvents) FN::log("DEBUG", "EV GW tStart timer"); k->start(k->nextStart.begin()->first, k->nextStart.begin()->second, k->nextIsPong); diff --git a/src/server/ui.h b/src/server/ui.h index c576e180d..173edef51 100644 --- a/src/server/ui.h +++ b/src/server/ui.h @@ -8,6 +8,7 @@ namespace K { string B64auth = "", notepad = ""; bool toggleSettings = true; + bool realtimeClient = false; map queue; map*> hello; map*> kiss; @@ -26,8 +27,8 @@ namespace K { }; void waitTime() { if (((CF*)config)->argHeadless) return; - ((EV*)events)->tDelay->data = (void*)this; - uv_timer_start(((EV*)events)->tDelay, sendState, 0, 0); + ((EV*)events)->tDelay->setData(this); + ((EV*)events)->tDelay->start(sendState, 0, 0); }; void waitData() { if (((CF*)config)->argHeadless) return; @@ -43,7 +44,6 @@ namespace K { string auth = req.getHeader("authorization").toString(); string addr = res->getHttpSocket()->getAddress().address; if (addr.length() > 7 and addr.substr(0, 7) == "::ffff:") addr = addr.substr(7); - lock_guard lock(((EV*)events)->hubMutex); if (((CF*)config)->argWhitelist != "" and ((CF*)config)->argWhitelist.find(addr) == string::npos) { FN::log("UI", "dropping gzip bomb on", addr); content << ifstream("etc/K-bomb.gzip").rdbuf(); @@ -109,10 +109,7 @@ namespace K { } if (uiBIT::Hello == (uiBIT)message[0] and hello.find(message[1]) != hello.end()) { json reply = (*hello[message[1]])(); - if (!reply.is_null()) { - lock_guard lock(((EV*)events)->hubMutex); - webSocket->send(string(message, 2).append(reply.dump()).data(), uWS::OpCode::TEXT); - } + if (!reply.is_null()) webSocket->send(string(message, 2).append(reply.dump()).data(), uWS::OpCode::TEXT); } else if (uiBIT::Kiss == (uiBIT)message[0] and kiss.find(message[1]) != kiss.end()) (*kiss[message[1]])(json::parse((length > 2 and (message[2] == '[' or message[2] == '{')) ? string(message, length).substr(2, length-2) : "{}" @@ -145,12 +142,13 @@ namespace K { }; void delayme(double delayUI) { if (((CF*)config)->argHeadless) return; - uv_timer_set_repeat(((EV*)events)->tDelay, delayUI > 0 ? (int)(delayUI*1e+3) : 6e+4 + 1); - uv_timer_again(((EV*)events)->tDelay); + realtimeClient = !delayUI; + ((EV*)events)->tDelay->stop(); + ((EV*)events)->tDelay->start(sendState, 0, realtimeClient ? 6e+4 : (int)(delayUI*1e+3)); }; void send(uiTXT k, json o, bool delayed = false) { if (((CF*)config)->argHeadless or connections == 0) return; - if (realtimeClient() or !delayed) send(k, o.dump()); + if (realtimeClient or !delayed) send(k, o.dump()); else queue[k] = o.dump(); }; private: @@ -174,7 +172,6 @@ namespace K { void send(uiTXT k, string j) { string m(1, (char)uiBIT::Kiss); m += string(1, (char)k) + j; - lock_guard lock(((EV*)events)->hubMutex); ((EV*)events)->uiGroup->broadcast(m.data(), m.length(), uWS::OpCode::TEXT); }; void sendQueue() { @@ -182,10 +179,10 @@ namespace K { send(it->first, it->second); queue.clear(); }; - void (*sendState)(uv_timer_t*) = [](uv_timer_t *handle) { + void (*sendState)(Timer*) = [](Timer *handle) { UI *k = (UI*)handle->data; if (((CF*)k->config)->argDebugEvents) FN::log("DEBUG", "EV UI tDelay timer"); - if (!k->realtimeClient()) { + if (!k->realtimeClient) { k->sendQueue(); static unsigned long uiT_1m = 0; if (uiT_1m+6e+4 > FN::T()) return; @@ -205,9 +202,6 @@ namespace K { {"a", gw->A()} }; }; - bool realtimeClient() { - return uv_timer_get_repeat(((EV*)events)->tDelay) == 6e+4 + 1; - }; }; }