CPPKiteConnect
ws.hpp
1 /*
2  * Licensed under the MIT License <http://opensource.org/licenses/MIT>.
3  * SPDX-License-Identifier: MIT
4  *
5  * Copyright (c) 2020-2021 Bhumit Attarde
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
20  * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
22  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23  * USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 
26 #pragma once
27 
28 #include <algorithm> //reverse
29 #include <atomic>
30 #include <chrono>
31 #include <cstdint>
32 #include <cstring> //memcpy
33 #include <functional>
34 #include <ios>
35 #include <iostream>
36 #include <limits>
37 #include <string>
38 #include <thread>
39 #include <unordered_map>
40 #include <utility>
41 #include <vector>
42 
43 #include "../exceptions.hpp"
44 #include "../responses/responses.hpp"
45 #include "../userconstants.hpp" //modes
46 #include "../utils.hpp"
47 
48 #include "rapidjson/include/rapidjson/document.h"
49 #include "rapidjson/include/rapidjson/rapidjson.h"
50 #include "rapidjson/include/rapidjson/writer.h"
51 #include <uWS/uWS.h>
52 
53 namespace kiteconnect {
54 
55 // To make sure doubles are parsed correctly
56 static_assert(std::numeric_limits<double>::is_iec559,
57  "Requires IEEE 754 floating point!");
58 
59 using std::string;
60 namespace kc = kiteconnect;
61 
66 class ticker {
67 
68  public:
69  // callbacks
71  std::function<void(ticker* ws)> onConnect;
72 
74  std::function<void(ticker* ws, const std::vector<kc::tick>& ticks)> onTicks;
75 
77  std::function<void(ticker* ws, const kc::postback& postback)> onOrderUpdate;
78 
80  std::function<void(ticker* ws, const string& message)> onMessage;
81 
84  std::function<void(ticker* ws, int code, const string& message)> onError;
85 
87  std::function<void(ticker* ws)> onConnectError;
88 
103  std::function<void(ticker* ws, unsigned int attemptCount)> onTryReconnect;
104 
109  std::function<void(ticker* ws)> onReconnectFail;
110 
112  std::function<void(ticker* ws, int code, const string& message)> onClose;
113 
126  explicit ticker(string Key,
139  unsigned int ConnectTimeout = DEFAULT_CONNECT_TIMEOUT,
140  bool EnableReconnect = false,
141  unsigned int MaxReconnectDelay = DEFAULT_MAX_RECONNECT_DELAY,
142  unsigned int MaxReconnectTries = DEFAULT_MAX_RECONNECT_TRIES);
143 
149  void setApiKey(const string& key);
150 
156  string getApiKey() const;
157 
166  void setAccessToken(const string& token);
167 
173  string getAccessToken() const;
174 
176  void connect();
177 
179  bool isConnected() const;
180 
187  std::chrono::time_point<std::chrono::system_clock> getLastBeatTime() const;
188 
190  void run();
191 
194  void stop();
195 
202  void subscribe(const std::vector<int>& instrumentTokens);
203 
210  void unsubscribe(const std::vector<int>& instrumentTokens);
211 
219  void setMode(const string& mode, const std::vector<int>& instrumentTokens);
220 
221  private:
222  friend class tickerTest_binaryParsingTest_Test;
223  const string connectUrlFmt =
224  "wss://ws.kite.trade/?api_key={0}&access_token={1}";
225  string key;
226  string token;
227  enum class SEGMENTS : int
228  {
229  NSE = 1,
230  NFO,
231  CDS,
232  BSE,
233  BFO,
234  BSECDS,
235  MCX,
236  MCXSX,
237  INDICES
238  };
239  enum class MODES
240  {
241  LTP,
242  QUOTE,
243  FULL
244  };
245  const MODES DEFAULT_MODE = MODES::QUOTE;
246  std::unordered_map<int, MODES> subbedInstruments;
247  uWS::Hub hub;
248  // NOLINTNEXTLINE(readability-implicit-bool-conversion)
249  uWS::Group<uWS::CLIENT>* group;
250  // NOLINTNEXTLINE(readability-implicit-bool-conversion)
251  uWS::WebSocket<uWS::CLIENT>* ws = nullptr;
252  static constexpr unsigned int DEFAULT_CONNECT_TIMEOUT = 5; // s
253  static constexpr unsigned int DEFAULT_MAX_RECONNECT_DELAY = 60; // s
254  static constexpr unsigned int DEFAULT_MAX_RECONNECT_TRIES = 30;
255  const unsigned int connectTimeout = DEFAULT_CONNECT_TIMEOUT; // ms
256  const string pingMessage;
257  const unsigned int pingInterval = 3000; // ms
258  const bool enableReconnect = false;
259  const unsigned int initReconnectDelay = 2; // s
260  unsigned int reconnectDelay = initReconnectDelay;
261  const unsigned int maxReconnectDelay = DEFAULT_MAX_RECONNECT_DELAY; // s
262  unsigned int reconnectTries = 0;
263  const unsigned int maxReconnectTries = DEFAULT_MAX_RECONNECT_TRIES;
264  std::atomic<bool> isReconnecting { false };
265  std::chrono::time_point<std::chrono::system_clock> lastPongTime;
266  std::chrono::time_point<std::chrono::system_clock> lastBeatTime;
267 
268  void connectInternal();
269 
270  void reconnect();
271 
272  void processTextMessage(const string& message);
273 
274  template <typename T>
275  T unpack(const std::vector<char>& bytes, size_t start, size_t end);
276 
277  std::vector<std::vector<char>> splitPackets(const std::vector<char>& bytes);
278 
279  std::vector<kc::tick> parseBinaryMessage(char* bytes, size_t size);
280 
281  void resubInstruments();
282 
283  void assignCallbacks();
284 };
285 } // namespace kiteconnect
kiteconnect::ticker::connect
void connect()
Connect to the websocket server.
Definition: internal.hpp:81
kiteconnect::ticker::onOrderUpdate
std::function< void(ticker *ws, const kc::postback &postback)> onOrderUpdate
Called when an order update is received.
Definition: ws.hpp:77
kiteconnect::ticker::onConnect
std::function< void(ticker *ws)> onConnect
Called on successful connect.
Definition: ws.hpp:71
kiteconnect::ticker
ticker wraps around the websocket API provided by KiteConnect and provides a native interface.
Definition: ws.hpp:66
kiteconnect::ticker::onMessage
std::function< void(ticker *ws, const string &message)> onMessage
Called when a message is received.
Definition: ws.hpp:80
kiteconnect::ticker::run
void run()
Start the client. Should always be called after connect().
Definition: internal.hpp:93
kiteconnect::ticker::setAccessToken
void setAccessToken(const string &token)
Set the access token.
Definition: internal.hpp:77
kiteconnect::ticker::subscribe
void subscribe(const std::vector< int > &instrumentTokens)
Subscribe to a list of instrument tokens.
Definition: internal.hpp:99
kiteconnect::postback
Represents a postback.
Definition: ws.hpp:79
kiteconnect::ticker::onConnectError
std::function< void(ticker *ws)> onConnectError
Called when an error occures while trying to connect.
Definition: ws.hpp:87
kiteconnect::ticker::setMode
void setMode(const string &mode, const std::vector< int > &instrumentTokens)
Set the subscription mode for a list of instrument tokens.
Definition: internal.hpp:132
kiteconnect::ticker::onTryReconnect
std::function< void(ticker *ws, unsigned int attemptCount)> onTryReconnect
Called when reconnection is being attempted.
Definition: ws.hpp:103
kiteconnect::ticker::isConnected
bool isConnected() const
Check if client is connected.
Definition: internal.hpp:86
kiteconnect::ticker::onClose
std::function< void(ticker *ws, int code, const string &message)> onClose
Called when connection is closed.
Definition: ws.hpp:112
kiteconnect::ticker::onReconnectFail
std::function< void(ticker *ws)> onReconnectFail
Called when reconnect attempts exceed maximum reconnect attempts set by user i.e.,...
Definition: ws.hpp:109
kiteconnect::ticker::onError
std::function< void(ticker *ws, int code, const string &message)> onError
Called when connection is closed with an error or websocket server sends an error message.
Definition: ws.hpp:84
kiteconnect::ticker::setApiKey
void setApiKey(const string &key)
Set the API key.
Definition: internal.hpp:73
kiteconnect::ticker::getAccessToken
string getAccessToken() const
Get access token set at the moment.
Definition: internal.hpp:79
kiteconnect::ticker::getLastBeatTime
std::chrono::time_point< std::chrono::system_clock > getLastBeatTime() const
Get the last time heartbeat was received. Should be used in conjunction with the isConnected() method...
Definition: internal.hpp:89
kiteconnect::ticker::getApiKey
string getApiKey() const
Get API key set at the moment.
Definition: internal.hpp:75
kiteconnect::ticker::ticker
ticker(string Key, unsigned int ConnectTimeout=DEFAULT_CONNECT_TIMEOUT, bool EnableReconnect=false, unsigned int MaxReconnectDelay=DEFAULT_MAX_RECONNECT_DELAY, unsigned int MaxReconnectTries=DEFAULT_MAX_RECONNECT_TRIES)
Construct a new kiteWS object.
Definition: internal.hpp:64
kiteconnect::ticker::onTicks
std::function< void(ticker *ws, const std::vector< kc::tick > &ticks)> onTicks
Called when ticks are received.
Definition: ws.hpp:74
kiteconnect::ticker::stop
void stop()
Stop the client. Closes the connection if connected. Should be the last method that is called.
Definition: internal.hpp:95
kiteconnect::ticker::unsubscribe
void unsubscribe(const std::vector< int > &instrumentTokens)
Unsubscribe.
Definition: internal.hpp:115