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;
using System.Media;
using TradeIdeas.ServerConnection;
namespace TclShell
{
public partial class MainForm : Form, IConnectionNameListener
{
///
/// This will be null if we don't know the channel. Possibly there was an error.
/// Possibly we're just waiting for the response from the server.
///
public static string ResponseChannel { get; private set; }
public MainForm()
{
InitializeComponent();
virtualNameComboBox.Items.AddRange(DESTINATIONS);
string[] args = Environment.GetCommandLineArgs();
if (args.Length >= 2)
{
hostNameTextBox.Text = args[1];
if (args.Length >= 3)
portTextBox.Text = args[2];
}
UpdateComboBox();
}
//
public static string ConnectionName { get; private set; }
private void connectButton_Click(object sender, EventArgs e)
{
int port;
if (Int32.TryParse(portTextBox.Text, out port))
{
ServerConnectionHolder.Connect(hostNameTextBox.Text, port);
// Listen for the old type of background messages.
var msg = TalkWithServer.CreateMessage("command", "flex_listen");
ServerConnectionHolder.Connection.SendMessage(msg, FlexResponse, true);
// Listen for the new type of background messages.
initBackgroundChannel();
ConnectionName = CurrentDestination().Name;
foreach (var window in Application.OpenForms)
if (window is IConnectionNameListener)
((IConnectionNameListener)window).OnNewConnectionName(ConnectionName);
}
else
SystemSounds.Beep.Play();
}
private void pingCheckBox_CheckedChanged(object sender, EventArgs e)
{
pingTimer.Enabled = pingCheckBox.Checked;
}
private Dictionary _lastMessage;
private void pingTimer_Tick(object sender, EventArgs e)
{
if (!ServerConnectionHolder.Connected)
{
pingStatusLabel.Text = "Not connected.";
return;
}
_lastMessage =
TalkWithServer.CreateMessage("command", "tcl_command", "script", "expr 1");
ServerConnectionHolder.Connection.SendMessage(_lastMessage, PingResponse, clientId: _lastMessage);
}
private void PingResponse(byte[] body, object clientId)
{
if (InvokeRequired)
Invoke((MethodInvoker)delegate { PingResponse(body, clientId); });
else
{
if (clientId == _lastMessage)
{ // Ignore old messages.
if (null == body)
pingStatusLabel.Text = "Error " + DateTime.Now.ToString("H:mm:ss");
else
pingStatusLabel.Text = "Good " + DateTime.Now.ToString("H:mm:ss");
}
}
}
private void FlexResponse(byte[] body, object clientId)
{
if (InvokeRequired)
Invoke((MethodInvoker)delegate { FlexResponse(body, clientId); });
else
{
if (null == body)
flexResponseTextBox.AppendText("Error.\r\n");
else
flexResponseTextBox.AppendText(TalkWithServer.BytesToStr(body).Replace("\n", "\r\n") + "\r\n");
}
}
private void newWindowButton_Click(object sender, EventArgs e)
{
new ScriptExecutor().Show();
}
private void MainForm_Resize(object sender, EventArgs e)
{
int space = backgroundChannelNameTextBox.Top - flexResponseTextBox.Bottom;
int usableWidth = flexResponseTextBox.Width - space;
try
{
backgroundChannelNameTextBox.Width = usableWidth / 2;
backgroundChannelScriptTextBox.Width = usableWidth - backgroundChannelNameTextBox.Width;
backgroundChannelScriptTextBox.Left = backgroundChannelNameTextBox.Right + space;
}
catch { }
}
private TalkWithServer.CancelToken _backgroundChannelCancelToken = null;
private object _sessionId;
bool _backgroundChannelFirstMessage;
private void initBackgroundChannel()
{
ShowDisconnected();
if (null != _backgroundChannelCancelToken)
_backgroundChannelCancelToken.Cancel();
_backgroundChannelCancelToken = new TalkWithServer.CancelToken();
var message = TalkWithServer.CreateMessage("command", "tcl_command", "script",
"namespace eval [ti::get_socket_temp_ns]::tcl_shell {variable channel [ti::get_current_channel]; set channel}");
_sessionId = new object();
_backgroundChannelFirstMessage = true;
ServerConnectionHolder.Connection.SendMessage(message, Response, streaming: true, clientId: _sessionId, cancelToken: _backgroundChannelCancelToken);
}
private void Response(byte[] body, object clientId)
{
BeginInvoke((MethodInvoker)delegate { ResponseInThread(body, clientId); });
}
private void ResponseInThread(byte[] body, object clientId)
{
if (clientId != _sessionId)
// Ignore old messages;
return;
if (null == body)
ShowDisconnected();
else
{
String response = TalkWithServer.BytesToStr(body);
if (_backgroundChannelFirstMessage)
{
_backgroundChannelFirstMessage = false;
if (response.StartsWith("0: "))
{
backgroundChannelNameTextBox.Enabled = true;
backgroundChannelNameTextBox.Text = response.Substring(3);
ResponseChannel = backgroundChannelNameTextBox.Text;
}
else
{ // Presumably we got an error message.
backgroundChannelNameTextBox.Enabled = false;
backgroundChannelNameTextBox.Text = response;
ResponseChannel = null;
}
}
else
flexResponseTextBox.AppendText(response.Replace("\n", "\r\n") + "\r\n");
}
}
private void ShowDisconnected()
{
backgroundChannelNameTextBox.Enabled = false;
backgroundChannelNameTextBox.Text = "disconnected";
ResponseChannel = null;
}
private class Destination
{
///
/// Visible to the user in the combo box.
///
public String Name { get; private set; }
///
/// Can be null. Null means we don't change the GUI when someone
/// selected this. Null means we won't Match() the GUI ever.
///
public String HostName {get; private set; }
///
/// Can be null. Null means we don't change the GUI when someone
/// selected this. Null means we won't Match() the GUI ever.
///
public String PortNumber { get; private set; }
public Destination(String name, String hostName, String portNumber)
{
Name = name;
HostName = hostName;
PortNumber = portNumber;
}
public Destination(String name)
{
Name = name;
}
public override string ToString()
{
return Name;
}
public void DisplayTo(MainForm mainForm)
{
if (null != HostName)
mainForm.hostNameTextBox.Text = HostName;
if (null != PortNumber)
mainForm.portTextBox.Text = PortNumber;
}
public bool Matches(MainForm mainForm)
{
return (HostName == mainForm.hostNameTextBox.Text)
&& (PortNumber == mainForm.portTextBox.Text);
}
}
// I considered a GUI to let you change this. But this seems sufficient.
// These are usually hiding behind a firewall, so you see 127.0.0.1 a lot.
// Make sure your SSH forwarding settings match these names.
private static readonly Destination[] DavesDestinations =
new Destination[] { new Destination("Custom"),
new Destination("Linode test", "127.0.0.1", "9372")
};
private static readonly Destination[] PhilipsDestinations =
new Destination[] { new Destination("Custom"),
new Destination("═══ Live ═══════════════"),
new Destination("Lrrr (live AI)", "127.0.0.1", "9370"), // 9370 --> lrrr:9370
new Destination("pc-load-letter (AI Server)", "127.0.0.1", "9383"), // 9383 --> pc-load-letter:9270
new Destination("y2k (AI Server)", "127.0.0.1", "9380"), // 9380 --> y2k:9270
new Destination("───────────────"),
new Destination("Sinclair-2k (live charts)", "127.0.0.1", "9373"), // 9373 --> sinclair-2k:9370
new Destination("Daisy-Mae-128k (live charts)", "127.0.0.1", "9374"), // 9374 --> daisy-mae-128k:9370
new Destination("y2k (live charts)", "127.0.0.1", "9381"), // 9381 --> y2k:9370
new Destination("dom (live charts, on its way out)", "127.0.0.1", "9382"), // 9382 --> dom:9370
new Destination("pc-load-letter (live charts)", "127.0.0.1", "9384"), // 9384 --> pc-load-letter:9370
new Destination("null-pointer (live charts)", "127.0.0.1", "9385"), // 9385 --> null-pointer:9370
new Destination("───────────────"),
new Destination("null-pointer (live Paper Trading)", "127.0.0.1", "9387"), // 9387 --> null-pointer:9270
new Destination("bob-saget (live calendar)", "127.0.0.1", "9389"), // 9389 --> bob-saget:9270
new Destination("chuck-liddell (live charts)", "127.0.0.1", "9390"), // 9390 --> chuck-liddell:9370
new Destination("race-condition (live charts)", "127.0.0.1", "9391"), // 9391 --> race-condition:9370
new Destination("seth (market explorer server)", "127.0.0.1", "9393"), // 9393 --> seth:9370
new Destination("Ndnd (misc)", "127.0.0.1", "9376"), // 9376 --> ndnd:9370
new Destination("Sinclair-2k (price alerts)", "127.0.0.1", "9375"), // 9375 --> sinclair-2k:9270
new Destination("═══ Test and Development ════"),
new Destination("Becca (test)", "127.0.0.1", "9371"), // 9371 --> becca:9370
new Destination("Linode test", "127.0.0.1", "9372"), // 9372 --> ??:9370
new Destination("Morbo (test AI)", "127.0.0.1", "9377"), // 9377 --> morbo:9370
new Destination("Morbo (dev AI)", "127.0.0.1", "9392"), // 9392 --> morbo:9270
new Destination("Morbo (dev Paper Trading)", "127.0.0.1", "9386"), // 9386 --> morbo:9170
new Destination("id-10-t (24 hour)", "127.0.0.1", "9378"), // 9378 --> 127.0.0.1:9370
new Destination("Joey-Mousepad (Philip dev)", "127.0.0.1", "9379"), // 9379 --> joey-mousepad:9370
new Destination("Morbo (Tim Dev Instance)", "127.0.0.1", "9394"), // 9394 --> morbo:9670
};
private static readonly Destination[] DESTINATIONS = PhilipsDestinations;
private static readonly Destination DEFAULT_DESTINATION = DESTINATIONS[0];
private bool _ignoreAddressChanges = false;
private void hostNameTextBox_TextChanged(object sender, EventArgs e)
{
if (_ignoreAddressChanges)
return;
UpdateComboBox();
}
private void virtualNameComboBox_SelectedValueChanged(object sender, EventArgs e)
{
if (_ignoreAddressChanges)
return;
UpdateFromComboBox();
}
private void UpdateComboBox()
{
_ignoreAddressChanges = true;
virtualNameComboBox.SelectedItem = DEFAULT_DESTINATION;
foreach (Destination destination in DESTINATIONS)
if (destination.Matches(this))
{
virtualNameComboBox.SelectedItem = destination;
break;
}
_ignoreAddressChanges = false;
}
private Destination CurrentDestination()
{
return (Destination)virtualNameComboBox.SelectedItem;
}
private void UpdateFromComboBox()
{
_ignoreAddressChanges = true;
CurrentDestination().DisplayTo(this);
_ignoreAddressChanges = false;
}
void IConnectionNameListener.OnNewConnectionName(string connectionName)
{
Text = "TCL Shell – " + connectionName;
}
private void reloaderButton_Click(object sender, EventArgs e)
{
new ReloadTcl().Show();
}
}
}