func main() { flag.Parse() if *jsonFlag { doc, _ := registryEntry.JSON() fmt.Println(string(doc)) os.Exit(0) } log.SetFlags(0) if *debug { log.SetOutput(os.Stdout) } else { log.SetOutput(ioutil.Discard) } validateArgs() openPorts() defer closePorts() exitCh := utils.HandleInterruption() // Wait for the configuration on the options port var bindAddr string for { log.Println("Waiting for configuration...") ip, err := optionsPort.RecvMultipart(0) if err != nil { log.Println("Error receiving IP:", err.Error()) continue } if !runtime.IsValidIP(ip) || !runtime.IsPacket(ip) { continue } bindAddr = string(ip[1]) break } optionsPort.Close() // Data from http handler and data to http handler inCh := make(chan httputils.HTTPResponse) outCh := make(chan HandlerRequest) go func(ctx *zmq.Context, endpoint string) { outPort, err = utils.CreateOutputPort(context, endpoint) utils.AssertError(err) // Map of uuid to requests dataMap := make(map[string]chan httputils.HTTPResponse) // Start listening in/out channels for { select { case data := <-outCh: dataMap[data.Request.Id] = data.ResponseCh ip, _ := httputils.Request2IP(data.Request) outPort.SendMultipart(ip, 0) case resp := <-inCh: if respCh, ok := dataMap[resp.Id]; ok { log.Println("Resolved channel for response", resp.Id) respCh <- resp delete(dataMap, resp.Id) continue } log.Println("Didn't find request handler mapping for a given ID", resp.Id) } } }(context, *outputEndpoint) // Web server goroutine go func() { mux := http.NewServeMux() mux.HandleFunc("/", Handler(outCh)) s := &http.Server{ Handler: mux, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, } ln, err := net.Listen("tcp", bindAddr) if err != nil { log.Println(err.Error()) exitCh <- syscall.SIGTERM return } log.Printf("Starting listening %v", bindAddr) err = s.Serve(ln) if err != nil { log.Println(err.Error()) exitCh <- syscall.SIGTERM return } }() // Process incoming message forever for { ip, err := inPort.RecvMultipart(0) if err != nil { log.Println("Error receiving message:", err.Error()) continue } if !runtime.IsValidIP(ip) { log.Println("Received invalid IP") continue } resp, err := httputils.IP2Response(ip) if err != nil { log.Printf("Error converting IP to response: %s", err.Error()) continue } inCh <- *resp } }
func main() { flag.Parse() if *jsonFlag { doc, _ := registryEntry.JSON() fmt.Println(string(doc)) os.Exit(0) } log.SetFlags(0) if *debug { log.SetOutput(os.Stdout) } else { log.SetOutput(ioutil.Discard) } validateArgs() openPorts() defer closePorts() poller.Add(requestPort, zmq.POLLIN) exitCh := utils.HandleInterruption() err = runtime.SetupShutdownByDisconnect(requestPort, "http-router.in", exitCh) utils.AssertError(err) // Main loop var ( index int = -1 outputIndex int = -1 params url.Values ip [][]byte pLength int = len(pollItems) router *Router = NewRouter() ) for { // Poll sockets log.Println("Polling sockets...") sockets, err := poller.Poll(-1) if err != nil { log.Println("Error polling ports:", err.Error()) os.Exit(1) } for index, s := range sockets { ip, err = s.Socket.RecvMessageBytes(0) if err != nil { log.Printf("Failed to receive data. Error: %s", err.Error()) continue } if !runtime.IsValidIP(ip) { log.Println("Received invalid IP") continue } } // Pattern arrived if index < pLength-1 { // Close pattern socket port = pollItems[index].Socket port.Close() // Resolve corresponding output socket index outputIndex = -1 for i, s := range patternPorts { if s == port { outputIndex = i } } if outputIndex == -1 { log.Printf("Failed to resolve output socket index") continue } // Remove closed socket from polling items pollItems = append(pollItems[:index], pollItems[index+1:]...) pLength -= 1 // Add pattern to router parts := strings.Split(string(ip[1]), " ") method := strings.ToUpper(strings.TrimSpace(parts[0])) pattern := strings.TrimSpace(parts[1]) switch method { case "GET": router.Get(pattern, outputIndex) case "POST": router.Post(pattern, outputIndex) case "PUT": router.Put(pattern, outputIndex) case "DELETE": router.Del(pattern, outputIndex) case "HEAD": router.Head(pattern, outputIndex) case "OPTIONS": router.Options(pattern, outputIndex) default: log.Printf("Unsupported HTTP method %s in pattern %s", method, pattern) } continue } // Request arrive req, err := httputils.IP2Request(ip) if err != nil { log.Printf("Failed to convert IP to request. Error: %s", err.Error()) continue } outputIndex, params = router.Route(req.Method, req.URI) log.Printf("Output index for %s %s: %v (params=%#v)", req.Method, req.URI, outputIndex, params) switch outputIndex { case NotFound: log.Println("Sending Not Found response to FAIL output") resp := &httputils.HTTPResponse{ Id: req.Id, StatusCode: http.StatusNotFound, } ip, _ = httputils.Response2IP(resp) failPort.SendMultipart(ip, 0) case MethodNotAllowed: log.Println("Sending Method Not Allowed response to FAIL output") resp := &httputils.HTTPResponse{ Id: req.Id, StatusCode: http.StatusMethodNotAllowed, } ip, _ = httputils.Response2IP(resp) failPort.SendMultipart(ip, 0) default: for k, values := range params { req.Form[k] = values } ip, _ = httputils.Request2IP(req) successPorts[outputIndex].SendMultipart(ip, 0) } index = -1 } }