void HandleNewCMs( IPEndPoint[] newCms )
        {
            for ( int x = 0 ; x < newCms.Length ; ++x )
            {
                IPEndPoint newServer = newCms[ x ];

                var newMonitor = new Monitor( newServer );
                monitors[ newServer ] = newMonitor;

                newMonitor.Connect( DateTime.Now + TimeSpan.FromSeconds( x ) );
            }
        }
        public async void NotifyCMOnline( Monitor monitor )
        {
            IPHostEntry dnsEntry = null;

            try
            {
                dnsEntry = await Task<IPHostEntry>.Factory.FromAsync( Dns.BeginGetHostEntry, Dns.EndGetHostEntry, monitor.Server.Address, null );
            }
            catch ( SocketException )
            {
                // not the end of the world if we can't reverse resolve the hostname
            }

            string keyName = monitor.Server.ToString();

            var serverInfo = new ServerInfo
            {
                Server = keyName,
                IsOnline = true,
                Result = null,
            };

            if ( dnsEntry != null )
            {
                serverInfo.Host = dnsEntry.HostName;
            }

            var task = redis.Hashes.Set( 10, "steamstatus:servers", keyName, serverInfo.SerializeToBytes() );
        }
        public async void NotifyCMOffline( Monitor monitor, EResult result = EResult.Invalid )
        {
            string keyName = monitor.Server.ToString();

            ServerInfo serverInfo = ServerInfo.DeserializeFromBytes( await redis.Hashes.Get( 10, "steamstatus:servers", keyName ) );

            serverInfo.IsOnline = false;

            if ( result != EResult.Invalid )
            {
                serverInfo.Result = result.ToString();
            }

            var task = redis.Hashes.Set( 10, "steamstatus:servers", keyName, serverInfo.SerializeToBytes() );
        }