func StartListener(protoAddr string, app types.Application) (net.Listener, error) { parts := strings.SplitN(protoAddr, "://", 2) proto, addr := parts[0], parts[1] ln, err := net.Listen(proto, addr) if err != nil { return nil, err } // A goroutine to accept a connection. go func() { // semaphore := make(chan struct{}, maxNumberConnections) for { // semaphore <- struct{}{} // Accept a connection fmt.Println("Waiting for new connection...") conn, err := ln.Accept() if err != nil { Exit("Failed to accept connection") } else { fmt.Println("Accepted a new connection") } appContext := app.Open() closeConn := make(chan error, 2) // Push to signal connection closed responses := make(chan types.Response, 1000) // A channel to buffer responses // Read requests from conn and deal with them go handleRequests(appContext, closeConn, conn, responses) // Pull responses from 'responses' and write them to conn. go handleResponses(closeConn, responses, conn) go func() { // Wait until signal to close connection errClose := <-closeConn if errClose != nil { fmt.Printf("Connection error: %v\n", errClose) } else { fmt.Println("Connection was closed.") } // Close the connection err := conn.Close() if err != nil { fmt.Printf("Error in closing connection: %v\n", err) } // Close the AppContext err = appContext.Close() if err != nil { fmt.Printf("Error in closing app context: %v\n", err) } // <-semaphore }() } }() return ln, nil }
func handleRequest(app types.Application, req types.Request, responses chan<- types.Response) { switch req := req.(type) { case types.RequestEcho: responses <- types.ResponseEcho{req.Message} case types.RequestFlush: responses <- types.ResponseFlush{} case types.RequestInfo: data := app.Info() responses <- types.ResponseInfo{data} case types.RequestSetOption: logStr := app.SetOption(req.Key, req.Value) responses <- types.ResponseSetOption{logStr} case types.RequestAppendTx: code, result, logStr := app.AppendTx(req.TxBytes) responses <- types.ResponseAppendTx{code, result, logStr} case types.RequestCheckTx: code, result, logStr := app.CheckTx(req.TxBytes) responses <- types.ResponseCheckTx{code, result, logStr} case types.RequestGetHash: hash, logStr := app.GetHash() responses <- types.ResponseGetHash{hash, logStr} case types.RequestQuery: result, logStr := app.Query(req.QueryBytes) responses <- types.ResponseQuery{result, logStr} default: responses <- types.ResponseException{"Unknown request"} } }
func handleRequest(app types.Application, req *types.Request, responses chan<- *types.Response) { switch req.Type { case types.MessageType_Echo: responses <- types.ResponseEcho(string(req.Data)) case types.MessageType_Flush: responses <- types.ResponseFlush() case types.MessageType_Info: data := app.Info() responses <- types.ResponseInfo(data) case types.MessageType_SetOption: logStr := app.SetOption(req.Key, req.Value) responses <- types.ResponseSetOption(logStr) case types.MessageType_AppendTx: code, result, logStr := app.AppendTx(req.Data) responses <- types.ResponseAppendTx(code, result, logStr) case types.MessageType_CheckTx: code, result, logStr := app.CheckTx(req.Data) responses <- types.ResponseCheckTx(code, result, logStr) case types.MessageType_Commit: hash, logStr := app.Commit() responses <- types.ResponseCommit(hash, logStr) case types.MessageType_Query: code, result, logStr := app.Query(req.Data) responses <- types.ResponseQuery(code, result, logStr) default: responses <- types.ResponseException("Unknown request") } }