using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace TradeIdeas.MarketDataProxy { public partial class ConnectionListenerForm : Form { private class Controller { // This class is a fairly simple adapter between the ConnectionListener // and the GUI. The form object would handle this directly if we only // had one connection. private string _address; private int _port; private string _userFriendlyName; private string _statusMessage = ""; private ConnectionListener _connectionListener; public string Address { get { return _address; } } public int Port { get { return _port; } } public string StatusMessage { get { return _statusMessage; } } // This may be used by multiple threads. You should lock it before // accessing it. private HashSet _symbols = new HashSet(); public string[] Symbols { get { string[] result; lock (_symbols) { result = new string[_symbols.Count]; int i = 0; foreach (string symbol in _symbols) { result[i] = symbol; i++; } } return result; } } public Controller(string address, int port) { _address = address; _port = port; _userFriendlyName = address + ':' + port; Connect(); } public override string ToString() { // For the list box. return _userFriendlyName; } // I assume this will only be called by the form, so it will only be // called in one thread. public void Connect() { Disconnect(); _statusMessage = "Trying to connect."; lock (_symbols) _symbols.Clear(); ConnectionDescription cd = new ConnectionDescription(); cd.username = Globals.downStreamUsername; cd.password = Globals.downStreamPassword; cd.hostname = _address; cd.port = _port; cd.onPreview = new ConnectionDescription.Preview(OnPreview); cd.onSubscription = new ConnectionDescription.Subscription(OnSubscription); cd.onDisconnected = new ConnectionDescription.Connection(OnDisconnect); _connectionListener = new ConnectionListener(cd); _connectionListener.Connect(); } // I assume this will only be called by the form, or by the destructor // after the form has given up on it, so threads are not an issue. public void Disconnect() { if (_connectionListener != null) { _connectionListener.Disconnect(); _connectionListener = null; } } ~Controller() { Disconnect(); } private void OnPreview(ConnectionListener source, byte[] body) { // This might come from any thread. if (body == null) // Presumably we'll get at least one of these because of the // subscription message. _statusMessage = "Error: " + DateTime.Now.ToString(); else // Presumably we'll get a stream of these because of the ping // messages. _statusMessage = "Alive: " + DateTime.Now.ToString(); } private void OnSubscription(ConnectionListener source, List data) { if (source != _connectionListener) return; foreach (SubscriptionItem item in data) { lock (_symbols) { _symbols.Add(item.Symbol); } if (Globals.symbolListenerThread != null) Globals.symbolListenerThread.NewSubscription(item.Symbol, source); } } private void OnDisconnect(ConnectionListener source) { _statusMessage = "Disconnected"; if (Globals.symbolListenerThread != null) Globals.symbolListenerThread.CloseConnection(source); } } private ConnectionListenerForm() { InitializeComponent(); } private static ConnectionListenerForm _instance; private static Object _instanceLock = new Object(); public static ConnectionListenerForm GetInstance() { // We could allow more than one of these, but that's not the intent. lock (_instanceLock) { // http://www.yoda.arachsys.com/csharp/singleton.html if (_instance == null) _instance = new ConnectionListenerForm(); return _instance; } } private void ConnectionListenerForm_FormClosing(object sender, FormClosingEventArgs e) { if (e.CloseReason == CloseReason.UserClosing) { e.Cancel = true; Hide(); } } private void closeButton_Click(object sender, EventArgs e) { Controller c = (Controller)connectionsListBox.SelectedItem; if (c != null) { c.Disconnect(); int selectedIndex = connectionsListBox.SelectedIndex; connectionsListBox.Items.RemoveAt(selectedIndex); // After removing the item, nothing is selected. connectionsListBox.SelectedIndex = Math.Min(selectedIndex, connectionsListBox.Items.Count - 1); } } public void AddConnection(string address, string port) { AddConnection(address, Int32.Parse(port)); } public void AddConnection(string address, int port) { Controller c = new Controller(address, port); connectionsListBox.Items.Add(c); connectionsListBox.SelectedItem = c; } private void newConnectionButton_Click(object sender, EventArgs e) { AddConnection(addressTextBox.Text, portTextBox.Text); } private void restartButton_Click(object sender, EventArgs e) { Controller c = (Controller)connectionsListBox.SelectedItem; if (c != null) c.Connect(); } private void connectionsListBox_SelectedValueChanged(object sender, EventArgs e) { Controller c = (Controller)connectionsListBox.SelectedItem; if (c != null) { // This only makes sense when the user clicks. addressTextBox.Text = c.Address; portTextBox.Text = c.Port.ToString(); // This could be done at other times, like on a timer event. UpdateConnectionStatus(); } } private void UpdateConnectionStatus() { Controller c = (Controller)connectionsListBox.SelectedItem; if (c != null) { lastResponseLabel.Text = c.StatusMessage; symbolsTextBox.Lines = c.Symbols; } } private void timer1_Tick(object sender, EventArgs e) { if (Visible && (WindowState != FormWindowState.Minimized)) UpdateConnectionStatus(); } } }