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); } }
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"); } }
public void SetStream(Stream stream) { _stream?.Dispose(); _stream = new BufferedStream(stream); _reader = new RedisReader(this); _pipeline = new RedisPipeline(this); }
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); }
public void SetStream(Stream stream) { if (_stream != null) { _stream.Dispose(); } NetworkStream = stream; _stream = new BufferedStream(stream); _reader = new RedisReader(this); _pipeline = new RedisPipeline(this); }
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); } }
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); }
/// <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); }