#include #include "../shared/TclUtil.h" #include "ServerSigner.h" #include "ScriptDispatcher.h" #include "TopListRequest.h" #include "TclTopListRequestWrapper.h" static ServerSigner serverSigner; enum class Options { NOT_FOUND = -1, collaborate, useDatabase, streaming, saveToMru, collaborateColumns, outsideMarketHours, resultCount, singleSymbol, sortFormula, whereFormula, extraColumnFormulas }; static GetTclIndex< Options > optionsList({ "collaborate", "use_database" , "streaming", "save_to_mru", "collaborate_columns", "outside_market_hours", "result_count", "single_symbol", "sort_formula", "where_formula", "extra_column_formulas" }); static int convertFromTcl(Tcl_Interp *interp, TopListRequest::OptionalBool &destination, Tcl_Obj *source) { bool tempDestination; int result = convertFromTcl(interp, tempDestination, source); if (result == TCL_OK) destination = TopListRequest::optionalBool(tempDestination); return result; } static void doDataCallback(std::string const &script, SmarterCP< TopListRequest::Data > data, int64_t id) { std::map< std::string, TclObjHolder > dataAsMap; dataAsMap["start"] = convertToTcl(data->start); dataAsMap["end"] = convertToTcl(data->end); dataAsMap["rows"] = convertToTcl(data->rows); Tcl_Obj *dataAsObj = convertToTcl(dataAsMap); ScriptDispatcher::getPrimary()->getContainer()->addLambdaToQueue([=]() { Tcl_Interp *const interp = ExecutionContext::getInstance()->getInterp(); Tcl_UnsetVar(interp, "::ti::t_top_list_temp", 0); Tcl_SetVar2Ex(interp, "::ti::t_top_list_temp", NULL, dataAsObj, 0); std::string const toRun = script + " $::ti::t_top_list_temp " + serverSigner.encodeInt(id); // TclObjCache::getInstance().find(toRun // Tcl_EvalObjEx(interp, toRun.c_str(), 0); Tcl_Eval(interp, toRun.c_str()); }); } static void doMetaDataCallback(std::string const &script, SmarterCP< TopListRequest::MetaData > metaData, int64_t id) { std::map< std::string, TclObjHolder > asMap; asMap["collaborate"] = convertToTcl(metaData->collaborate); asMap["window_name"] = convertToTcl(metaData->windowName); asMap["sort_by"] = convertToTcl(metaData->sortBy); asMap["columns"] = convertToTcl(metaData->columns); Tcl_Obj *asObj = convertToTcl(asMap); ScriptDispatcher::getPrimary()->getContainer()->addLambdaToQueue([=]() { Tcl_Interp *const interp = ExecutionContext::getInstance()->getInterp(); Tcl_UnsetVar(interp, "::ti::t_top_list_temp", 0); Tcl_SetVar2Ex(interp, "::ti::t_top_list_temp", NULL, asObj, 0); std::string const toRun = script + " $::ti::t_top_list_temp " + serverSigner.encodeInt(id); Tcl_Eval(interp, toRun.c_str()); }); } static int topListRequestCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { if ((objc < 3) || (objc > 4)) { Tcl_WrongNumArgs(interp, 1, objv, "request data_callback ?metadata_callback?"); return TCL_ERROR; } Tcl_Obj *const requestDetails = objv[1]; // What to send to the server. Tcl_Obj *const dataCallback = objv[2]; Tcl_Obj *const metaDataCallback = (objc > 3)?objv[3]:NULL; TopListRequest request; int result = tclDictForEach(interp, requestDetails, [&](Tcl_Obj *key, Tcl_Obj *value) { const Options index = optionsList.get(interp, key, "top list option"); switch (index) { case Options::NOT_FOUND: throw BreakAndFail(); break; case Options::collaborate: if (convertFromTcl(interp, request.collaborate, value) != TCL_OK) throw BreakAndFail(); break; case Options::useDatabase: if (convertFromTcl(interp, request.useDatabase, value) != TCL_OK) throw BreakAndFail(); break; case Options::streaming: if (convertFromTcl(interp, request.streaming, value) != TCL_OK) throw BreakAndFail(); break; case Options::saveToMru: if (convertFromTcl(interp, request.saveToMru, value) != TCL_OK) throw BreakAndFail(); break; case Options::collaborateColumns: if (convertFromTcl(interp, request.collaborateColumns, value) != TCL_OK) throw BreakAndFail(); break; case Options::outsideMarketHours: if (convertFromTcl(interp, request.outsideMarketHours, value) != TCL_OK) throw BreakAndFail(); break; case Options::resultCount: if (convertFromTcl(interp, request.resultCount, value) != TCL_OK) throw BreakAndFail(); break; case Options::singleSymbol: if (convertFromTcl(interp, request.singleSymbol, value) != TCL_OK) throw BreakAndFail(); break; case Options::sortFormula: if (convertFromTcl(interp, request.sortFormula, value) != TCL_OK) throw BreakAndFail(); break; case Options::whereFormula: if (convertFromTcl(interp, request.whereFormula, value) != TCL_OK) throw BreakAndFail(); break; case Options::extraColumnFormulas: if (convertFromTcl(interp, request.extraColumnFormulas, value) != TCL_OK) throw BreakAndFail(); break; } }); if (result != TCL_OK) return TCL_ERROR; request.skipMetaData = TopListRequest::optionalBool(!metaDataCallback); const std::string dataCallbackString = getString(dataCallback); request.onData = [=](SmarterCP< TopListRequest::Data > data, int64_t id) { doDataCallback(dataCallbackString, data, id); }; if (metaDataCallback) { const std::string metaDataCallbackString = getString(metaDataCallback); request.onMetaData = [=](SmarterCP< TopListRequest::MetaData > metaData, int64_t id) { doMetaDataCallback(metaDataCallbackString, metaData, id); }; } const auto cancelCode = request.send(); Tcl_SetObjResult(interp, makeTclString(serverSigner.encodeInt(cancelCode))); return TCL_OK; } static int topListCancelCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "id"); return TCL_ERROR; } const int64_t id = serverSigner.decodeInt(getString(objv[1]), TopListRequest::UNUSED_ID); if (id == TopListRequest::UNUSED_ID) { Tcl_SetObjResult(interp, makeTclString("Invalid id")); return TCL_ERROR; } TopListRequest::cancel(id); return TCL_OK; } static int topListHistoryRequestCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { if ((objc < 4) || (objc > 5)) { Tcl_WrongNumArgs(interp, 1, objv, "collaborate save_to_mru data_callback ?metadata_callback?"); return TCL_ERROR; } Tcl_Obj *const collaborate = objv[1]; // What to send to the server. Tcl_Obj *const saveToMru = objv[2]; Tcl_Obj *const dataCallback = objv[3]; Tcl_Obj *const metaDataCallback = (objc > 4)?objv[4]:NULL; TopListHistoryRequest request; request.collaborate = getString(collaborate); int saveToMruAsInt; const int result = Tcl_GetBooleanFromObj(interp, saveToMru, &saveToMruAsInt); if (result != TCL_OK) return TCL_ERROR; request.saveToMru = saveToMruAsInt; const std::string dataCallbackString = getString(dataCallback); request.onData = [=](SmarterCP< TopListRequest::Data > data, int64_t id) { doDataCallback(dataCallbackString, data, id); }; if (metaDataCallback) { const std::string metaDataCallbackString = getString(metaDataCallback); request.onMetaData = [=](SmarterCP< TopListRequest::MetaData > metaData, int64_t id) { doMetaDataCallback(metaDataCallbackString, metaData, id); }; } const auto id = request.send(); Tcl_SetObjResult(interp, makeTclString(serverSigner.encodeInt(id))); return TCL_OK; } static int topListLoginCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "username password"); return TCL_ERROR; } TopListRequest::logIn(getString(objv[1]), getString(objv[2])); return TCL_OK; } static int topListLogoutCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { if (objc != 1) { Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } TopListRequest::logOut(); return TCL_OK; } void installTopListRequestCommands(Tcl_Interp *interp) { Tcl_CreateObjCommand(interp, "ti::t_top_list_request", topListRequestCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "ti::t_top_list_cancel", topListCancelCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "ti::t_top_list_history_request", topListHistoryRequestCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "ti::t_top_list_login", topListLoginCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "ti::t_top_list_logout", topListLogoutCmd, NULL, NULL); }