namespace OpenVPNSocketGUI import System import System.Collections import System.Drawing import System.Windows.Forms import System.Net import System.Net.Sockets interface NetworkStreamLineConsumer: def NetworkStreamLineConsume(s as string) class NetworkStreamLineWatcher: static final BUFFER_SIZE = 1024; // TODO: turn this down for corner-case testing! _stream as NetworkStream _timer as System.Timers.Timer _buffer as (byte) = array(byte, BUFFER_SIZE) _partial_string as string _consumers as List = [] def constructor(stream as NetworkStream): self._stream = stream self._timer = System.Timers.Timer() self._timer.Interval = 200 self._timer.Elapsed += {self._tick()} self._timer.Enabled = true self._partial_string = null def AddConsumer(consumer as NetworkStreamLineConsumer): self._consumers.Add(consumer) def Start(): self._timer.Start() def Stop(): self._timer.Stop() private def _inform_consumers(s as string): for consumer as NetworkStreamLineConsumer in self._consumers: consumer.NetworkStreamLineConsume(s) private def _tick(): while self._stream.DataAvailable: read_length = self._stream.Read(self._buffer, 0, BUFFER_SIZE) read_string = System.Text.ASCIIEncoding.ASCII.GetString(self._buffer[:read_length]) substrings = read_string.Split(char('\n')) if substrings.Length == 1: // only a partial line if self._partial_string == null: self._partial_string = substrings[0] else: self._partial_string += substrings[0] return elif substrings.Length > 1: // first line first if self._partial_string == null: self._inform_consumers(substrings[0]) else: self._inform_consumers(self._partial_string + substrings[0]) self._partial_string = null for s in substrings[1:-1]: self._inform_consumers(s) if substrings[-1].Length != 0: self._partial_string = substrings[-1] interface VpnStateWatcher: def VpnStateChange(new_text as string) def VpnLogLine(new_text as string) class VpnState(NetworkStreamLineConsumer): [property(State)] _state_text as string _watchers as List _tcpclient as TcpClient _tcpclient_stream as NetworkStream _tcpclient_watcher as NetworkStreamLineWatcher def constructor(): self._tcpclient = null self._tcpclient_stream = null self._watchers = [] def AddWatcher(watcher as VpnStateWatcher): self._watchers.Add(watcher) def NetworkStreamLineConsume(s as string): for watcher as VpnStateWatcher in self._watchers: watcher.VpnLogLine(s) private def _inform_watchers(): for watcher as VpnStateWatcher in self._watchers: watcher.VpnStateChange(self._state_text) def connect(host as string, port as int): try: self._tcpclient = TcpClient(host, port) self._tcpclient_stream = self._tcpclient.GetStream() self._tcpclient_watcher = NetworkStreamLineWatcher(self._tcpclient_stream) self._tcpclient_watcher.AddConsumer(self) except e as System.Net.Sockets.SocketException: self._tcpclient = null self._tcpclient_stream = null self._state_text = "Connection error (${e.Message})" self._inform_watchers() def disconnect(): self._tcpclient.Close() self._tcpclient = null self._tcpclient_stream = null partial class MainForm(VpnStateWatcher): vpn_model as VpnState def constructor(): vpn_model = VpnState() vpn_model.AddWatcher(self) InitializeComponent() // Make the Designer bits work def VpnStateChange(new_text as string): self.toolStripStatusLabel.Text = new_text def VpnLogLine(new_text as string): print 'This line is executed' self.textBox_log.Text += new_text print 'This line is not' private def MainFormLoad(sender as object, e as System.EventArgs): pass private def Button_refreshClick(sender as object, e as System.EventArgs): vpn_model.connect('127.0.0.1', int.Parse(self.textBox_port.Text)) [STAThread] def Main(argv as (string)): Application.EnableVisualStyles() Application.SetCompatibleTextRenderingDefault(false) Application.Run(MainForm())