示例#1
0
        private async Task OnMessageReceived(object sender, MessageReceivedEventArgs e, WebSocket webSocket, string seedString, SignInSession session)
        {
            //_logger.Log(sender.ToString());
            _ = _logger.Log($"RECEIVED - {e.Message}");
            try
            {
                var msg   = JObject.Parse(e.Message);
                var route = msg["route"]?.ToString().ToLower() ?? "";

                switch (route)
                {
                case "connection":
                    // TODO: pass parameters
                    Init(null, null, session, seedString, null, null);
                    Instance4Net = webSocket;
                    //this.heartbeat()
                    _connected = true;

                    var connectionMessage = JsonConvert.DeserializeObject <ConnectionMessage>(e.Message);
                    Keys.Salts = connectionMessage.KeySalts;
                    _encryptedValidationMessage = connectionMessage.EncryptedValidationMessage.Data;

                    await SetKeys(seedString);

                    break;

                case "ping":
                    //this.heartbeat()
                    _ = _logger.Log("SENT - PONG");
                    const string action = "Pong";
                    Instance4Net.Send(JsonConvert.SerializeObject(new { action }));
                    break;

                case "applytransactions":
                    // TODO: in progress
                    var dbId       = msg["dbId"].ToString();
                    var dbNameHash = msg["dbNameHash"].ToString();    // || State.dbIdToHash[dbId]
                    if (!State.Databases.TryGetValue(dbNameHash, out var database))
                    {
                        throw new Exception("Missing database");
                    }

                    // queue guarantees transactions will be applied in the order they are received from the server
                    if (database.ApplyTransactionsQueue.Count == 0)
                    {
                        // take a spot in the queue and proceed applying so the next caller knows queue is not empty
                        database.ApplyTransactionsQueue.Enqueue(null);
                    }
                    else
                    {
                        // wait until prior batch in queue finishes applying successfully
                        var promise = new TaskCompletionSource <int>();
                        void Resolve()
                        {
                            var localPromise = promise;

                            localPromise.SetResult(0);
                        }
                        database.ApplyTransactionsQueue.Enqueue(Resolve);
                        await promise.Task;
                    }

                    var openingDatabase = msg["dbNameHash"] != null && msg["dbKey"] != null;
                    if (openingDatabase)
                    {
                        var dbKeyString = AesGcmUtils.DecryptString(Keys.EncryptionKey, msg["dbKey"].ToString());
                        database.DbKeyString = dbKeyString;
                        // TODO
                        //database.dbKey = await AesGcmUtils.GetKeyFromKeyString(dbKeyString);
                    }

                    //if (!database.dbKey) throw new Error('Missing db key')

                    if (msg["bundle"] != null)
                    {
                        /*const bundleSeqNo = message.bundleSeqNo
                         * const base64Bundle = message.bundle
                         * const compressedString = await crypto.aesGcm.decryptString(database.dbKey, base64Bundle)
                         * const plaintextString = LZString.decompress(compressedString)
                         * const bundle = JSON.parse(plaintextString)
                         *
                         * database.applyBundle(bundle, bundleSeqNo)*/
                    }

                    /*const newTransactions = message.transactionLog
                     *  await database.applyTransactions(newTransactions)*/

                    if (!database.Init)
                    {
                        State.DbIdToHash[dbId] = dbNameHash;
                        database.DbId          = dbId;
                        database.Init          = true;
                        _ = _logger.Log("DB - RECEIVED MESSAGE");
                        database.ReceivedMessage();
                    }

                    if (msg["buildBundle"] != null)
                    {
                        BuildBundle(database);
                    }

                    // start applying next batch in queue when this one is finished applying successfully
                    database.ApplyTransactionsQueue.Dequeue();
                    if (database.ApplyTransactionsQueue.Count > 0)
                    {
                        var startApplyingNextBatchInQueue = database.ApplyTransactionsQueue.Peek();
                        startApplyingNextBatchInQueue();
                    }

                    break;

                case "signout":
                case "updateuser":
                case "deleteuser":
                case "createdatabase":
                case "getdatabase":
                case "opendatabase":
                case "insert":
                case "update":
                case "delete":
                case "batchtransaction":
                case "bundle":
                case "validatekey":
                case "getpasswordsalts":
                    var requestId = msg["requestId"]?.ToString().ToLower() ?? "";

                    if (string.IsNullOrEmpty(requestId))
                    {
                        // TODO: log warning
                        Console.WriteLine("Missing request id");
                        return;
                    }

                    //var request = this.requests[requestId];
                    if (!_pendingRequests.TryGetValue(requestId, out var request))
                    {
                        // TODO: log warning
                        Console.WriteLine($"Request {requestId} no longer exists!");
                        return;
                    }
                    else if (request.Resolve == null || request.Reject == null)
                    {
                        return;
                    }

                    var response = msg["response"]?.ToString().ToLower() ?? "";
                    var status   = msg["response"]["status"]?.ToString().ToLower() ?? "";

                    var statusCode         = HttpStatusCode.BadRequest;
                    var successfulResponse = !string.IsNullOrEmpty(response) &&
                                             !string.IsNullOrEmpty(status) &&
                                             Enum.TryParse(status, out statusCode) &&
                                             statusCode == HttpStatusCode.OK;

                    if (successfulResponse)
                    {
                        request.Resolve(requestId);
                    }
                    else
                    {
                        request.Reject(requestId, route, statusCode, response);
                    }

                    break;

                default:
                    Console.WriteLine($"Received unknown message from backend: {msg}");
                    break;
                }
            }
            catch (Exception exception)
            {
                _ = _logger.Log($"ERROR - {exception.Message}");
            }
        }