Beispiel #1
0
        public void PackUnpack()
        {
            var doc      = TestHelpers.CreateStarDocument();
            var original = DocdbGatewayMessage.Create("Star", doc);

            var storage = new InMemoryGatewayBlobStore();

            byte[] packed   = GatewayPacket.Pack(original, storage);
            var    unpacked = GatewayPacket.Unpack <DocdbGatewayMessage>(packed, storage);

            Assert.AreEqual(original.Key, unpacked.Key);

            TestHelpers.AssertEqualStars(
                original.DocumentsAs <StarDocument>().First(),
                unpacked.DocumentsAs <StarDocument>().First()
                );
        }
Beispiel #2
0
        public void PackUnpack()
        {
            var entity   = TestHelpers.CreateStarEntity();
            var original = TableGatewayMessage.Create("Person", entity);

            var storage = new InMemoryGatewayBlobStore();

            byte[] packed = GatewayPacket.Pack(original, storage);
            TableGatewayMessage unpacked = GatewayPacket.Unpack <TableGatewayMessage>(packed, storage);

            Assert.AreEqual(original.Key, unpacked.Key);

            TestHelpers.AssertEqualStars(
                original.EntitiesAs <StarEntity>().First(),
                unpacked.EntitiesAs <StarEntity>().First()
                );
        }
Beispiel #3
0
        private void SendTo(ServerState state, GatewayPacket packet)
        {
            if (state.State == SERVER_STATE.Running)
            {
                byte[]      data = null;
                PACKET_TYPE type = PACKET_TYPE.PKT_UNKNOWN;

                switch (packet.PacketType)
                {
                case PACKET_TYPE.PKT_PUSH_DATA:
                    data = new byte[4];
                    type = PACKET_TYPE.PKT_PUSH_ACK;
                    break;

                case PACKET_TYPE.PKT_PULL_DATA:
                    data = new byte[12];
                    packet.EUI.CopyTo(data, 4);
                    type = PACKET_TYPE.PKT_PULL_ACK;
                    break;

                default:
                    break;
                }

                if (type != PACKET_TYPE.PKT_UNKNOWN)
                {
                    data[0] = packet.Version;
                    BitConverter.GetBytes(packet.Token).CopyTo(data, 1);
                    data[3] = (byte)type;

                    try
                    {
                        state.Socket.BeginSendTo(data, 0, data.Length, SocketFlags.None, packet.Sender, new AsyncCallback(SendToCallback), state);
                    }
                    catch (Exception ex)
                    {
                        state.ErrorSendTo = ex;
                    }
                }
            }
        }
Beispiel #4
0
 public async Task Send(GatewayPacket packet)
 {
     // from `ManagedWebSocket.s_validSendStates`
     if (_client is not {
         State : WebSocketState.Open or WebSocketState.CloseReceived
     })
        private async Task HandlePacket(string json, CancellationToken cancellationToken)
        {
            var genericGateway = JsonSerializer.Deserialize <GatewayPacket <object> >(json, _jsonOptions);

            if (genericGateway is null)
            {
                _logger.LogError("Unable to parse generic gateway packet");
                return;
            }

            if (genericGateway.SequenceNumber is not null)
            {
                _lastSequenceNumber = genericGateway.SequenceNumber;
            }

            switch (_state)
            {
            case GatewayState.Connecting:
                if (genericGateway.Opcode == Opcode.Hello)
                {
                    // We got a Hello, start sending heartbeats!
                    var helloPacket = DeserializePacket <HelloData>(json);
                    if (helloPacket is null || helloPacket.Data is null)
                    {
                        _logger.LogError("Invalid hello packet");
                        return;
                    }
                    _heartbeatInterval = TimeSpan.FromMilliseconds(helloPacket.Data.HeartbeatInterval);
                    _logger.LogDebug("Heartbeat interval set to '{Interval}'", _heartbeatInterval);
                    if (_heartbeatTask is null)
                    {
                        _heartbeatTask = new BackgroundTask(SendHeartbeatAsync);
                    }
                    // Queue up an Identify packet
                    var identifyPacket = new GatewayPacket <IdentifyData>
                    {
                        Data = new IdentifyData
                        {
                            // TODO: Intents
                            Intents    = 1,
                            Token      = _settings.Value.Token,
                            Properties = new IdentifyDataProperties
                            {
                                Browser = "octantis",
                                Device  = "octantis",
                                Os      = "linux"
                            }
                        },
                        Opcode = Opcode.Identify
                    };

                    await TransmitGatewayAsync(identifyPacket, cancellationToken);
                }
                else if (genericGateway.Opcode == Opcode.Dispatch && genericGateway.EventName == Events.Ready)
                {
                    var readyPacket = DeserializePacket <ReadyData>(json);
                    if (readyPacket is null || readyPacket.Data is null)
                    {
                        _logger.LogError("Invalid ready packet");
                        return;
                    }
                    ApplicationId = readyPacket.Data.User?.Id ?? 0;
                    _sessionId    = readyPacket.Data.SessionId;
                    _logger.LogInformation("Connected to gateway v{Version}, application id '{Id}', session id '{Id}'", readyPacket.Data.GatewayVersion, ApplicationId, _sessionId);
                    foreach (var guild in readyPacket.Data.Guilds)
                    {
                        _logger.LogDebug("Guild '{Id}'", guild.Id);
                    }

                    // Got the ready event, move up to connected state!
                    _state = GatewayState.Connected;
                }
                else
                {
                    _logger.LogWarning("Unhandled opcode '{Opcode}'", genericGateway.Opcode);
                }
                break;

            case GatewayState.Connected:
            {
                // Handle events
                if (genericGateway.Opcode == Opcode.Heartbeat)
                {
                    // Force heartbeat send?
                    _logger.LogError("TODO: SEND HEARTBEAT");
                }
                else if (genericGateway.Opcode == Opcode.Dispatch)
                {
                    // EVENTS :D
                    var type = Events.FromString(genericGateway.EventName !);
                    List <Registration>?registrationsForEvent;
                    lock (_registrations)
                    {
                        _registrations.TryGetValue(type, out registrationsForEvent);
                    }
                    if (registrationsForEvent is not null)
                    {
                        foreach (var registration in registrationsForEvent)
                        {
                            var     packetType         = typeof(GatewayPacket <>).MakeGenericType(registration.ArgumentType);
                            dynamic deserializedAsType = JsonSerializer.Deserialize(json, packetType, _jsonOptions) !;
                            registration.Action(deserializedAsType.Data);
                        }
                    }
                    else
                    {
                        _logger.LogWarning("Unhandled event type '{Type}'", type);
                    }
                }
            }
            break;
            }
        }
 public async Task WritePacket(ClientWebSocket socket, GatewayPacket packet)
 {
     var bytes = JsonSerializer.SerializeToUtf8Bytes(packet, _jsonSerializerOptions);
     await socket.SendAsync(bytes.AsMemory(), WebSocketMessageType.Text, true, default);
 }
        protected override async void PacketRecieved(string packetstr)
        {
            GatewayPacket     packet = new GatewayPacket(packetstr);
            GatewayPacketType type   = packet.GetPacketType();

            if (type == GatewayPacketType.Hello)
            {
                Logger.Info("Server says hello!");
                SendIdentityPacket();
            }
            else if (type == GatewayPacketType.Heartbeat)
            {
                SendHeartBeat();
            }
            else if (type == GatewayPacketType.HeartbeatACK)
            {
            }
            else if (type == GatewayPacketType.InvalidSession)
            {
                Logger.Error("Invalid session");
                Disconnect();
            }
            else if (type == GatewayPacketType.Reconnect)
            {
                await Reconnect();
            }
            else if (type == GatewayPacketType.Dispatch)
            {
                string  EventType = packet.GetEventType();
                JObject data      = packet.GetData <JObject>();

                if (EventType == "READY")
                {
                    string bot_name = (string)data["user"]["username"];

                    botUserId = (string)data["user"]["id"];
                    sessionId = (string)data["session_id"];

                    foreach (Processor p in processors)
                    {
                        p.OnReady(bot_name);
                    }
                }
                else if (EventType == "MESSAGE_CREATE")
                {
                    Message message = packet.GetData <Message>();
                    (Guild guild, Channel channel) = GetGuildAndChannel(message.channel_id);

                    string[] words = SplitString(message.content);

                    Logger.Info($"New message [{message.author.username} in {guild.name} -> {channel.name}] {message.content}");

                    if (!message.author.bot)
                    {
                        foreach (Processor p in processors)
                        {
                            string prefix = p.GetPrefix();

                            if (prefix != null)
                            {
                                if (words.Length >= 2 && prefix == words[0])
                                {
                                    List <string> w2 = new List <string>(words);

                                    Logger.Debug("Command detected!");

                                    w2.RemoveAt(0);
                                    string command = w2[0];
                                    w2.RemoveAt(0);
                                    p.OnCommand(message, channel, command, w2.ToArray());
                                }
                            }

                            p.OnMessage(message, channel);
                        }
                    }
                    else
                    {
                        Logger.Info("Bot messeges are ignored");
                    }
                }
                else if (EventType == "TYPING_START")
                {
                    string channel_id = (string)data["channel_id"];
                    string user_id    = (string)data["user_id"];

                    foreach (Processor p in processors)
                    {
                        p.OnTypingStarted(channel_id, user_id);
                    }
                }
                else if (EventType == "PRESENCE_UPDATE")
                {
                    string status = (string)data["status"];
                    string game   = null;
                    try {
                        game = (string)data["game"]["name"];
                    } catch { }
                    string user_id = (string)data["user"]["id"];

                    foreach (Processor p in processors)
                    {
                        p.OnStatusChange(user_id, status, game);
                    }
                }
                else if (EventType == "GUILD_CREATE")
                {
                    Guild guild = packet.GetData <Guild>();
                    guilds.Add(guild);

                    Logger.Info($"Guild created: {guild.name} #{guild.id}");

                    foreach (Processor p in processors)
                    {
                        p.OnGuildCreate(guild);
                    }
                }
                else if (EventType == "GUILD_DELETE")
                {
                    string guild_id = (string)data["id"];

                    Logger.Info($"Guild removed: #{guild_id}");

                    for (int i = guilds.Count - 1; i >= 0; i--)
                    {
                        if (guilds[i].id == guild_id)
                        {
                            guilds.RemoveAt(i);
                        }
                    }

                    foreach (Processor p in processors)
                    {
                        p.OnGuildDelete(guild_id);
                    }
                }
                else if (EventType == "VOICE_STATE_UPDATE")
                {
                    string user_id = (string)data["user_id"];

                    userStatus[user_id] = packet.GetData <UserVoiceStatus>();

                    if (user_id != botUserId)
                    {
                        foreach (Processor p in processors)
                        {
                            p.OnUserVoiceStatusChange(user_id, userStatus[user_id]);
                        }
                    }
                }
                else if (EventType == "VOICE_SERVER_UPDATE")
                {
                    string guildId  = (string)data["guild_id"];
                    string endpoint = (string)data["endpoint"];
                    string token    = (string)data["token"];

                    if (endpoint != null)
                    {
                        if (!voiceSockets.ContainsKey(guildId) || !voiceSockets[guildId].IsOk())
                        {
                            string prefix = "wss://";
                            if (endpoint.Contains(":80"))
                            {
                                prefix = "ws://";
                            }
                            voiceSockets[guildId] = new VoiceSocket(new Uri(prefix + endpoint), guildId, sessionId, token, botUserId);
                            await voiceSockets[guildId].Connect();
                        }
                    }
                }
                else
                {
                    Logger.Debug($"Unknown event: {EventType}");
                }
            }
        }
Beispiel #8
0
        private void ReceiveFromCallback(IAsyncResult ar)
        {
            ServerState state = (ServerState)ar.AsyncState;

            if (state.State == SERVER_STATE.Running)
            {
                Socket socket = state.Socket;
                try
                {
                    // Read packet from gateway
                    IPEndPoint ipep      = new IPEndPoint(IPAddress.Any, 0);
                    EndPoint   epSender  = (EndPoint)ipep;
                    int        bytesRead = socket.EndReceiveFrom(ar, ref epSender);
                    byte[]     buffer    = state.Buffer;

                    // Check packet from gateway
                    if (bytesRead >= 4)
                    {
                        byte version = buffer[0];
                        if (version == 1 || version == 2)
                        {
                            GatewayPacket packet = new GatewayPacket();
                            packet.Version = version;
                            packet.Token   = BitConverter.ToUInt16(buffer, 1);

                            byte type = buffer[3];
                            switch (type)
                            {
                            case (byte)PACKET_TYPE.PKT_PUSH_DATA:
                                if (bytesRead > 12)
                                {
                                    packet.Json = Encoding.ASCII.GetString(buffer, 12, bytesRead - 12);
                                    packet.SetEUI(buffer);
                                }
                                else
                                {
                                    packet = null;
                                }
                                break;

                            case (byte)PACKET_TYPE.PKT_PULL_DATA:
                                if (bytesRead == 12)
                                {
                                    packet.SetEUI(buffer);
                                }
                                else
                                {
                                    packet = null;
                                }
                                break;

                            case (byte)PACKET_TYPE.PKT_TX_ACK:
                                if (bytesRead > 4)
                                {
                                    packet.Json = Encoding.ASCII.GetString(buffer, 4, bytesRead - 4);
                                }
                                else
                                {
                                    packet = null;
                                }
                                break;

                            default:
                                packet = null;
                                break;
                            }

                            if (packet != null)
                            {
                                packet.PacketType = (PACKET_TYPE)type;
                                packet.Sender     = epSender;

                                lock (state.LockPackets)
                                {
                                    if (state.Packets.Count < 100)
                                    {
                                        state.Packets.Enqueue(packet);
                                    }
                                    else
                                    {
                                        state.LostPackets++;
                                    }

                                    state.ResetEvent.Set();
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    state.ErrorReceiveFromCB = ex;
                }

                try
                {
                    IPEndPoint ipep     = new IPEndPoint(IPAddress.Any, 0);
                    EndPoint   epSender = (EndPoint)ipep;
                    socket.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref epSender, new AsyncCallback(ReceiveFromCallback), state);
                }
                catch (Exception ex)
                {
                    state.ErrorReceiveFrom = ex;
                }
            }
        }
Beispiel #9
0
        public void Run()
        {
            Console.WriteLine("\nPress any key to exit");

            JsonSerializerSettings settings = new JsonSerializerSettings();

            settings.Culture = CultureInfo.InvariantCulture;

            try
            {
                state.Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                state.Socket.Bind(new IPEndPoint(IPAddress.Any, Properties.Settings.Default.LwgPort));

                IPEndPoint ipep     = new IPEndPoint(IPAddress.Any, 0);
                EndPoint   epSender = (EndPoint)ipep;
                state.Socket.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref epSender, new AsyncCallback(ReceiveFromCallback), state);
                state.State = SERVER_STATE.Running;

                /*
                 * Test PULL_RESP
                 */
                GatewayPullResp TestPullRest = new GatewayPullResp();
                {
                    GatewayTxpkV1 txpk = new GatewayTxpkV1();
                    txpk.imme = true;
                    txpk.tmst = 0;
                    txpk.time = DateTime.UtcNow;
                    txpk.freq = 864.123456;
                    txpk.rfch = 0;
                    txpk.powe = 14;
                    txpk.modu = "SF11BW125";
                    txpk.codr = "4/6";
                    txpk.ipol = false;
                    txpk.size = 32;
                    txpk.data = "H3P3N2i9qc4yt7rK7ldqoeCVJGBybzPY5h1Dd7P7p8v";

                    TestPullRest.Txpk = txpk;
                }

                DateTime keyTime = DateTime.Now;
                while (state.State == SERVER_STATE.Running)
                {
                    while (state.Packets.Count > 0)
                    {
                        #region Process packets
                        GatewayPacket packet = null;
                        lock (state.LockPackets)
                        {
                            packet = state.Packets.Dequeue();
                            state.ResetEvent.Reset();
                        }

                        if (packet == null)
                        {
                            continue;
                        }

                        Console.WriteLine(string.Format("Recv from {0}", packet.Sender));
                        Console.WriteLine(packet.ToString());

                        try
                        {
                            switch (packet.PacketType)
                            {
                            case PACKET_TYPE.PKT_TX_ACK:
                                UInt32       token = packet.Token;
                                GatewayTxAck data  =
                                    string.IsNullOrEmpty(packet.Json)
                                                                                ? null
                                                                                : JsonConvert.DeserializeObject <GatewayTxAck>(packet.Json, settings);

                                if (data != null)
                                {                                               // Error
                                    Console.WriteLine("ERROR:");
                                    Console.WriteLine(JsonConvert.SerializeObject(data, Formatting.Indented));

                                    if (state.PullRespPackets.ContainsKey(token))
                                    {
                                        lock (state.LockPullResp)
                                        {
                                            GatewayPullResp pull = state.PullRespPackets[token];
                                            if (pull.Retry > 0)
                                            {
                                                pull.Retry--;
                                                pull.TimeToSend = DateTime.Now.AddSeconds(15);
                                                pull.State      = PULL_RESP_STATE.Ready;
                                            }
                                            else
                                            {
                                                state.PullRespPackets.Remove(token);
                                            }
                                        }
                                    }
                                }
                                else
                                {                                               // No error
                                    if (state.PullRespPackets.ContainsKey(token))
                                    {
                                        lock (state.LockPullResp)
                                            state.PullRespPackets.Remove(token);
                                    }
                                }
                                break;

                            case PACKET_TYPE.PKT_PULL_DATA:
                                GatewayState gw;
                                UInt64       eui = BitConverter.ToUInt64(packet.EUI, 0);
                                if (state.Gateways.ContainsKey(eui))
                                {
                                    gw = state.Gateways[eui];
                                }
                                else
                                {
                                    gw = new GatewayState();
                                }

                                gw.EndPoint = packet.Sender;
                                gw.LastTime = DateTime.Now;
                                SendTo(state, packet);
                                break;

                            case PACKET_TYPE.PKT_PUSH_DATA:
                                if (string.IsNullOrEmpty(packet.Json))
                                {
                                    Console.WriteLine("JSON ERROR: Empty payload");
                                }
                                else
                                {
                                    GatewayPushData json =
                                        (packet.Version == 1)
                                                                                        ? (GatewayPushData)JsonConvert.DeserializeObject <GatewayPushDataV1>(packet.Json, settings)
                                                                                        : (GatewayPushData)JsonConvert.DeserializeObject <GatewayPushDataV2>(packet.Json, settings)
                                    ;
                                    if (json != null)
                                    {
                                        /*
                                         * Console.WriteLine("JSON:");
                                         * Console.WriteLine(JsonConvert.SerializeObject(json, Formatting.Indented));
                                         */
                                        bool success = true;
                                        if (json.stat != null)
                                        {
                                            success &= ProcessingStat(json.stat);
                                        }

                                        if (json.rxpk != null && json.rxpk.Count > 0)
                                        {
                                            for (int idx = 0; idx < json.rxpk.Count; idx++)
                                            {
                                                success &= ProcessingRxpt(json.rxpk[idx]);
                                            }
                                        }
                                        if (success)
                                        {
                                            // Thread.Sleep(10);
                                            SendTo(state, packet);
                                        }
                                    }
                                }
                                break;

                            default:
                                break;
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(string.Format("Processing error:\n{0}", ex.ToString()));
                        }
                        #endregion
                    }

                    lock (state.LockPackets)
                        if (state.Packets.Count == 0)
                        {
                            state.ResetEvent.Reset();
                        }

                    if (!state.ResetEvent.WaitOne(500))
                    {
                        if ((DateTime.Now - keyTime).Seconds >= 5)
                        {
                            keyTime = DateTime.Now;
                            if (Console.KeyAvailable)
                            {
                                while (Console.KeyAvailable)
                                {
                                    Console.ReadKey(true);
                                }
                                state.State = SERVER_STATE.Stoped;
                                break;
                            }
                        }
                    }
                }

                state.Socket.Shutdown(SocketShutdown.Both);
                state.Socket.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
Beispiel #10
0
        private async Task OnReceive(GatewayPacket packet)
        {
            switch (packet.Opcode)
            {
            case GatewayOpcode.Hello:
            {
                await HandleHello((JsonElement)packet.Payload !);

                break;
            }

            case GatewayOpcode.Heartbeat:
            {
                _logger.Debug("Shard {ShardId}: Received heartbeat request from shard, sending Ack", ShardId);
                await _conn !.Send(new GatewayPacket {
                        Opcode = GatewayOpcode.HeartbeatAck
                    });
                break;
            }

            case GatewayOpcode.HeartbeatAck:
            {
                Latency = DateTimeOffset.UtcNow - _lastHeartbeatSent;
                _logger.Debug("Shard {ShardId}: Received heartbeat Ack with latency {Latency}", ShardId, Latency);
                if (Latency != null)
                {
                    HeartbeatReceived?.Invoke(Latency !.Value);
                }

                _hasReceivedAck = true;
                break;
            }

            case GatewayOpcode.Reconnect:
            {
                _logger.Information("Shard {ShardId}: Received Reconnect, closing and reconnecting", ShardId);
                await _conn !.Disconnect(WebSocketCloseStatus.Empty, null);
                break;
            }

            case GatewayOpcode.InvalidSession:
            {
                var canResume = ((JsonElement)packet.Payload !).GetBoolean();

                // Clear session info before DCing
                if (!canResume)
                {
                    SessionInfo = SessionInfo with {
                        Session = null
                    }
                }
                ;

                var delay = TimeSpan.FromMilliseconds(new Random().Next(1000, 5000));

                _logger.Information(
                    "Shard {ShardId}: Received Invalid Session (can resume? {CanResume}), reconnecting after {ReconnectDelay}",
                    ShardId, canResume, delay);
                await _conn !.Disconnect(WebSocketCloseStatus.Empty, null);

                // Will reconnect after exiting this "loop"
                await Task.Delay(delay);

                break;
            }

            case GatewayOpcode.Dispatch:
            {
                SessionInfo = SessionInfo with {
                    LastSequence = packet.Sequence
                };
                var evt = DeserializeEvent(packet.EventType !, (JsonElement)packet.Payload !) !;

                if (evt is ReadyEvent rdy)
                {
                    if (State == ShardState.Connecting)
                    {
                        await HandleReady(rdy);
                    }
                    else
                    {
                        _logger.Warning("Shard {ShardId}: Received Ready event in unexpected state {ShardState}, ignoring?",
                                        ShardId, State);
                    }
                }
                else if (evt is ResumedEvent)
                {
                    if (State == ShardState.Connecting)
                    {
                        await HandleResumed();
                    }
                    else
                    {
                        _logger.Warning("Shard {ShardId}: Received Resumed event in unexpected state {ShardState}, ignoring?",
                                        ShardId, State);
                    }
                }

                await HandleEvent(evt);

                break;
            }

            default:
            {
                _logger.Debug("Shard {ShardId}: Received unknown gateway opcode {Opcode}", ShardId, packet.Opcode);
                break;
            }
            }
        }