func ProcRecordResult( handler *coreprocessing.Handler, inIns *coreprocessing.CoreInstruction, outIns *coreprocessing.CoreInstruction) []*coreprocessing.CoreInstruction { // var result []*coreprocessing.CoreInstruction if answer, _ := outIns.GetAnswer(); (*answer).Error.Code == 0 { if srcCmd, hasCmd := inIns.GetCommand(); hasCmd { rpcManager := coreprocessing.NewRpcServerManager() taskId := (*srcCmd).Params.Task if targetCidPtr := rpcManager.ResultDirectionDict.Get(taskId); targetCidPtr != nil { // check client group if handler.StateCheker.ClientInGroup(*targetCidPtr, connectionsupport.GroupConnectionWsClient) { cmd := transport.NewCommandWithParams( 0, "result", transport.MethodParams{ Cid: *targetCidPtr, Task: taskId, Json: (*srcCmd).Params.Json}) clientIns := coreprocessing.NewCoreInstruction(coreprocessing.TypeInstructionSetResult) clientIns.SetCommand(cmd) result = make([]*coreprocessing.CoreInstruction, 1) result[0] = clientIns } else { rpcManager.ResultBufferDict.Set(taskId, (*srcCmd).Params.Json) } } else { rllogger.Outputf(rllogger.LogError, "Processing pass for: %s", srcCmd) } } } return result }
func (server *ConnectionServer) connectionReadProcessing( connection net.Conn, workerManager *coresupport.CoreWorkerManager, label string) { // defer connection.Close() buffer := bufio.NewReader(connection) wait := true hasAnswerChannel := false connectionData := server.connectionDataManager.NewConnection() // TODO: rllogger.LogDebug rllogger.Outputf(rllogger.LogInfo, "new connection %s", connectionData.Cid) sizeBuffer := (*server).option.BufferSize for wait { // lineData, _, err := buffer.ReadLine() if err == nil { server.stat.SendMsg("income_data_size", len(lineData)) if cmd, err := transport.ParseCommand(&lineData); err == nil { workerManager.Processing(cmd, server.connectionDataManager, connectionData) if !hasAnswerChannel { // create backChannel := make(chan coreprocessing.CoreInstruction, sizeBuffer) // dont like closure, only realy need go connectionWriteProcessing( connection, &backChannel, (*server).connectionDataManager, server.stat, label) workerManager.AppendBackChannel(connectionData, &backChannel) hasAnswerChannel = true } } else { server.stat.SendMsg("bad_command_count", 1) rllogger.Outputf(rllogger.LogWarn, "connection %s bad command: %s", connectionData.Cid, err) } } else { // has error if err == io.EOF { // client break connection workerManager.BrokenConnection(connectionData) rllogger.Outputf(rllogger.LogDebug, "broken connection %s", connectionData.Cid) } wait = false } } server.stat.DelOneMsg("connection_count") // remove from methods if server.connectionDataManager.ClientInGroup(connectionData.Cid, connectionsupport.GroupConnectionServer) { cidMethods := coreprocessing.NewRpcServerManager() cidMethods.Remove(connectionData.Cid) server.stat.DelOneMsg("count_connection_server") } else { server.stat.DelOneMsg("count_connection_client") } workerManager.RemoveBackChannel(connectionData) server.connectionDataManager.RemoveConnection(connectionData.Cid) // TODO: rllogger.LogDebug rllogger.Outputf(rllogger.LogInfo, "out connection %s", connectionData.Cid) }
// main method for client routing to server methods func ProcRouteRpc(handler *coreprocessing.Handler, inIns *coreprocessing.CoreInstruction) *coreprocessing.CoreInstruction { var answer *transport.Answer var errStr string var answerData string insType := coreprocessing.TypeInstructionSkip errCode := 0 // check methods if cmd, exists := inIns.GetCommand(); exists { rpcManager := coreprocessing.NewRpcServerManager() variants := rpcManager.GetCidVariants((*cmd).Method) if len(variants) > 0 { var freeCid string for _, serverCid := range variants { if !handler.StateCheker.ClientBusy(serverCid) { freeCid = serverCid break } } if len(freeCid) > 0 { data := RpcAnswerData{ Cid: freeCid, Task: handler.TaskIdGenerator.CreateTaskId()} // TODO: to debug rllogger.Outputf(rllogger.LogInfo, "rpc call: '%s()' -> %s", (*cmd).Method, data) if strData, err := json.Marshal(data); err == nil { answerData = string(strData) rpcManager.ResultDirectionDict.Set(data.Task, (*inIns).Cid) } else { errCode = transport.ErrorCodeInternalProblem errStr = fmt.Sprintf("Error dump %T: '%s'", data, err) } } else { errCode = transport.ErrorCodeAllServerBusy errStr = fmt.Sprintf("All server busy for method '%s'.", (*cmd).Method) } } else { errCode = transport.ErrorCodeRemouteMethodNotExists errStr = fmt.Sprintf("Method '%s' unregistred or workers lost.", (*cmd).Method) } } else { errCode = transport.ErrorCodeCommandFormatWrong errStr = "Command is empty." } if errCode > 0 { insType = coreprocessing.TypeInstructionProblem answer = inIns.MakeErrAnswer(errCode, errStr) } else { insType = coreprocessing.TypeInstructionOk answer = inIns.MakeOkAnswer(answerData) } result := coreprocessing.NewCoreInstruction(insType) result.SetAnswer(answer) return result }
func ProcRegistration(handler *coreprocessing.Handler, inIns *coreprocessing.CoreInstruction) *coreprocessing.CoreInstruction { insType := coreprocessing.TypeInstructionSkip var answer *transport.Answer var result *coreprocessing.CoreInstruction var resultChanges *connectionsupport.StateChanges var errStr string errCode := 0 if cmd, exists := inIns.GetCommand(); exists { info := ClientInfo{} if loadErr := json.Unmarshal([]byte((*cmd).Params.Json), &info); loadErr == nil { if (*handler).StateCheker.IsAuth(inIns.Cid) { // TODO: need implimentation for replace current cid to old switch info.Group { case connectionsupport.GroupConnectionClient: { changes := connectionsupport.StateChanges{ ChangeType: connectionsupport.StateChangesTypeGroup, ConnectionClientGroup: connectionsupport.GroupConnectionClient} resultChanges = &changes answer = inIns.MakeOkAnswer( fmt.Sprintf("{\"ok\": true, \"cid\": \"%s\"}", inIns.Cid)) } case connectionsupport.GroupConnectionServer: { dict := coreprocessing.NewMethodInstructionDict() methodsCount := dict.RegisterClientMethods(info.Methods...) rpcManager := coreprocessing.NewRpcServerManager() rpcManager.Append(inIns.Cid, &(info.Methods)) answer = inIns.MakeOkAnswer( fmt.Sprintf( "{\"methods_count\": %d, \"ok\": true, \"cid\": \"%s\"}", methodsCount, inIns.Cid)) changes := connectionsupport.StateChanges{ ChangeType: connectionsupport.StateChangesTypeGroup, ConnectionClientGroup: connectionsupport.GroupConnectionServer} resultChanges = &changes } case connectionsupport.GroupConnectionWsClient: { // denied errCode = transport.ErrorCodeAccessDenied errStr = "Web-socket client don't accepted on simple TCP socket." } default: { errCode = transport.ErrorCodeUnexpectedValue errStr = "Unknown group, see the protocol specification." } } } else { errCode = transport.ErrorCodeAccessDenied errStr = "Access denied." } } else { errCode = transport.ErrorCodeMethodParamsFormatWrong errStr = fmt.Sprint(loadErr) } } else { errCode = transport.ErrorCodeCommandFormatWrong errStr = "Command is empty." } if errCode > 0 { insType = coreprocessing.TypeInstructionProblem answer = inIns.MakeErrAnswer(errCode, errStr) } else { insType = coreprocessing.TypeInstructionOk } result = coreprocessing.NewCoreInstruction(insType) result.SetAnswer(answer) result.StateChanges = resultChanges return result }
func TestRegistratioAddGroupServer(t *testing.T) { option := options.SysOption{ Statistic: false} stat := statistic.NewStatistic(option) methodName := "test_test" cid := "27d90e5e-0000000000000011-1" handler := coreprocessing.NewHandler(1, option, stat) cheker := forTestConnectionStateCheck{Auth: true} handler.StateCheker = &cheker inIns := coreprocessing.NewCoreInstruction(coreprocessing.TypeInstructionReg) cmd := transport.NewCommand(0, cid, "registration", "") (*cmd).Params.Json = fmt.Sprintf( "{\"methods\": [\"%s\"], \"group\": %d}", methodName, connectionsupport.GroupConnectionServer) inIns.SetCommand(cmd) outIns := coremethods.ProcRegistration(handler, inIns) if answer, exists := outIns.GetAnswer(); exists { err := (*answer).Error.Code if err > 0 { t.Error("Answer with problem, %s", (*answer).Error) } else { stCh := (*outIns).StateChanges if stCh != nil { if (*stCh).ChangeType == connectionsupport.StateChangesTypeGroup { if (*stCh).ConnectionClientGroup == connectionsupport.GroupConnectionServer { cidMethods := coreprocessing.NewRpcServerManager() cidList := cidMethods.GetCidVariants(methodName) if len(cidList) > 0 { exists := false for _, variant := range cidList { t.Logf("%s == %s ?", cid, variant) if variant == cid { exists = true } } if exists { // check answer if answer, exists := outIns.GetAnswer(); exists { if (*answer).Result != "{\"methods_count\": 1, \"ok\": true}" { t.Errorf("Incorrect answer data: %s", (*answer).Result) } } else { t.Error("Answer data is empty.") } } else { t.Errorf("Not found cid '%s' for method '%s'.", cid, methodName) } } else { t.Errorf("New cid '%s' lost for method '%s'.", cid, methodName) } } else { t.Errorf("Incorrect connection group %s in changes.", (*stCh).ConnectionClientGroup) } } else { t.Errorf("Type of changes is not a {}", connectionsupport.StateChangesTypeGroup) } } else { t.Error("Changes empty.") } } } else { t.Errorf("Empty answer to %s.", *cmd) } }