func (server *ReaderServer) Start(parentContext context.Context) {
	defer server.waitForExitTimeout()
	logger := logging.GetLoggerFromContext(parentContext)
	poisonCallbacks := base.NewPoisonCallbackStorage()
	server.detectPoisonRecords(poisonCallbacks)
	errCh := make(chan error)
	decryptorData := &common.TranslatorData{
		Keystorage:                  server.keystorage,
		PoisonRecordCallbacks:       poisonCallbacks,
		CheckPoisonRecords:          server.config.DetectPoisonRecords(),
		UseConnectionClientID:       server.config.GetUseClientIDFromConnection(),
		ConnectionClientIDExtractor: server.config.GetGRPCClientIDExtractor(),
	}
	if server.config.IncomingConnectionHTTPString() != "" {
		listener, err := network.Listen(server.config.IncomingConnectionHTTPString())
		if err != nil {
			log.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorTranslatorCantAcceptNewHTTPConnection).
				Errorln("Can't create HTTP listener from specified connection string")
			return
		}
		server.listenerHTTP = listener
		server.startHTTP(parentContext, logger, decryptorData, errCh, listener)
	}
	if server.config.IncomingConnectionGRPCString() != "" {
		listener, err := network.Listen(server.config.IncomingConnectionGRPCString())
		if err != nil {
			log.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorTranslatorCantAcceptNewGRPCConnection).
				Errorln("Can't create gRPC listener from specified connection string")
			return
		}
		server.listenerGRPC = listener
		server.startGRPC(logger, decryptorData, errCh, listener)
	}
	select {
	case <-parentContext.Done():
		break
	case outErr := <-errCh:
		if outErr != nil {
			log.WithError(outErr).Errorln("Can't correctly exit from readerServer component")
		}
		break
	}
	return
}
Start setups gRPC handler or HTTP handler, poison records callbacks and starts listening to connections.
package server
import (
	"context"
	"errors"
	"github.com/cossacklabs/acra/utils"
	"net"
	"os"
	"sync"
	"time"
	"google.golang.org/grpc/credentials"
	"bufio"
	"net/http"
	"github.com/cossacklabs/acra/cmd/acra-translator/common"
	"github.com/cossacklabs/acra/cmd/acra-translator/http_api"
	"github.com/cossacklabs/acra/decryptor/base"
	"github.com/cossacklabs/acra/keystore"
	"github.com/cossacklabs/acra/logging"
	"github.com/cossacklabs/acra/network"
	log "github.com/sirupsen/logrus"
	"go.opencensus.io/trace"
	"google.golang.org/grpc"
)
type ReaderServer struct {
	config                *common.AcraTranslatorConfig
	keystorage            keystore.TranslationKeyStore
	connectionManager     *network.ConnectionManager
	grpcServer            *grpc.Server
	httpDecryptor         *http_api.HTTPConnectionsDecryptor
	waitTimeout           time.Duration
	grpcServerFactory     common.GRPCServerFactory
	backgroundWorkersSync sync.WaitGroup
	listenerHTTP          net.Listener
	listenerGRPC          net.Listener
}
const (
	grpcFilenamePlaceholder = "tmp/acra_translator_grpc"
	httpFilenamePlaceholder = "tmp/acra_translator_http"
)
func NewReaderServer(config *common.AcraTranslatorConfig, keystorage keystore.TranslationKeyStore, grpcServerFactory common.GRPCServerFactory, waitTimeout time.Duration) (server *ReaderServer, err error) {
	return &ReaderServer{
		grpcServerFactory: grpcServerFactory,
		waitTimeout:       waitTimeout,
		config:            config,
		keystorage:        keystorage,
		connectionManager: network.NewConnectionManager(),
	}, nil
}
func (server *ReaderServer) Stop() {
	log.Infoln("Stop accepting new connections")
	server.StopListeners()
	if server.grpcServer != nil {
		server.backgroundWorkersSync.Add(1)
		go func() {
			defer server.backgroundWorkersSync.Done()
			server.grpcServer.GracefulStop()
		}()
	}
	if server.connectionManager.Counter != 0 {
		log.Infof("Wait ending current connections (%v)", server.connectionManager.Counter)
		<-time.NewTimer(server.waitTimeout).C
	}
	log.Infof("Stop all connections that not closed (%v)", server.connectionManager.Counter)
	if server.grpcServer != nil {
		server.grpcServer.Stop()
	}
	if err := server.connectionManager.CloseConnections(); err != nil {
		log.WithField(logging.FieldKeyEventCode, logging.EventCodeErrorCantCloseConnection).WithError(err).Errorln("Took error on closing available connections")
	}
}
func (server *ReaderServer) HandleHTTPConnection(parentContext context.Context, listener net.Listener, connectionString string, processingFunc ProcessingFunc) error {
	logger := logging.GetLoggerFromContext(parentContext)
	if logger == nil {
		logger = log.NewEntry(log.StandardLogger())
	}
	logger = log.WithField("connection_string", connectionString)
	errCh := make(chan error)
	connectionChannel, err := common.AcceptConnections(parentContext, listener, errCh)
	if err != nil {
		logger.WithField(logging.FieldKeyEventCode, logging.EventCodeErrorCantAcceptNewConnections).WithError(err).Errorf("Can't start to handle connection string %v", connectionString)
		return err
	}
	server.backgroundWorkersSync.Add(1)
	go func() {
		defer server.backgroundWorkersSync.Done()
		logger.WithField("connection_string", connectionString).Debugln("Start wrap new connections")
		for {
			var connection net.Conn
			select {
			case connection = <-connectionChannel:
				break
			case <-parentContext.Done():
				if !errors.Is(parentContext.Err(), context.Canceled) {
					logger.WithError(parentContext.Err()).Debugln("Stop wrapping new connections")
				}
				return
			}
			connectionContext := context.TODO()
			wrappedConnection, clientID, err := server.config.ConnectionWrapper.WrapServer(connectionContext, connection)
			if err != nil {
				logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorTranslatorCantWrapConnectionToSS).
					Errorln("Can't wrap new connection")
				if err := connection.Close(); err != nil {
					logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorTranslatorCantCloseConnection).
						Errorln("Can't close connection")
				}
				continue
			}
			logger = logger.WithField("client_id", string(clientID))
			var span *trace.Span
			var ctx context.Context
			if server.config.GetWithConnector() {
				logger.WithField("with_connector", server.config.GetWithConnector()).Debugln("Read trace")
				spanContext, err := network.ReadTrace(wrappedConnection)
				if err != nil {
					log.WithField(logging.FieldKeyEventCode, logging.EventCodeErrorTracingCantReadTrace).WithError(err).Errorln("Can't read trace from AcraConnector")
					return
				}
				ctx, span = trace.StartSpanWithRemoteParent(parentContext, "HandleHTTPConnection", spanContext, server.config.GetTraceOptions()...)
			} else {
				ctx, span = trace.StartSpan(parentContext, "HandleHTTPConnection", server.config.GetTraceOptions()...)
			}
			ctx = logging.SetLoggerToContext(ctx, logger)
			logger.Debugln("Pass wrapped connection to processing function")
			server.backgroundWorkersSync.Add(1)
			go func() {
				defer func() {
					span.End()
					err := wrappedConnection.Close()
					if err != nil {
						logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorTranslatorCantCloseConnection).
							Errorln("Can't close wrapped connection")
					}
					logger.Infoln("Connection closed")
					server.backgroundWorkersSync.Done()
				}()
				if err := server.connectionManager.AddConnection(wrappedConnection); err != nil {
					logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorTranslatorCantHandleHTTPConnection).
						Errorln("Can't add connection to connection manager")
					return
				}
				processingFunc(ctx, clientID, wrappedConnection)
				if err := server.connectionManager.RemoveConnection(wrappedConnection); err != nil {
					logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorTranslatorCantHandleHTTPConnection).
						Errorln("Can't remove connection from connection manager")
				}
			}()
		}
	}()
	var outErr error
	select {
	case <-parentContext.Done():
		outErr = parentContext.Err()
	case outErr = <-errCh:
		if outErr != nil {
			log.WithError(outErr).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorTranslatorCantAcceptNewHTTPConnection).
				Errorln("Error on accepting new connections")
		}
	}
	return outErr
}