/* runReceive receives all messages from a specified queue. */ func runReceive(conn *stompngo.Connection, q int, w *sync.WaitGroup) { ltag := tag + "-runreceive" qns := fmt.Sprintf("%d", q) // queue number id := stompngo.Uuid() // A unique subscription ID d := sngecomm.Dest() + "." + qns ll.Printf("%stag:%s connsess:%s starts id:%s qns:%s d:%s\n", exampid, ltag, conn.Session(), id, qns, d) // Subscribe (use common helper) sc := sngecomm.HandleSubscribe(conn, d, id, sngecomm.AckMode()) ll.Printf("%stag:%s connsess:%s subscribe_done id:%s qns:%s d:%s\n", exampid, ltag, conn.Session(), id, qns, d) // tmr := time.NewTimer(100 * time.Hour) pbc := sngecomm.Pbc() // Print byte count nmsgs := senv.Nmsgs() // Receive loop var md stompngo.MessageData for mc := 1; mc <= nmsgs; mc++ { ll.Printf("%stag:%s connsess:%s chanchek id:%s qns:%s lensc:%d capsc:%d\n", exampid, ltag, conn.Session(), id, qns, len(sc), cap(sc)) select { case md = <-sc: case md = <-conn.MessageData: // Frames RECEIPT or ERROR not expected here ll.Fatalf("%stag:%s connsess:%s send_error qns:%v md:%v", exampid, ltag, conn.Session(), qns, md) // Handle this ...... } if md.Error != nil { ll.Fatalf("%stag:%s connsess:%s receive_error qns:%v error:%v\n", exampid, ltag, conn.Session(), qns, md.Error) } // Process the inbound message ................. ll.Printf("%stag:%s connsess:%s inbound id:%s qns:%s mc:%d\n", exampid, ltag, conn.Session(), id, qns, mc) // Sanity check the message Command, and the queue and message numbers mns := fmt.Sprintf("%d", mc) // string message number if md.Message.Command != stompngo.MESSAGE { ll.Fatalf("%stag:%s connsess:%s bad_frame qns:%s mc:%d md:%v\n", exampid, ltag, conn.Session(), qns, mc, md) } if !md.Message.Headers.ContainsKV("qnum", qns) || !md.Message.Headers.ContainsKV("msgnum", mns) { ll.Fatalf("%stag:%s connsess:%s dirty_message qns:%v msgnum:%v md:%v", exampid, tag, conn.Session(), qns, mns, md) // Handle this ...... } sl := len(md.Message.Body) if pbc > 0 { sl = pbc if len(md.Message.Body) < sl { sl = len(md.Message.Body) } } ll.Printf("%stag:%s connsess:%s runReceive_recv_message id:%s body:%s qns:%s msgnum:%s\n", exampid, ltag, conn.Session(), id, string(md.Message.Body[0:sl]), qns, md.Message.Headers.Value("msgnum")) // Handle ACKs if needed if sngecomm.AckMode() != "auto" { ah := stompngo.Headers{} sngecomm.HandleAck(conn, ah, id) } if mc == nmsgs { break } if rw { dt := time.Duration(sngecomm.ValueBetween(min, max, rf)) ll.Printf("%stag:%s connsess:%s recv_stagger dt:%v qns:%s mc:%d\n", exampid, ltag, conn.Session(), dt, qns, mc) tmr.Reset(dt) _ = <-tmr.C runtime.Gosched() } } // Unsubscribe sngecomm.HandleUnsubscribe(conn, d, id) ll.Printf("%stag:%s connsess:%s runRecieve_ends id:%s qns:%s\n", exampid, ltag, conn.Session(), id, qns) w.Done() }
func recv(conn *stompngo.Connection, s int) { ltag := tag + "-recv" ll.Printf("%stag:%s connsess:%s receiver_starts s:%d\n", exampid, ltag, conn.Session(), s) // Setup Headers ... id := stompngo.Uuid() // Use package convenience function for unique ID d := sngecomm.Dest() ackMode = sngecomm.AckMode() // get ack mode pbc := sngecomm.Pbc() // Print byte count sc := sngecomm.HandleSubscribe(conn, d, id, ackMode) // Receive loop. mc := 0 var md stompngo.MessageData for { select { case md = <-sc: // Read a messagedata struct, with a MESSAGE frame case md = <-conn.MessageData: // Read a messagedata struct, with a ERROR/RECEIPT frame // Frames RECEIPT or ERROR not expected here ll.Fatalf("%stag:%s connsess:%s bad_frame md:%v", exampid, ltag, conn.Session(), md) // Handle this ...... } // mc++ if md.Error != nil { ll.Fatalf("%stag:%s connsess:%s error_read error:%v", exampid, ltag, conn.Session(), md.Error) // Handle this ...... } ll.Printf("%stag:%s connsess:%s received_message s:%d id:%s mc:%d\n", exampid, ltag, conn.Session(), s, id, mc) if pbc > 0 { maxlen := pbc if len(md.Message.Body) < maxlen { maxlen = len(md.Message.Body) } ss := string(md.Message.Body[0:maxlen]) ll.Printf("%stag:%s connsess:%s payload body:%s\n", exampid, tag, conn.Session(), ss) } // time.Sleep(3 * time.Second) // A very arbitrary number // time.Sleep(500 * time.Millisecond) // A very arbitrary number runtime.Gosched() time.Sleep(1500 * time.Millisecond) // A very arbitrary number runtime.Gosched() if ackMode != "auto" { sngecomm.HandleAck(conn, md.Message.Headers, id) ll.Printf("%stag:%s connsess:%s ack_complete s:%d id:%s mc:%d\n", exampid, ltag, conn.Session(), s, id, mc) } runtime.Gosched() } }
// Connect to a STOMP broker, receive some messages and disconnect. func main() { st := time.Now() // Standard example connect sequence // Use AMQ port here n, conn, e := sngecomm.CommonConnect(exampid, tag, ll) if e != nil { ll.Fatalf("%stag:%s connsess:%s main_on_connect error:%v", exampid, tag, sngecomm.Lcs, e.Error()) // Handle this ...... } pbc := sngecomm.Pbc() // Print byte count // Setup Headers ... id := stompngo.Uuid() // Use package convenience function for unique ID d := "jms.queue.exampleQueue" sc := sngecomm.HandleSubscribe(conn, d, id, "auto") ll.Printf("%stag:%s connsess:%s stomp_subscribe_complete\n", exampid, tag, conn.Session()) // var md stompngo.MessageData // Read data from the returned channel for i := 1; i <= nmsgs; i++ { select { case md = <-sc: case md = <-conn.MessageData: // Frames RECEIPT or ERROR not expected here ll.Fatalf("%stag:%s connsess:%s bad_frame error:%v", exampid, tag, conn.Session(), e.Error()) // Handle this ...... } ll.Printf("%stag:%s connsess:%s channel_read_complete\n", exampid, tag, conn.Session()) // MessageData has two components: // a) a Message struct // b) an Error value. Check the error value as usual if md.Error != nil { ll.Fatalf("%stag:%s connsess:%s error_read error:%v", exampid, tag, conn.Session(), e.Error()) // Handle this ...... } ll.Printf("%stag:%s connsess:%s frame_type cmd:%s\n", exampid, tag, conn.Session(), md.Message.Command) if md.Message.Command != stompngo.MESSAGE { ll.Fatalf("%stag:%s connsess:%s error_frame_type error:%v", exampid, tag, conn.Session(), e.Error()) // Handle this ...... } wh := md.Message.Headers for j := 0; j < len(wh)-1; j += 2 { ll.Printf("%stag:%s connsess:%s Header:%s:%s\n", exampid, tag, conn.Session(), wh[j], wh[j+1]) } if pbc > 0 { maxlen := pbc if len(md.Message.Body) < maxlen { maxlen = len(md.Message.Body) } ss := string(md.Message.Body[0:maxlen]) ll.Printf("%stag:%s connsess:%s payload body:%s\n", exampid, tag, conn.Session(), ss) } } // sngecomm.HandleUnsubscribe(conn, d, id) ll.Printf("%stag:%s connsess:%s unsubscribe_complete\n", exampid, tag, conn.Session()) // Standard example disconnect sequence e = sngecomm.CommonDisconnect(n, conn, exampid, tag, ll) if e != nil { ll.Fatalf("%stag:%s connsess:%s main_disconnect error:%v", exampid, tag, conn.Session(), e.Error()) // Handle this ...... } ll.Printf("%stag:%s connsess:%s main_elapsed:%v\n", exampid, tag, conn.Session(), time.Now().Sub(st)) }
// Connect to a STOMP broker, receive some messages, ACK them, and disconnect. func main() { st := time.Now() // Standard example connect sequence n, conn, e := sngecomm.CommonConnect(exampid, tag, ll) if e != nil { ll.Fatalf("%stag:%s connsess:%s main_on_connect error:%v", exampid, tag, sngecomm.Lcs, e.Error()) // Handle this ...... } pbc := sngecomm.Pbc() // Print byte count // *NOTE* your application functionaltiy goes here! // With Stomp, you must SUBSCRIBE to a destination in order to receive. // Subscribe returns a channel of MessageData struct. // Here we use a common utility routine to handle the differing subscribe // requirements of each protocol level. d := senv.Dest() id := stompngo.Uuid() sc := sngecomm.HandleSubscribe(conn, d, id, "client") ll.Printf("%stag:%s connsess:%s main_subscribe_complete\n", exampid, tag, conn.Session()) // Read data from the returned channel var md stompngo.MessageData for i := 1; i <= senv.Nmsgs(); i++ { select { case md = <-sc: case md = <-conn.MessageData: // Frames RECEIPT or ERROR not expected here ll.Fatalf("%stag:%s connsess:%s main_channel_frame error:%v", exampid, tag, conn.Session(), e.Error()) // Handle this ...... } ll.Printf("%stag:%s connsess:%s main_channel_read_complete\n", exampid, tag, conn.Session()) // MessageData has two components: // a) a Message struct // b) an Error value. Check the error value as usual if md.Error != nil { ll.Fatalf("%stag:%s connsess:%s main_channel_read error:%v", exampid, tag, conn.Session(), e.Error()) // Handle this ...... } // ll.Printf("%stag:%s connsess:%s frame_type:%v\n", exampid, tag, conn.Session(), md.Message.Command) if md.Message.Command != stompngo.MESSAGE { ll.Fatalf("%stag:%s connsess:%s bad_frame frame:%v", exampid, tag, conn.Session(), md.Message.Command) // Handle this ...... } wh := md.Message.Headers for j := 0; j < len(wh)-1; j += 2 { ll.Printf("%stag:%s connsess:%s header:%s:%s\n", exampid, tag, conn.Session(), wh[j], wh[j+1]) } if pbc > 0 { maxlen := pbc if len(md.Message.Body) < maxlen { maxlen = len(md.Message.Body) } ss := string(md.Message.Body[0:maxlen]) ll.Printf("%stag:%s connsess:%s message_payload body:%s\n", exampid, tag, conn.Session(), ss) } // ACK the message just received. // Agiain we use a utility routine to handle the different requirements // of the protocol versions. sngecomm.HandleAck(conn, md.Message.Headers, id) ll.Printf("%stag:%s connsess:%s ack_complete\n", exampid, tag, conn.Session()) } // It is polite to unsubscribe, although unnecessary if a disconnect follows. // Again we use a utility routine to handle the different protocol level // requirements. sngecomm.HandleUnsubscribe(conn, d, id) ll.Printf("%stag:%s connsess:%s stomp_unsubscribe_complete\n", exampid, tag, conn.Session()) // Standard example disconnect sequence e = sngecomm.CommonDisconnect(n, conn, exampid, tag, ll) if e != nil { ll.Fatalf("%stag:%s connsess:%s disconnect error:%v", exampid, tag, conn.Session(), e.Error()) // Handle this ...... } ll.Printf("%stag:%s connsess:%s main_elapsed:%v\n", exampid, tag, conn.Session(), time.Now().Sub(st)) }
// A forever reader. func main() { st := time.Now() sngecomm.ShowRunParms(exampid) // Standard example connect sequence var e error n, conn, e = sngecomm.CommonConnect(exampid, tag, ll) if e != nil { if conn != nil { ll.Printf("%stag:%s connsess:%s Connect Response headers:%v body%s\n", exampid, tag, conn.Session(), conn.ConnectResponse.Headers, string(conn.ConnectResponse.Body)) } ll.Fatalf("%stag:%s connsess:%s main_on_connect error:%v", exampid, tag, sngecomm.Lcs, e.Error()) // Handle this ...... } //** qn := 1 ltag := tag + "-receiver" id := stompngo.Uuid() // A unique subscription ID d := sngecomm.Dest() ll.Printf("%stag:%s connsess:%s queue_info id:%v d:%v qnum:%v\n", exampid, ltag, conn.Session(), id, d, qn) // Subscribe sc := sngecomm.HandleSubscribe(conn, d, id, sngecomm.AckMode()) ll.Printf("%stag:%s connsess:%s subscribe_complete id:%v d:%v qnum:%v\n", exampid, ltag, conn.Session(), id, d, qn) // var md stompngo.MessageData // Receive loop mc := 1 for { ll.Println("========================== ", "Expecting Message:", mc, "==========================") select { case md = <-sc: case md = <-conn.MessageData: // A RECEIPT or ERROR frame is unexpected here ll.Fatalf("%stag:%s connsess:%s bad_frame qnum:%v headers:%v body:%s", exampid, tag, conn.Session(), qn, md.Message.Headers, md.Message.Body) // Handle this ...... } if md.Error != nil { ll.Fatalf("%stag:%s connsess:%s recv_error qnum:%v error:%v", exampid, tag, conn.Session(), qn, md.Error) // Handle this ...... } ll.Printf("%stag:%s connsess:%s next_frame mc:%v command:%v headers:%v body:%v\n", exampid, tag, conn.Session(), mc, md.Message.Command, md.Message.Headers, string(md.Message.Body)) // Handle this ...... mc++ } //** // Standard example disconnect sequence e = sngecomm.CommonDisconnect(n, conn, exampid, tag, ll) if e != nil { ll.Fatalf("%stag:%s connsess:%s main_on_disconnect error:%v", exampid, tag, conn.Session(), e.Error()) // Handle this ...... } sngecomm.ShowStats(exampid, tag, conn) ll.Printf("%stag:%s connsess:%s main_elapsed:%v\n", exampid, tag, conn.Session(), time.Now().Sub(st)) }
// Receive messages from a particular queue func receiver(conn *stompngo.Connection, qn, nmsgs int) { ltag := tag + "-receiver" qns := fmt.Sprintf("%d", qn) // queue number ll.Printf("%stag:%s connsess:%s starts qns:%d nmsgs:%d\n", exampid, ltag, conn.Session(), qn, nmsgs) // qp := sngecomm.Dest() // queue name prefix q := qp + "." + qns ll.Printf("%stag:%s connsess:%s queue_info q:%s qn:%d nmsgs:%d\n", exampid, ltag, conn.Session(), q, qn, nmsgs) id := stompngo.Uuid() // A unique subscription ID sc := sngecomm.HandleSubscribe(conn, q, id, sngecomm.AckMode()) ll.Printf("%stag:%s connsess:%s subscribe_complete\n", exampid, ltag, conn.Session()) // Many receivers running under the same connection can cause // (wire read) performance issues. This is *very* dependent on the broker // being used, specifically the broker's algorithm for putting messages on // the wire. // To alleviate those issues, this strategy insures that messages are // received from the wire as soon as possible. Those messages are then // buffered internally for (possibly later) application processing. bs := -1 // if s := os.Getenv("STOMP_CONN2BUFFER"); s != "" { i, e := strconv.ParseInt(s, 10, 32) if nil != e { ll.Fatalf("%stag:%s connsess:%s CONN2BUFFER_conversion_error error:%v", exampid, ltag, conn.Session(), e.Error()) // Handle this ...... } else { bs = int(i) } } if bs < 1 { bs = nmsgs } ll.Printf("%stag:%s connsess:%s mdbuffersize_qnum bs:%d qn:%d\n", exampid, ltag, conn.Session(), bs, qn) // Process all inputs async ....... // var mc chan stompngo.MessageData mdc := make(chan stompngo.MessageData, bs) // MessageData Buffer size dc := make(chan bool) // Receive processing done channel go receiveWorker(mdc, qns, nmsgs, dc, conn, id) // Start async processor for i := 1; i <= nmsgs; i++ { mdc <- <-sc // Receive message data as soon as possible, and internally queue it } ll.Printf("%stag:%s connsess:%s waitforWorkersBegin qns:%s\n", exampid, ltag, conn.Session(), qns) <-dc // Wait until receive processing is done for this queue ll.Printf("%stag:%s connsess:%s waitforWorkersEnd qns:%s\n", exampid, ltag, conn.Session(), qns) // Unsubscribe sngecomm.HandleUnsubscribe(conn, q, id) ll.Printf("%stag:%s connsess:%s unsubscribe_complete\n", exampid, ltag, conn.Session()) // Receiving is done ll.Printf("%stag:%s connsess:%s ends qns:%s\n", exampid, ltag, conn.Session(), qns) wgr.Done() }
func main() { // Make sure that the queue used by this example do not exist, or are // empty. // Following is a lengthy piece of code. Read it striaght from top // to bottom. There is zero complex logic here. // What this code will do: // Phase 1: // - Connect to a broker // - Verify a connection spec level // - Send a single message to the specified queue on that broker // - Disconnect from that broker // // Phase 2: // - Reconnect to the same broker // - Subscribe to the specified queue, using "ack:client-individual" // - Receive a single message // - Send an ACK, asking for a receipt //************************************************************************** // - Receive a RECEIPT // The point of this exercise. // - Show data from the RECEIPT and verify it // The point of this exercise. //************************************************************************** // - Disconnect from the broker // Start st := time.Now() // **************************************** Phase 1 // Set up the connection. // Standard example connect sequence n, conn, e := sngecomm.CommonConnect(exampid, tag, ll) if e != nil { ll.Fatalf("%stag:%s connsess:%s main_on_connect error:%v", exampid, tag, sngecomm.Lcs, e.Error()) // Handle this ...... } // **************************************** // App logic here ..... d := sngecomm.Dest() ll.Printf("%stag:%s connsess:%s destination:%v\n", exampid, tag, conn.Session(), d) // **************************************** // Send exactly one message. sh := stompngo.Headers{"destination", sngecomm.Dest()} if senv.Persistent() { sh = sh.Add("persistent", "true") } m := exampid + " message: " t := m + "1" ll.Printf("%stag:%s connsess:%s sending_now body:%v\n", exampid, tag, conn.Session(), t) e = conn.Send(sh, t) if e != nil { ll.Fatalf("%stag:%s connsess:%s main_bad_send error:%v", exampid, tag, conn.Session(), e.Error()) // Handle this ...... } ll.Printf("%stag:%s connsess:%s send_complete body:%v\n", exampid, tag, conn.Session(), t) // **************************************** // Disconnect from the Stomp server // Standard example disconnect sequence e = sngecomm.CommonDisconnect(n, conn, exampid, tag, ll) if e != nil { ll.Fatalf("%stag:%s connsess:%s main_disconnect error:%v", exampid, tag, conn.Session(), e.Error()) // Handle this ...... } // **************************************** Phase 2 // Standard example connect sequence n, conn, e = sngecomm.CommonConnect(exampid, tag, ll) if e != nil { ll.Fatalf("%stag:%s connsess:%s main_on_connect error:%v", exampid, tag, sngecomm.Lcs, e.Error()) // Handle this ...... } // **************************************** // Subscribe here id := stompngo.Uuid() // Get the "subscribe channel" sc := sngecomm.HandleSubscribe(conn, d, id, "client-individual") ll.Printf("%stag:%s connsess:%s stomp_subscribe_complete\n", exampid, tag, conn.Session()) // Get data from the broker var md stompngo.MessageData // A message data instance select { case md = <-sc: case md = <-conn.MessageData: // This would be contain an ERROR or RECEIPT frame. Both are unexpected // in this example. ll.Fatalf("%stag:%s connsess:%s bad_frame md:%v", exampid, tag, conn.Session(), md) // Handle this ...... } ll.Printf("%stag:%s connsess:%s channel_read_complete\n", exampid, tag, conn.Session()) // MessageData has two components: // a) a Message struct // b) an Error value. Check the error value as usual if md.Error != nil { ll.Fatalf("%stag:%s connsess:%s message_error md:%v", exampid, tag, conn.Session(), md.Error) // Handle this ...... } ll.Printf("%stag:%s connsess:%s read_message_COMMAND command:%s\n", exampid, tag, conn.Session(), md.Message.Command) ll.Printf("%stag:%s connsess:%s read_message_HEADERS headers:%s\n", exampid, tag, conn.Session(), md.Message.Headers) ll.Printf("%stag:%s connsess:%s read_message_BODY body:%s\n", exampid, tag, conn.Session(), string(md.Message.Body)) // Here we need to send an ACK. Required Headers are different between // a 1.1 and a 1.2 connection level. var ah stompngo.Headers if conn.Protocol() == stompngo.SPL_11 { // 1.1 ah = ah.Add("subscription", md.Message.Headers.Value("subscription")) ah = ah.Add("message-id", md.Message.Headers.Value("message-id")) } else { // 1.2 ah = ah.Add("id", md.Message.Headers.Value("ack")) } // We are also going to ask for a RECEIPT for the ACK rid := "receipt-001" ah = ah.Add("receipt", rid) // ll.Printf("%stag:%s connsess:%s ACK_receipt_headers headers:%v\n", exampid, tag, conn.Session(), ah) e = conn.Ack(ah) if e != nil { ll.Fatalf("%stag:%s connsess:%s ack_error error:%v", exampid, tag, conn.Session(), e.Error()) // Handle this ...... } // **************************************** // Finally get the RECEIPT. Where is it? It is *not* on the "subscribe // channel". It is on the connection level MessageData channel. Why? // Because the broker does *not* include a "subscription" header in // RECEIPT frames.. // **************************************** // ***IMPORTANT*** // ***NOTE*** which channel this RECEIPT MessageData comes in on. ll.Printf("%stag:%s connsess:%s start_receipt_read\n", exampid, tag, conn.Session()) var rd stompngo.MessageData select { case rd = <-sc: // This would contain a MESSAGE frame. It is unexpected here // in this example. ll.Fatalf("%stag:%s connsess:%s bad_frame_channel rd:%v\n", exampid, tag, conn.Session(), rd) // Handle this ...... case rd = <-conn.MessageData: // RECEIPT frame s/b in the MessageData // Step 1 of Verify if rd.Message.Command != stompngo.RECEIPT { ll.Fatalf("%stag:%s connsess:%s bad_frame_command rd:%v\n", exampid, tag, conn.Session(), rd) // Handle this ...... } } ll.Printf("%stag:%s connsess:%s end_receipt_read\n", exampid, tag, conn.Session()) // **************************************** // Show details about the RECEIPT MessageData struct ll.Printf("%stag:%s connsess:%s receipt_COMMAND command:%s\n", exampid, tag, conn.Session(), rd.Message.Command) ll.Printf("%stag:%s connsess:%s receipt_HEADERS headers:%v\n", exampid, tag, conn.Session(), rd.Message.Headers) ll.Printf("%stag:%s connsess:%s receipt_BODY body:%s\n", exampid, tag, conn.Session(), string(rd.Message.Body)) // Step 2 of Verify // Verify that the receipt has the id we asked for if rd.Message.Headers.Value("receipt-id") != rid { ll.Fatalf("%stag:%s connsess:%s bad_receipt_id wanted:%v got:%v\n", exampid, tag, conn.Session(), rid, rd.Message.Headers.Value("receipt-id")) // Handle this ...... } ll.Printf("%stag:%s connsess:%s receipt_id_verified rid:%s\n", exampid, tag, conn.Session(), rid) // **************************************** // Disconnect from the Stomp server // Standard example disconnect sequence e = sngecomm.CommonDisconnect(n, conn, exampid, tag, ll) if e != nil { ll.Fatalf("%stag:%s connsess:%s main_disconnect error:%v", exampid, tag, sngecomm.Lcs, e.Error()) // Handle this ...... } ll.Printf("%stag:%s connsess:%s main_elapsed:%v\n", exampid, tag, conn.Session(), time.Now().Sub(st)) }
func receiveMessages(conn *stompngo.Connection, qnum int, nc net.Conn) { ltag := tag + "-receivemessages" qns := fmt.Sprintf("%d", qnum) // queue number d := sngecomm.Dest() + "." + qns id := stompngo.Uuid() // A unique subscription ID ll.Printf("%stag:%s connsess:%s receiveMessages_start id:%s d:%s qnum:%d nmsgs:%d\n", exampid, ltag, conn.Session(), id, d, qnum, nmsgs) // Subscribe sc := sngecomm.HandleSubscribe(conn, d, id, sngecomm.AckMode()) pbc := sngecomm.Pbc() // Print byte count // tmr := time.NewTimer(100 * time.Hour) var md stompngo.MessageData for mc := 1; mc <= nmsgs; mc++ { select { case md = <-sc: case md = <-conn.MessageData: // Frames RECEIPT or ERROR not expected here ll.Fatalf("%stag:%s connsess:%s send_error qns:%v md:%v", exampid, ltag, conn.Session(), qns, md) // Handle this ...... } if md.Error != nil { ll.Fatalf("%stag:%s connsess:%s receive_error qns:%v error:%v\n", exampid, ltag, conn.Session(), qns, md.Error) } if md.Message.Command != stompngo.MESSAGE { ll.Fatalf("%stag:%s connsess:%s bad_frame qns:%s mc:%d md:%v\n", exampid, ltag, conn.Session(), qns, mc, md) } mcs := fmt.Sprintf("%d", mc) // message number if !md.Message.Headers.ContainsKV("qnum", qns) || !md.Message.Headers.ContainsKV("msgnum", mcs) { ll.Fatalf("%stag:%s connsess:%s dirty_message qns:%v msgnum:%v md:%v", exampid, tag, conn.Session(), qns, mcs, md) // Handle this ...... } // Process the inbound message ................. sl := len(md.Message.Body) if pbc > 0 { sl = pbc if len(md.Message.Body) < sl { sl = len(md.Message.Body) } } ll.Printf("%stag:%s connsess:%s receiveMessages_msg d:%s body:%s qnum:%d msgnum:%s\n", exampid, ltag, conn.Session(), d, string(md.Message.Body[0:sl]), qnum, md.Message.Headers.Value("msgnum")) if mc == nmsgs { break } // Handle ACKs if needed if sngecomm.AckMode() != "auto" { ah := []string{} sngecomm.HandleAck(conn, ah, id) } if mc == nmsgs { break } // if rw { runtime.Gosched() // yield for this example dt := time.Duration(sngecomm.ValueBetween(min, max, rf)) ll.Printf("%stag:%s connsess:%s recv_stagger dt:%v qns:%s mc:%d\n", exampid, ltag, conn.Session(), dt, qns, mc) tmr.Reset(dt) _ = <-tmr.C } } ll.Printf("%stag:%s connsess:%s end d:%s qnum:%d nmsgs:%d\n", exampid, ltag, conn.Session(), d, qnum, nmsgs) // Unsubscribe sngecomm.HandleUnsubscribe(conn, d, id) // }
// Receive messages from a particular queue func receiver(qn, mc int) { ltag := tag + "-receiver" qns := fmt.Sprintf("%d", qn) // string queue number pbc := sngecomm.Pbc() id := stompngo.Uuid() // A unique subscription ID d := sngecomm.Dest() + "." + qns ll.Printf("%stag:%s connsess:%s queue_info id:%v d:%v qnum:%v mc:%v\n", exampid, ltag, conn.Session(), id, d, qn, mc) // Subscribe sc := sngecomm.HandleSubscribe(conn, d, id, sngecomm.AckMode()) ll.Printf("%stag:%s connsess:%s subscribe_complete id:%v d:%v qnum:%v mc:%v\n", exampid, ltag, conn.Session(), id, d, qn, mc) // tmr := time.NewTimer(100 * time.Hour) var md stompngo.MessageData // Receive loop for i := 1; i <= mc; i++ { ll.Printf("%stag:%s connsess:%s recv_ranchek id:%v d:%v qnum:%v mc:%v chlen:%v chcap:%v\n", exampid, ltag, conn.Session(), id, d, qn, mc, len(sc), cap(sc)) select { case md = <-sc: case md = <-conn.MessageData: // A RECEIPT or ERROR frame is unexpected here ll.Fatalf("%stag:%s connsess:%s bad_frame qnum:%v headers:%v body:%s", exampid, tag, conn.Session(), qn, md.Message.Headers, md.Message.Body) // Handle this ...... } if md.Error != nil { ll.Fatalf("%stag:%s connsess:%s recv_error qnum:%v error:%v", exampid, tag, conn.Session(), qn, md.Error) // Handle this ...... } // Process the inbound message ................. ll.Printf("%stag:%s connsess:%s recv_message qnum:%v i:%v\n", exampid, tag, conn.Session(), qn, i) if pbc > 0 { maxlen := pbc if len(md.Message.Body) < maxlen { maxlen = len(md.Message.Body) } ss := string(md.Message.Body[0:maxlen]) ll.Printf("%stag:%s connsess:%s payload qnum:%v body:%s\n", exampid, tag, conn.Session(), qn, ss) } // Sanity check the message Command, and the queue and message numbers mns := fmt.Sprintf("%d", i) // message number if md.Message.Command != stompngo.MESSAGE { ll.Fatalf("%stag:%s connsess:%s bad_frame qnum:%v command:%v headers:%v body:%v\n", exampid, tag, conn.Session(), qn, md.Message.Command, md.Message.Headers, string(md.Message.Body)) // Handle this ...... } if !md.Message.Headers.ContainsKV("qnum", qns) || !md.Message.Headers.ContainsKV("msgnum", mns) { ll.Fatalf("%stag:%s connsess:%s dirty_message qns:%v msgnum:%v command:%v headers:%v body:%v\n", exampid, tag, conn.Session(), qns, mns, md.Message.Command, md.Message.Headers, string(md.Message.Body)) // Handle this ......) // Handle this ...... } if i == mc { break } if rw { dt := time.Duration(sngecomm.ValueBetween(min, max, rf)) ll.Printf("%stag:%s connsess:%s recv_stagger id:%v d:%v qnum:%v stagger:%v\n", exampid, ltag, conn.Session(), id, d, qn, dt) tmr.Reset(dt) _ = <-tmr.C runtime.Gosched() } // Handle ACKs if needed if sngecomm.AckMode() != "auto" { sngecomm.HandleAck(conn, md.Message.Headers, id) } } // Unsubscribe sngecomm.HandleUnsubscribe(conn, d, id) ll.Printf("%stag:%s connsess:%s unsubscribe_complete id:%v d:%v qnum:%v mc:%v\n", exampid, ltag, conn.Session(), id, d, qn, mc) // Receiving is done ll.Printf("%stag:%s connsess:%s recv_end id:%v d:%v qnum:%v mc:%v\n", exampid, ltag, conn.Session(), id, d, qn, mc) wgr.Done() }