func main() { // Parse flags and arguments, print usage message on error. flag.Usage = func() { fmt.Fprintf(os.Stderr, ` Usage: %s url [url ...] Receive messages from all the listed URLs concurrently and print them. `, os.Args[0]) flag.PrintDefaults() } flag.Parse() urls := flag.Args() // Non-flag arguments are URLs to receive from if len(urls) == 0 { flag.Usage() fmt.Fprintf(os.Stderr, "No URL provided") os.Exit(1) } duration := time.Duration(*timeout) * time.Second if duration == 0 { duration = time.Duration(math.MaxInt64) // Not forever, but 290 years is close enough. } if *count == 0 { *count = math.MaxInt64 } // Create a goroutine for each URL that receives messages and sends them to // the messages channel. main() receives and prints them. messages := make(chan proton.Message) // Channel for messages from goroutines to main() stop := make(chan struct{}) // Closing this channel means the program is stopping. var wait sync.WaitGroup // Used by main() to wait for all goroutines to end. wait.Add(len(urls)) // Wait for one goroutine per URL. // Arrange to close all connections on exit connections := make([]*messaging.Connection, len(urls)) defer func() { for _, c := range connections { if c != nil { c.Close() } } }() for i, urlStr := range urls { debug.Printf("Connecting to %s", urlStr) go func(urlStr string) { defer wait.Done() // Notify main() that this goroutine is done. url, err := proton.ParseURL(urlStr) // Like net/url.Parse() but with AMQP defaults. fatalIf(err) // Open a standard Go net.Conn for the AMQP connection conn, err := net.Dial("tcp", url.Host) // Note net.URL.Host is actually "host:port" fatalIf(err) pc, err := messaging.Connect(conn) // This is our AMQP connection. fatalIf(err) connections[i] = pc // For convenience a proton.Connection provides a DefaultSession() // pc.Receiver() is equivalent to pc.DefaultSession().Receiver() r, err := pc.Receiver(url.Path) fatalIf(err) for { var m proton.Message select { // Receive a message or stop. case m = <-r.Receive: case <-stop: // The program is stopping. return } select { // Send m to main() or stop case messages <- m: // Send m to main() case <-stop: // The program is stopping. return } } }(urlStr) } info.Printf("Listening") // time.After() returns a channel that will close when the timeout is up. timer := time.After(duration) // main() prints each message and checks for count or timeout being exceeded. for i := int64(0); i < *count; i++ { select { case m := <-messages: debug.Print(formatMessage{m}) case <-timer: // Timeout has expired i = 0 } } info.Printf("Received %d messages", *count) close(stop) // Signal all goroutines to stop. wait.Wait() // Wait for all goroutines to finish. }
func main() { // Parse flags and arguments, print usage message on error. flag.Usage = func() { fmt.Fprintf(os.Stderr, ` Usage: %s url [url ...] Send messages to all the listed URLs concurrently. To each URL, send the string "path-n" where n is the message number. `, os.Args[0]) flag.PrintDefaults() } flag.Parse() urls := flag.Args() // Non-flag arguments are URLs to receive from if len(urls) == 0 { flag.Usage() fmt.Fprintf(os.Stderr, "No URL provided\n") os.Exit(1) } if *count == 0 { *count = math.MaxInt64 } // Create a channel to receive all the acknowledgements acks := make(chan Ack) // Create a goroutine for each URL that sends messages. var wait sync.WaitGroup // Used by main() to wait for all goroutines to end. wait.Add(len(urls)) // Wait for one goroutine per URL. // Arrange to close all connections on exit connections := make([]*messaging.Connection, len(urls)) defer func() { for _, c := range connections { c.Close() } }() for i, urlStr := range urls { url, err := proton.ParseURL(urlStr) // Like net/url.Parse() but with AMQP defaults. fatalIf(err) debug.Printf("Connecting to %v", url) // Open a standard Go net.Conn for the AMQP connection conn, err := net.Dial("tcp", url.Host) // Note net.URL.Host is actually "host:port" fatalIf(err) pc, err := messaging.Connect(conn) // This is our AMQP connection using conn. fatalIf(err) connections[i] = pc // Start a goroutine to send to urlStr go func(urlStr string) { defer wait.Done() // Notify main() that this goroutine is done. // FIXME aconway 2015-04-29: sessions, default sessions, senders... // Create a sender using the path of the URL as the AMQP target address s, err := pc.Sender(url.Path) fatalIf(err) for i := int64(0); i < *count; i++ { m := proton.NewMessage() body := fmt.Sprintf("%v-%v", url.Path, i) m.SetBody(body) ack, err := s.Send(m) fatalIf(err) acks <- Ack{ack, body} } }(urlStr) } // Wait for all the acknowledgements expect := int(*count) * len(urls) debug.Printf("Started senders, expect %v acknowledgements", expect) for i := 0; i < expect; i++ { ack, ok := <-acks if !ok { info.Fatalf("acks channel closed after only %d acks\n", i) } d := <-ack.ack debug.Printf("acknowledgement[%v] %v", i, ack.info) if d != messaging.Accepted { info.Printf("Unexpected disposition %v", d) } } info.Printf("Received all %v acknowledgements", expect) wait.Wait() // Wait for all goroutines to finish. }