using System.Threading; using TradeIdeas.TIProData.Interfaces; namespace TradeIdeas.TIProData { /// /// IConnectionMaster gives a high level view of the connection. Most /// parts of the code will only need to talk with this object, and its /// exported members to talk with the server. /// /// The next level down is the ConnectionLifeCycle object. This is /// very generic and is responsible for creating and destroying the /// TalkWithServer objects, which are the next lower level. Those /// create a fairly generic server connection. ConnectionMaster /// takes care of other things, like logging in at appropriate times. /// When the main program asks to send a single message, the /// IConnectionMaster object might first send a login message then /// send the message requested by the main program. /// /// In the Delphi code all of the functions of this object, and the /// objects it owns were all part of one class. The C# version /// splits the work into more pieces. IConnectionMaster is very /// small. Most it just owns all of the things which should exist /// exactly once per connection. /// /// It is perfectly reasonable to create more than one ConnectionMaster /// object. That was not possible in Delphi, mostly as a convenience. /// It was easier to have just one place to look for this object. /// Now we rely on the main program to create an appropriate variable /// to store this object. /// public class ConnectionMaster : IConnectionMaster { /// /// This is what automatically reconnects, when required. /// private ConnectionLifeCycle _connectionLifeCycle; /// /// This lets you set the username and related items for the connection. /// public ILoginManager LoginManager { get; private set; } /// /// This provides ping statistics, if required. /// This is sometimes required to keep the connection alive. /// public PingManager PingManager { get; private set; } /// /// This is a convenent way to send messages. It helps manage retries, among /// other things. /// public ISendManager SendManager { get; private set; } /// /// This takes care of reading and setting symbol lists. /// public ListManager ListManager { get; private set; } /// /// This is the way to request streaming data for an alert window. /// public StreamingAlertsManager StreamingAlertsManager { get; private set; } /// /// This is the way to request historical alerts. /// public HistoryManager HistoryManager { get; private set; } /// /// This is the way to request historical top list data. /// /// At one time this was also used for streaming data. /// TopListRequest is now the preferred way to get streaming or non-historical snapshot data. /// public TopListManager TopListManager { get; private set; } /// /// This accesses the company name and exchange. We cache it so we can access it /// quickly and we don't send a lot of duplicate requests to the server. /// public ISymbolDetailsCacheManager SymbolDetailsCacheManager { get; private set; } /// /// This is the way to run the OddsMaker. /// public OddsMakerManager OddsMakerManager { get; private set; } /// /// This is the preferred way to request icons and the like. /// public ImageCacheManager ImageCacheManager { get; private set; } /// /// This is the way to get the company profile text /// public CompanyProfileManager CompanyProfileManager { get; private set; } /// /// This is the way to get insider trades /// public InsidersManager InsidersManager { get; private set; } /// /// This provides limited access to the connection life cycle. The main program /// can use this to offer connection instructions or to monitor the status of the /// connection. /// public ConnectionBase ConnectionBase { get { return _connectionLifeCycle; } } /// /// This is related to TIQ-Like stuff such as RBI, GBI /// public TraditionalAlertsManager TraditionalAlertsManager { get; private set; } /// /// Constructor for the connection master. /// public ConnectionMaster() { _connectionLifeCycle = new ConnectionLifeCycle(); // Initialize the login manager before anything else so it will be the first // one to get callbacks from the connection life cycle. We want to send the // login command first, before any other commands. LoginManager = new LoginManager(_connectionLifeCycle); PingManager = new PingManager(_connectionLifeCycle); SendManager = new SendManager(_connectionLifeCycle, LoginManager); ListManager = new ListManager(_connectionLifeCycle, SendManager); StreamingAlertsManager = new StreamingAlertsManager(_connectionLifeCycle, SendManager); HistoryManager = new HistoryManager(_connectionLifeCycle); TopListManager = new TopListManager(_connectionLifeCycle); SymbolDetailsCacheManager = new SymbolDetailsCacheManager(SendManager); OddsMakerManager = new OddsMakerManager(SendManager); ImageCacheManager = new ImageCacheManager(SendManager); CompanyProfileManager = new CompanyProfileManager(SendManager); InsidersManager = new InsidersManager(SendManager); TraditionalAlertsManager = new TraditionalAlertsManager(SendManager); Interlocked.CompareExchange(ref _first, this, null); } /// /// Throw away the resources. Can't use this object again after this. /// It is safe to call this more than once. /// /// You don't usually call Dispose(). Typically you create a IConnectionMaster once /// when the program first starts and use it forever. However, if you do choose to /// create lots of these, consider calling Dispose() to clean up memory. /// public void Dispose() { if (null != _connectionLifeCycle) _connectionLifeCycle.Dispose(); //SoftReset(); // Calling SoftReset from the GUI lead to a deadlock. The thread will // disconnect the socket soon enough, and that's all we really need. } /// /// The destructor calls Dispose(). /// ~ConnectionMaster() { Dispose(); } private static IConnectionMaster _first; /// /// A reference to the first IConnectionMaster created. /// /// You have a lot of freedom with IConnectionMaster object. You can create as many as you need. /// You can use multiple at once. You can Destroy() old ones. But in practice most programs only /// use one of these. And it can be a pain for every library to find the IConnectionMaster created /// by the main program. /// /// This always points to the first IConnectionMaster object created. Chances are, that's what /// you want. /// public static IConnectionMaster First { get { return _first; } } } }