Exemple #1
0
        public GameLobby Read(string gameType, string lobbyId)
        {
            new ValidationCheck()
            .Assert(ValidationCheck.BasicStringCheck(gameType, nameof(gameType)))
            .Assert(ValidationCheck.BasicStringCheck(lobbyId, nameof(lobbyId)))
            .Throw();

            string lobbyKey = CreateKey(gameType, lobbyId);

            using (var r = new RedisClient(this.opt))
            {
                var p = new RedisPipeline()
                        .Send(RedisCommand.GET, lobbyKey)
                        .Send(RedisCommand.EXPIRE, lobbyKey);

                Stopwatch sw = new Stopwatch();
                sw.Start();
                var foundGame = r.Send(p);
                this.publishTimingStats(redisCategory, sw.ElapsedMilliseconds);

                if (foundGame[0] == null)
                {
                    throw new LobbyException(404, "lobby does not exist");
                }

                string    lobbyStr = Encoding.UTF8.GetString(foundGame[0]);
                GameLobby gl       = JsonConvert.DeserializeObject <GameLobby>(lobbyStr);

                return(gl);
            }
        }
Exemple #2
0
        public void SetTest()
        {
            RedisOptions opt = new RedisOptions("localhost", 6379);

            using (var r = new RedisClient(opt))
            {
                var pipe1 = new RedisPipeline()
                            // only allow one game to be hosted per IP address
                            .Send(RedisCommand.GET, "derp")
                            // actually create the lobby
                            .Send(RedisCommand.SET, "derp", "hi", "NX", "EX", "900");

                var resp1 = r.Send(pipe1);
                Assert.NotEqual(null, resp1[1]);


                var pipe2 = new RedisPipeline()
                            // only allow one game to be hosted per IP address
                            .Send(RedisCommand.GET, "derp")
                            // actually create the lobby
                            .Send(RedisCommand.SET, "derp", "bye ", "NX", "EX", "900");

                var resp2 = r.Send(pipe2);
                Assert.Equal(null, resp2[1]);

                r.Send(RedisCommand.DEL, "derp");
            }
        }
Exemple #3
0
        public void SetStream(Stream stream)
        {
            _stream?.Dispose();

            _stream   = new BufferedStream(stream);
            _reader   = new RedisReader(this);
            _pipeline = new RedisPipeline(this);
        }
Exemple #4
0
        public void SetStream(Stream stream)
        {
            if (_stream != null)
            {
                try { _stream.Close(); } catch { }
                try { _stream.Dispose(); } catch { }
            }

            _stream   = stream;
            _reader   = new RedisReader(this);
            _pipeline = new RedisPipeline(this);
        }
Exemple #5
0
        public void SetStream(Stream stream)
        {
            if (_stream != null)
            {
                _stream.Dispose();
            }

            NetworkStream = stream;
            _stream       = new BufferedStream(stream);
            _reader       = new RedisReader(this);
            _pipeline     = new RedisPipeline(this);
        }
Exemple #6
0
        public GameLobby Create(string gameType, string ip, int port, string name, bool hidden, Dictionary <string, string> meta)
        {
            new ValidationCheck()
            .Assert(ValidationCheck.BasicStringCheck(gameType, nameof(gameType)))
            .Assert(ValidationCheck.BasicStringCheck(ip, nameof(ip)))
            .Assert(ValidationCheck.BasicStringCheck(name, nameof(name)))
            .Assert(port > 1024, nameof(port) + " is privileged")
            .Throw();

            gameType = gameType.ToUpperInvariant().Trim();
            ip       = ip.ToUpperInvariant().Trim();

            using (var r = new RedisClient(this.opt))
            {
                GameLobby gl = new GameLobby();
                gl.clients      = new List <Client>();
                gl.creationTime = DateTime.UtcNow;
                gl.host         = new Client();
                gl.host.port    = port;
                gl.host.name    = name;
                gl.host.ip      = ip;
                gl.gameType     = gameType;
                gl.hidden       = hidden;
                // The lobbyID is very much a magic string, and care
                // should be taken if you mess with it.
                // Redis search methods depend on it being a certain
                // format: "gameType-[s]shortId"
                gl.lobbyId = IdGenerator.GetId(hidden);

                gl.metaData = meta ?? new Dictionary <string, string>();

                string lobbyKey = CreateKey(gl.gameType, gl.lobbyId);

                var pipe = new RedisPipeline()
                           // only allow one game to be hosted per IP address
                           .Send(RedisCommand.EVAL, EnsureSingleLua, "2", hostPrefix + gl.host.ip, lobbyKey)
                           // actually create the lobby
                           .Send(RedisCommand.SET, lobbyKey, JsonConvert.SerializeObject(gl), "NX", "EX", ExpirationTimeSec);

                Stopwatch sw = new Stopwatch();
                sw.Start();
                var resp = r.Send(pipe);
                this.publishTimingStats(redisCategory, sw.ElapsedMilliseconds);

                if (resp[1] == null)
                {
                    throw new LobbyException(500, "lobby already exists");
                }

                return(gl);
            }
        }
Exemple #7
0
        private IRedisChannel PrepareRedisChannel(Socket socket)
        {
            var socketWrapper = new SocketWrapper(socket);

            var channel = _redisPipelinePool.GetOrCreate(() =>
            {
                var asyncSocket = new AsyncSocketWrapper();
                var pipeline    = new RedisPipeline(asyncSocket, new RedisSender(_buffersPool, asyncSocket, false), new RedisReceiver(_inputBuffersPool, asyncSocket));
                return(new RedisChannel(pipeline));
            });

            channel.ResetState();
            channel.EngageWith(socketWrapper);
            channel.EngageWith(Serializer);

            return(channel);
        }
        bool InitIO(Stream stream)
        {
            lock (_connectionLock)
            {
                if (_stream != null)
                {
                    return(true);
                }
            }

            if (stream != null)
            {
                _stream = new BufferedStream(stream);
                _writer = new RedisWriter(_stream, Encoding);
                //_reader = new RedisReader(_stream, Encoding);
                _pipeline = new RedisPipeline(_stream, Encoding, _reader);
            }
            return(Connected);
        }
Exemple #9
0
        /// <summary>
        /// get a list of lobbies for a gametype.
        /// hidden games will not be returned
        /// </summary>
        /// <param name="gameType">gametype to search</param>
        /// <param name="metaKey">optional metadata key filter. the key must exist</param>
        /// <param name="metaValue">optional metadata value filter. the value must match for the given key.</param>
        /// <returns></returns>
        public List <GameLobby> Search(string gameType, string metaKey = null, string metaValue = null)
        {
            new ValidationCheck()
            .Assert(ValidationCheck.BasicStringCheck(gameType, nameof(gameType)))
            .Throw();

            gameType = gameType.ToUpperInvariant();

            // As it stands now, this search method will not scale well when there are many instances
            // of lobbies for the same game. maxSearchReturnSize*keyMult games are pulled first,
            // and then those are filtered by metaKey and metaValue. If none of those games in that
            // first scan match, then no games will be returned.
            // If this ever becomes a problem, I could create additional keys for metadata
            // inside Redis and use pattern matching SCAN on those keys. This just opens me up
            // to requiring a much larger redis instance, though, unless I want to further restrict
            // metaData.
            int keyMult = 1;
            Func <Dictionary <string, string>, bool> matches = (d) => true;

            if (!string.IsNullOrWhiteSpace(metaKey))
            {
                keyMult = 10;
                if (!string.IsNullOrWhiteSpace(metaValue))
                {
                    matches = (d) => d != null && d.ContainsKey(metaKey) && string.Equals(d[metaKey], metaValue);
                }
                else
                {
                    matches = (d) => d != null && d.ContainsKey(metaKey);
                }
            }

            var           foundGames = new List <GameLobby>();
            RedisPipeline pipe       = new RedisPipeline();

            using (var r = new RedisClient(this.opt))
            {
                // get initial set of keys
                Stopwatch sw = new Stopwatch();
                sw.Start();
                foreach (var searchRes in r.Scan(RedisCommand.SCAN, lobbyPrefix + gameType + "-[^" + SecretPrefix.ToString() + "]*"))
                {
                    foreach (var key in searchRes)
                    {
                        // build up messages to get more data
                        pipe.Send(RedisCommand.GET, key);

                        if (pipe.Length >= maxSearchReturnSize * keyMult)
                        {
                            break;
                        }
                    }
                    if (pipe.Length >= maxSearchReturnSize * keyMult)
                    {
                        break;
                    }
                }

                // get lobby data
                var readDetails = r.Send(pipe);
                this.publishTimingStats(redisCategory, sw.ElapsedMilliseconds);

                foreach (var lobby in readDetails)
                {
                    string    lobbyStr = Encoding.UTF8.GetString(lobby);
                    GameLobby gl       = JsonConvert.DeserializeObject <GameLobby>(lobbyStr);

                    if (matches(gl.metaData) && (gl.gameType == gameType))
                    {
                        foundGames.Add(gl);
                    }

                    if (foundGames.Count >= maxSearchReturnSize)
                    {
                        break;
                    }
                }
            }

            if (foundGames.Count == 0)
            {
                throw new LobbyException(404, "no games match search parameters");
            }

            return(foundGames);
        }