Exemplo n.º 1
0
 private async Task Receive(CancellationToken cancellationToken)
 {
     await Task.Run(() =>
     {
         using (var consumer = new ConsumerBuilder <Ignore, string>(config).Build())
         {
             Message message;
             consumer.Subscribe("main");
             while (!cancellationToken.IsCancellationRequested)
             {
                 var consumeResult = consumer.Consume(cancellationToken);
                 var strMessage    = consumeResult.Message.Value;
                 try
                 {
                     message = JsonConvert.DeserializeObject <Message>(consumeResult.Message.Value);
                     NewMessage?.BeginInvoke(message, null, null);
                 }
                 catch (Exception ex)
                 {
                     logger.Error(ex.Message);
                 }
             }
             consumer.Close();
         }
     });
 }
Exemplo n.º 2
0
        /// <summary>
        /// Send a message (data) to all server in the dictionnary (wsDict)
        /// </summary>
        /// <param name="data"></param>
        /// <remarks>
        /// It will close connection with server who didn't respond
        /// </remarks>
        public void Broadcast(string data)
        {
            var serverClose = new Dictionary <string, WebSocket>();

            foreach (var item in MainViewModel.ServerList)
            {
                try
                {
                    item.Value.Send(data);
                }
                catch (Exception)
                {
                    NewMessage.BeginInvoke(this, new EventArgsMessage($"The server {item.Key} is closed."), null, null);
                    serverClose.Add(item.Key, item.Value);
                }
            }
            foreach (var item in serverClose)
            {
                MainViewModel.ServerList.Remove(item);
                var receivers = MainViewModel.ServerListUpdated?.GetInvocationList();
                if (receivers != null)
                {
                    foreach (EventHandler receiver in receivers)
                    {
                        receiver.BeginInvoke(this, EventArgs.Empty, null, null);
                    }
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Connect to a list of server
        /// </summary>
        /// <param name="servers"></param>
        /// <see cref="Connect"/>
        public void ConnectToAll(List <string> servers)
        {
            NewMessage.BeginInvoke(this, new EventArgsMessage("Connect to the others servers"), null, null);

            // Connect to those servers
            foreach (var address in servers)
            {
                Connect(address);
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Method used to connect to a server
        /// It will :
        /// - Create the "OnMessage" method to answer the server request
        /// - Send the blockchain in local to the server (to check who have the good one)
        /// - Ask for new server
        /// </summary>
        /// <param name="url">
        /// The server address
        /// </param>
        /// <remarks>
        /// It will create a connection only if the server is not the local one
        /// and if the server is not already in the server list
        /// </remarks>
        public void Connect(string url)
        {
            // If we know the adress (url) or if it's our server address don't connect
            if (MainViewModel.ServerList.ContainsKey(url) || url == ServerAddress)
            {
                return;
            }

            // Message for the console
            NewMessage.BeginInvoke(this, new EventArgsMessage($"Begin Connection to {url}"), null, null);

            // Create the webSocket from the url
            var ws = new WebSocket(url);

            ws.OnMessage += (sender, e) =>
            {
                var guid = Guid.NewGuid();
                try
                {
                    MainViewModel.WaitingForBlockchainAccess(guid);

                    #region BlockChain Received

                    if (e.Data.StartsWith(Constants.BLOCKCHAIN_IS_NOT_VALID))
                    {
                        NewMessage.BeginInvoke(this, new EventArgsMessage(Constants.BLOCKCHAIN_IS_NOT_VALID), null, null);
                        var chainReceived = JsonConvert.DeserializeObject <KittyChain>(e.Data.Substring(Constants.BLOCKCHAIN_IS_NOT_VALID.Length));
                        MainViewModel.BlockChain = chainReceived;
                        NewMessage.BeginInvoke(this, new EventArgsMessage(Constants.BLOCKCHAIN_UPDATED), null, null);
                    }
                    else if (e.Data.StartsWith(Constants.BLOCKCHAIN_MISS_BLOCK))
                    {
                        NewMessage.BeginInvoke(this, new EventArgsMessage(Constants.BLOCKCHAIN_MISS_BLOCK), null, null);
                        var chainReceived = JsonConvert.DeserializeObject <KittyChain>(e.Data.Substring(Constants.BLOCKCHAIN_MISS_BLOCK.Length));
                        MainViewModel.BlockChain = chainReceived;
                        NewMessage.BeginInvoke(this, new EventArgsMessage(Constants.BLOCKCHAIN_UPDATED), null, null);
                    }
                    else if (e.Data.StartsWith(Constants.BLOCKCHAIN_OVERWRITE))
                    {
                        NewMessage.BeginInvoke(this, new EventArgsMessage(Constants.BLOCKCHAIN_OVERWRITE), null, null);
                        var chainReceived = JsonConvert.DeserializeObject <KittyChain>(e.Data.Substring(Constants.BLOCKCHAIN_OVERWRITE.Length));
                        MainViewModel.BlockChain = chainReceived;
                        NewMessage.BeginInvoke(this, new EventArgsMessage(Constants.BLOCKCHAIN_UPDATED), null, null);
                    }
                    else if (e.Data.StartsWith(Constants.NEED_BLOCKCHAIN))
                    {
                        ws.Send(Constants.BLOCKCHAIN + JsonConvert.SerializeObject(MainViewModel.BlockChain));
                    }
                    else if (e.Data.StartsWith(Constants.BLOCKCHAIN))
                    {
                        var chainReceived = JsonConvert.DeserializeObject <KittyChain>(e.Data.Substring(Constants.BLOCKCHAIN.Length));
                        if (!MainViewModel.BlockChain.IsValid() && chainReceived.IsValid())
                        {
                            MainViewModel.BlockChain = chainReceived;
                            NewMessage.BeginInvoke(this, new EventArgsMessage(Constants.BLOCKCHAIN_UPDATED), null, null);
                        }
                    }

                    #endregion

                    #region Server List Request Receive

                    // The request want our server list
                    else if (e.Data.StartsWith("ServerList"))
                    {
                        NewMessage.BeginInvoke(this, new EventArgsMessage("Server list received"), null, null);

                        // Deserialize the server send in the request
                        // The Substring cut "GetServers"
                        var servers = JsonConvert.DeserializeObject <List <string> >(e.Data.Substring(10));

                        ConnectToAll(servers);
                    }

                    #endregion

                    // Unknow request
                    else
                    {
                        NewMessage.BeginInvoke(this, new EventArgsMessage("Unknown message"), null, null);
                    }
                }
                catch (Exception ex)
                {
                    NewMessage.BeginInvoke(this, new EventArgsMessage(ex.Message), null, null);
                }
                finally
                {
                    MainViewModel.BlockChainWaitingList.Remove(guid);
                    var receivers = MainViewModel.BlockChainUpdated?.GetInvocationList();
                    if (receivers != null)
                    {
                        foreach (EventHandler receiver in receivers)
                        {
                            receiver.BeginInvoke(this, EventArgs.Empty, null, null);
                        }
                    }
                }
            };
            ws.Connect();
            var receiversServerList = MainViewModel.ServerListUpdated?.GetInvocationList();
            if (receiversServerList != null)
            {
                foreach (EventHandler receiver in receiversServerList)
                {
                    receiver.BeginInvoke(this, EventArgs.Empty, null, null);
                }
            }
            ws.Send(Constants.BLOCKCHAIN + JsonConvert.SerializeObject(MainViewModel.BlockChain));
            ws.Send(Constants.GET_SERVERS + JsonConvert.SerializeObject(new List <string>(GetServers())
            {
                ServerAddress
            }));

            MainViewModel.ServerList.Add(url, ws);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Method called when the server receive a message
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMessage(MessageEventArgs e)
        {
            var guid = Guid.NewGuid();

            try
            {
                MainViewModel.WaitingForBlockchainAccess(guid);
                #region BlockChain Receive

                // The request send the entire blockchain
                if (e.Data.StartsWith(Constants.BLOCKCHAIN))
                {
                    // Deserialize the blockchain received
                    // The Substring cut "BlockChain" or "BlockChainOverwrite"
                    var chainReceived = JsonConvert.DeserializeObject <KittyChain>(e.Data.Substring(e.Data.StartsWith("BlockChainOverwrite") ? 19 : 10));
                    NewMessage.BeginInvoke(this, new EventArgsMessage("Check blockchain"), null, null);

                    /* If chain received and local is not valid
                     * OR
                     * If same blockchain received and local
                     * OR
                     * If same chain and same pending transfers list
                     * => Do nothing
                     */
                    if (MainViewModel.BlockChain.Equals(chainReceived))
                    {
                        MainViewModel.BlockChainWaitingList.Remove(guid);
                        return;
                    }

                    var localIsValid    = MainViewModel.BlockChain.IsValid();
                    var receivedIsValid = chainReceived.IsValid();

                    if (!localIsValid &&
                        !receivedIsValid)
                    {
                        MainViewModel.BlockChain.InitializeChain();
                    }

                    // If chain received is not valid but local is
                    // => Send that the received blockchain is not valid
                    if (!receivedIsValid && localIsValid)
                    {
                        NewMessage.BeginInvoke(this, new EventArgsMessage("Blockchain receive not valid but local is"), null, null);
                        Send(Constants.BLOCKCHAIN_IS_NOT_VALID + JsonConvert.SerializeObject(MainViewModel.BlockChain));
                    }

                    // If chain received is valid but local is not
                    // Copy the received blockchain
                    if (receivedIsValid && !localIsValid)
                    {
                        NewMessage.BeginInvoke(this, new EventArgsMessage("Blockchain receive is valid and local is not"), null, null);
                        MainViewModel.BlockChain = chainReceived;
                        NewMessage.BeginInvoke(this, new EventArgsMessage(Constants.BLOCKCHAIN_UPDATED), null, null);
                    }

                    // If the received chain is bigger than local
                    // => Copy the received blockchain
                    else if (chainReceived.Chain.Count > MainViewModel.BlockChain.Chain.Count)
                    {
                        NewMessage.BeginInvoke(this, new EventArgsMessage("Blockchain is bigger than local"), null, null);
                        MainViewModel.BlockChain = chainReceived;
                        NewMessage.BeginInvoke(this, new EventArgsMessage(Constants.BLOCKCHAIN_UPDATED), null, null);
                    }

                    // If the received chain is lower than local
                    // => Send the local blockchain
                    else if (chainReceived.Chain.Count < MainViewModel.BlockChain.Chain.Count)
                    {
                        NewMessage.BeginInvoke(this, new EventArgsMessage("Blockchain receive lower than local"), null, null);
                        Send(Constants.BLOCKCHAIN_MISS_BLOCK + JsonConvert.SerializeObject(MainViewModel.BlockChain));
                    }

                    // If the chain are equals but the pending transfer list are different
                    // => Get the pending transfer not in local and send the list of transfer
                    else if (chainReceived.Chain.SequenceEqual(MainViewModel.BlockChain.Chain) &&
                             !chainReceived.PendingTransfers.SequenceEqual(MainViewModel.BlockChain.PendingTransfers))
                    {
                        NewMessage.BeginInvoke(this, new EventArgsMessage("Chain equals but different pending transfers/nWaiting for transfer message"), null, null);
                    }
                    else
                    {
                        // If the sender force to overwrite the local
                        if (e.Data.StartsWith(Constants.BLOCKCHAIN_OVERWRITE))
                        {
                            NewMessage.BeginInvoke(this, new EventArgsMessage("Overwrite BlockChain from sender"), null, null);
                            MainViewModel.BlockChain = chainReceived;
                            NewMessage.BeginInvoke(this, new EventArgsMessage(Constants.BLOCKCHAIN_UPDATED), null, null);
                        }
                        // Send a overwrite force to the sender
                        else
                        {
                            NewMessage.BeginInvoke(this, new EventArgsMessage("BlockChain receive is same size than actual but different information"), null, null);
                            Send(Constants.BLOCKCHAIN_OVERWRITE + JsonConvert.SerializeObject(MainViewModel.BlockChain));
                        }
                    }
                }
                else if (e.Data.StartsWith(Constants.NEED_BLOCKCHAIN))
                {
                    Send(Constants.BLOCKCHAIN + JsonConvert.SerializeObject(MainViewModel.BlockChain));
                }

                #endregion

                #region Block Receive

                else if (e.Data.StartsWith(Constants.BLOCK))
                {
                    // Deserialize the block
                    // The Substring cut "Block"
                    var newBlock = JsonConvert.DeserializeObject <Block>(e.Data.Substring(5));
                    NewMessage.BeginInvoke(this, new EventArgsMessage("New Block received"), null, null);

                    if (!MainViewModel.BlockChain.IsValid() ||
                        newBlock.PreviousHash != MainViewModel.BlockChain.LastBlock.Hash ||
                        newBlock.Index != MainViewModel.BlockChain.LastBlock.Index + 1)
                    {
                        Send(Constants.NEED_BLOCKCHAIN);
                    }
                    else
                    {
                        MainViewModel.BlockChain.Chain.Add(newBlock);
                        foreach (var tr in newBlock.Transfers)
                        {
                            MainViewModel.BlockChain.PendingTransfers.Remove(tr);
                        }

                        if (newBlock.Index % Constants.NUMBER_OF_BLOCKS_TO_CHECK_DIFFICULTY == 0)
                        {
                            NewMessage.BeginInvoke(this, new EventArgsMessage(MainViewModel.BlockChain.CheckDifficulty()), null, null);
                        }
                    }
                }

                #endregion

                #region Transfer Receive

                // The request send a new transfer
                else if (e.Data.StartsWith(Constants.TRANSFER))
                {
                    // Deserialize the transfer
                    // The Substring cut "Transfer"
                    var newTransfer = JsonConvert.DeserializeObject <Transfer>(e.Data.Substring(8));
                    NewMessage.BeginInvoke(this, new EventArgsMessage("New transfer received"), null, null);

                    var chain        = MainViewModel.BlockChain.Chain.ToArray();
                    var transactions = MainViewModel.BlockChain.PendingTransfers.ToArray();

                    // If we already have it (in pending transfer or already validated) or it's not a valid transfer don't add it
                    if (transactions.Any(t => t.Equals(newTransfer)) ||
                        chain.Any(b => b.Transfers.Any(t => t.Equals(newTransfer))) ||
                        !newTransfer.IsValid() ||
                        newTransfer.Amount <= 0 ||
                        newTransfer.Biscuit < 0 ||
                        MainViewModel.BlockChain.GetBalance(newTransfer.FromAddress, chain, transactions) < newTransfer.Amount + newTransfer.Biscuit)
                    {
                        NewMessage.BeginInvoke(this, new EventArgsMessage("New Transfer not valid or already in local"), null, null);
                    }
                    else
                    {
                        // If already is Ok add it to our pending transfer list
                        MainViewModel.BlockChain.PendingTransfers.Add(newTransfer);
                        NewMessage.BeginInvoke(this, new EventArgsMessage("New transfer added from server"), null, null);
                    }
                }
                // The request send a list of transfer
                else if (e.Data.StartsWith(Constants.TRANSFERS))
                {
                    // Deserialize the transfer
                    // The Substring cut "Transfer"
                    var newTransfers = JsonConvert.DeserializeObject <List <Transfer> >(e.Data.Substring(9));
                    NewMessage.BeginInvoke(this, new EventArgsMessage("New list of transfer received"), null, null);

                    foreach (var newTransfer in newTransfers)
                    {
                        // If we already have it or it's not a valid transfer don't add it
                        if (MainViewModel.BlockChain.PendingTransfers.Any(t => t.Equals(newTransfer)) ||
                            MainViewModel.BlockChain.Chain.Any(b => b.Transfers.Any(t => t.Equals(newTransfer))) ||
                            !newTransfer.IsValid())
                        {
                            NewMessage.BeginInvoke(this, new EventArgsMessage("New Transfer not valid or already in local"), null, null);
                        }
                        else
                        {
                            // If already is Ok add it to our pending transfer list
                            MainViewModel.BlockChain.PendingTransfers.Add(newTransfer);
                            NewMessage.BeginInvoke(this, new EventArgsMessage("New transfer added from server"), null, null);
                        }
                    }
                }

                #endregion

                #region GetServers Receive

                else if (e.Data.StartsWith(Constants.GET_SERVERS))
                {
                    NewMessage.BeginInvoke(this, new EventArgsMessage("Get Servers request received"), null, null);
                    var listWs = JsonConvert.DeserializeObject <List <string> >(e.Data.Substring(10));

                    ServerUpdate.BeginInvoke(this, new EventArgsObject(listWs), null, null);
                    if (MainViewModel.ServerList.Any())
                    {
                        Send("ServerList" + JsonConvert.SerializeObject(MainViewModel.ServerList.Select(x => x.Key)));
                    }
                }

                #endregion

                else
                {
                    NewMessage.BeginInvoke(this, new EventArgsMessage("Unknown message"), null, null);
                }
            }
            catch (Exception ex)
            {
                NewMessage.BeginInvoke(this, new EventArgsMessage(ex.Message), null, null);
            }
            finally
            {
                MainViewModel.BlockChainWaitingList.Remove(guid);
                var receivers = MainViewModel.BlockChainUpdated?.GetInvocationList();
                if (receivers != null)
                {
                    foreach (EventHandler receiver in receivers)
                    {
                        receiver.BeginInvoke(this, EventArgs.Empty, null, null);
                    }
                }
            }
        }