Ejemplo n.º 1
0
        public async Task Run()
        {
            using var _ = _client;
            using var messageBuilder = new MessageBuilder();

            Stream stream = _client.GetStream();

            stream = await HandleInitialMessage(stream, messageBuilder);

            var reader = PipeReader.Create(stream);
            var writer = PipeWriter.Create(stream);

            if (_clientOptions == null) //TODO pfyasu maybe unused when cancel message will be implemented
            {
                return;
            }

            if (_clientOptions.TryGetValue("database", out string databaseName) == false)
            {
                await writer.WriteAsync(messageBuilder.ErrorResponse(
                                            PgSeverity.Fatal,
                                            PgErrorCodes.ConnectionFailure,
                                            "Failed to connect to database",
                                            "Missing database name in the connection string"), _token);

                return;
            }

            var database = await _databasesLandlord.TryGetOrCreateResourceStore(databaseName);

            if (database == null)
            {
                await writer.WriteAsync(messageBuilder.ErrorResponse(
                                            PgSeverity.Fatal,
                                            PgErrorCodes.ConnectionFailure,
                                            "Failed to connect to database",
                                            $"Database '{databaseName}' does not exist"), _token);

                return;
            }

            string username = null;

            try
            {
                username = _clientOptions["user"];

                using var transaction = new PgTransaction(database, new MessageReader(), username);

                if (_serverCertificate != null)
                {
                    // Authentication is required only when running in secured mode

                    await writer.WriteAsync(messageBuilder.AuthenticationCleartextPassword(), _token);

                    var authMessage = await transaction.MessageReader.GetUninitializedMessage(reader, _token);

                    await authMessage.Init(transaction.MessageReader, reader, _token);

                    await authMessage.Handle(transaction, messageBuilder, reader, writer, _token);
                }
                else
                {
                    await writer.WriteAsync(messageBuilder.AuthenticationOk(), _token);
                }

                await writer.WriteAsync(messageBuilder.ParameterStatusMessages(PgConfig.ParameterStatusList), _token);

                await writer.WriteAsync(messageBuilder.BackendKeyData(_processId, _identifier), _token);

                await writer.WriteAsync(messageBuilder.ReadyForQuery(transaction.State), _token);

                while (_token.IsCancellationRequested == false)
                {
                    var message = await transaction.MessageReader.GetUninitializedMessage(reader, _token);

                    try
                    {
                        await message.Init(transaction.MessageReader, reader, _token);

                        await message.Handle(transaction, messageBuilder, reader, writer, _token);
                    }
                    catch (PgErrorException e)
                    {
                        await message.HandleError(e, transaction, messageBuilder, writer, _token);
                    }
                }
            }
            catch (PgFatalException e)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info($"{e.Message} (fatal pg error code {e.ErrorCode}). {GetSourceConnectionDetails(username)}", e);
                }

                await writer.WriteAsync(messageBuilder.ErrorResponse(
                                            PgSeverity.Fatal,
                                            e.ErrorCode,
                                            e.Message,
                                            e.ToString()), _token);
            }
            catch (PgErrorException e)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info($"{e.Message} (pg error code {e.ErrorCode}). {GetSourceConnectionDetails(username)}", e);
                }

                // Shouldn't get to this point, PgErrorExceptions shouldn't be fatal
                await writer.WriteAsync(messageBuilder.ErrorResponse(
                                            PgSeverity.Error,
                                            e.ErrorCode,
                                            e.Message,
                                            e.ToString()), _token);
            }
            catch (PgTerminateReceivedException)
            {
                // Terminate silently
            }
            catch (QueryParser.ParseException e)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info("Invalid RQL query", e);
                }

                try
                {
                    await writer.WriteAsync(messageBuilder.ErrorResponse(
                                                PgSeverity.Error,
                                                PgErrorCodes.InvalidSqlStatementName,
                                                e.ToString()), _token);
                }
                catch (Exception)
                {
                    // ignored
                }
            }
            catch (Exception e)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info($"Unexpected internal pg error. {GetSourceConnectionDetails(username)}", e);
                }

                try
                {
                    await writer.WriteAsync(messageBuilder.ErrorResponse(
                                                PgSeverity.Fatal,
                                                PgErrorCodes.InternalError,
                                                e.ToString()), _token);
                }
                catch (Exception)
                {
                    // ignored
                }
            }
        }