func connectionHandler( server *RlServer, toCoreBuffer *chan protocol.CoreMsg, connection net.Conn, label string, dispatcher *AnswerDispatcher, stat *RlStatistic) { // server and service connections defer connection.Close() options := server.GetOption() connectionContext := helpers.ConnectionContext{} buffer := bufio.NewReader(connection) wait := true answerWriterActive := false var answer *string answerBuffer := make(chan protocol.ServerCmd, options.BufferSize) localConnectionInfo := newConnectionInfo(label) for wait { line, _, err := buffer.ReadLine() answer = nil if err != nil { if err == io.EOF { // client break connection localConnectionInfo.SetActive(false) if cid, exists := connectionContext.GetCid(); exists { dispatcher.RemoveChannel(cid, true) } } wait = false } else { stat.Append(StatIncomeDataSize, len(line)) cmd, err := protocol.NewClientCmd(&line) if err != nil { wait = false rllogger.Outputf( rllogger.LogWarn, "Incorrect command from %s error: %s", label, err) answer = protocol.FastErrorAnswer(err, protocol.ErrCodeFormatProblem) } else { if cmd.RequiredClose() { wait = false rllogger.Outputf(rllogger.LogInfo, "close command from %s", label) } else { // check auth if cmd.RequiredAuth() && !connectionContext.IsAuth() { answer = protocol.FastErrorAnswer( "Access denied!", protocol.ErrCodeAccessDenied) } else { // try get fast handler if exists, handler := cmd.GetFastHandler(); exists { if newAnswer, err := handler(cmd, &connectionContext, options); err != nil { rllogger.Outputf( rllogger.LogWarn, "Client: %s target: %d Handler error: %s", label, cmd.Target, err) answer = protocol.FastErrorAnswer(err, protocol.ErrCodeProtocolProblem) } else { if dataPtr, dumpErr := newAnswer.Dump(); dumpErr != nil { answer = protocol.FastErrorAnswer(err, protocol.ErrCodeImplementationProblem) } else { answer = dataPtr if exists, contextUpdater := newAnswer.GetContextUpdater(); exists { contextUpdater.Update(&connectionContext) rllogger.Outputf( rllogger.LogDebug, "-> %s context updated: %s", label, connectionContext) } } } } else { clientGroup := connectionContext.GetClientGroup() msg, convertError := protocol.NewCoreMsg(clientGroup, cmd) if convertError != nil { rllogger.Outputf( rllogger.LogWarn, "Msg create error: %s from %s", convertError, label) answer = protocol.FastErrorAnswer( convertError, protocol.ErrCodeProtocolProblem) } else { *toCoreBuffer <- *msg if !answerWriterActive { answerWriterActive = true // this channel to dispatcher dispatcher.AddChannel((*msg).Cid, &answerBuffer) // run async answer writer go conntectionWriteAnswer( connection, &answerBuffer, localConnectionInfo, stat) } } } } } } // write sync handler answer if answer != nil { writen, err := connection.Write([]byte(*answer)) if err != nil { rllogger.Outputf( rllogger.LogError, "Can't send answer to %s error: %s", label, err) } else { stat.Append(StatOutcomeDataSize, writen) } } } } //not need "close(answerBuffer)" dispatcher do it stat.Append(StatConnectionCount, -1) server.ChangeConnectionCount(-1) }