// Connect to a STOMP broker, publish some messages 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 ...... } // *NOTE* application specific functionaltiy starts here! sh := stompngo.Headers{"destination", sngecomm.Dest()} ll.Printf("%stag:%s connsess:%s destination dest:%s\n", exampid, tag, conn.Session(), sngecomm.Dest()) if senv.Persistent() { sh = sh.Add("persistent", "true") } ms := exampid + "message: " for i := 1; i <= senv.Nmsgs(); i++ { mse := ms + fmt.Sprintf("%d", i) ll.Printf("%stag:%s connsess:%s main_sending mse:~%s~\n", exampid, tag, conn.Session(), mse) e := conn.Send(sh, mse) if e != nil { ll.Fatalf("%stag:%s connsess:%s main_on_connect error:%v", exampid, tag, conn.Session(), e.Error()) // Handle this ...... } ll.Printf("%stag:%s connsess:%s main_send_complete mse:~%s~\n", exampid, tag, conn.Session(), mse) time.Sleep(100 * time.Millisecond) } // *NOTE* application specific functionaltiy ends here! // 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 ...... } ll.Printf("%stag:%s connsess:%s main_elapsed:%v\n", exampid, tag, conn.Session(), time.Now().Sub(st)) }
// Send messages to a particular queue func sender(qn, mc int) { ltag := tag + "-sender" qns := fmt.Sprintf("%d", qn) // string queue number id := stompngo.Uuid() // A unique sender 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) // wh := stompngo.Headers{"destination", d, "senderId", id, "qnum", qns} // send Headers if senv.Persistent() { wh = wh.Add("persistent", "true") } // tmr := time.NewTimer(100 * time.Hour) // Send loop for i := 1; i <= mc; i++ { si := fmt.Sprintf("%d", i) sh := append(wh, "msgnum", si) // Generate a message to send ............... ll.Printf("%stag:%s connsess:%s send_headers id:%v d:%v qnum:%v headers:%v\n", exampid, ltag, conn.Session(), id, d, qn, sh) e := conn.Send(sh, string(sngecomm.Partial())) if e != nil { ll.Fatalf("%stag:%s connsess:%s send_error qnum:%v error:%v", exampid, tag, conn.Session(), qn, e.Error()) // Handle this ...... } if i == mc { break } if sw { dt := time.Duration(sngecomm.ValueBetween(min, max, sf)) ll.Printf("%stag:%s connsess:%s send_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() } } // Sending is done ll.Printf("%stag:%s connsess:%s finish_info id:%v d:%v qnum:%v mc:%v\n", exampid, ltag, conn.Session(), id, d, qn, mc) wgs.Done() }
// Send messages to a particular queue func sender(conn *stompngo.Connection, qn, nmsgs int) { ltag := tag + "-sender" qns := fmt.Sprintf("%d", qn) // queue number d := sngecomm.Dest() + "." + qns ll.Printf("%stag:%s connsess:%s starts qn:%d nmsgs:%d d:%s\n", exampid, ltag, conn.Session(), qn, nmsgs, d) // wh := stompngo.Headers{"destination", d, "qnum", qns} // send Headers if senv.Persistent() { wh = wh.Add("persistent", "true") } // tmr := time.NewTimer(100 * time.Hour) // Send loop for i := 1; i <= nmsgs; i++ { si := fmt.Sprintf("%d", i) sh := append(wh, "msgnum", si) // Generate a message to send ............... ll.Printf("%stag:%s connsess:%s message qns:%s si:%s\n", exampid, ltag, conn.Session(), qns, si) e := conn.Send(sh, string(sngecomm.Partial())) if e != nil { ll.Fatalf("%stag:%s connsess:%s send_error qnum:%v error:%v", exampid, ltag, conn.Session(), qn, e.Error()) // Handle this ...... } if i == nmsgs { break } if sw { runtime.Gosched() // yield for this example dt := time.Duration(sngecomm.ValueBetween(min, max, sf)) ll.Printf("%stag:%s connsess:%s send_stagger dt:%v qns:%s\n", exampid, ltag, conn.Session(), dt, qns) tmr.Reset(dt) _ = <-tmr.C } } // Sending is done ll.Printf("%stag:%s connsess:%s sender_ends qn:%d nmsgs:%d\n", exampid, ltag, conn.Session(), qn, nmsgs) wgs.Done() }
func main() { fmt.Println("Receiver Start...") // create a net.Conn, and pass that into Connect p := os.Getenv("STOMP_PORT") if p == "" { p = "61613" } nc, error := net.Dial("tcp", hap+p) if error != nil { log.Fatal(error) } // Connect ch := stompngo.Headers{"login", "getter", "passcode", "recv1234"} ch = ch.Add("accept-version", "1.0") // 1.0 only ch = ch.Add("host", host) c, error := stompngo.Connect(nc, ch) if error != nil { log.Fatal(error) } for i := 1; i <= mq; i++ { qn := fmt.Sprintf("%d", i) wg.Add(1) go recMessages(c, qname+qn) } wg.Wait() fmt.Println("Receiver done with wait") // Disconnect nh := stompngo.Headers{} error = c.Disconnect(nh) if error != nil { log.Fatalf("Receiver discerr %v\n", error) } // Sanity check for spurious errors select { case v := <-c.MessageData: fmt.Printf("Receiver frame2: %s\n", v.Message.Command) fmt.Printf("Receiver header2: %v\n", v.Message.Headers) fmt.Printf("Receiver data2: %s\n", string(v.Message.Body)) default: fmt.Println("Receiver Nothing to show") } // Network close nc.Close() fmt.Println("Receiver done nc.Close()") ngor := runtime.NumGoroutine() fmt.Printf("Receiver ngor: %v\n", ngor) fmt.Println("Receiver End... numq:", mq, "Num received:", numRecv) }
// Connect to a STOMP broker, send 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 ...... } // Suppress content length here, so JMS will treat this as a 'text' message. sh := stompngo.Headers{"destination", "jms.queue.exampleQueue"} if os.Getenv("STOMP_NOSCL") != "true" { sh = sh.Add("suppress-content-length", "true") } if senv.Persistent() { sh = sh.Add("persistent", "true") } ms := exampid + " message: " for i := 1; i <= nmsgs; i++ { mse := ms + fmt.Sprintf("%d", i) e := conn.Send(sh, mse) if e != nil { ll.Fatalf("%stag:%s connsess:%s send_error error:%v\n", exampid, tag, conn.Session(), e.Error()) // Handle this ...... } ll.Printf("%stag:%s connsess:%s send_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, sngecomm.Lcs, e.Error()) // Handle this ...... } ll.Printf("%stag:%s connsess:%s main_elapsed:%v\n", exampid, tag, conn.Session(), time.Now().Sub(st)) }
/* runSender sends all messages to a specified queue. */ func runSender(conn *stompngo.Connection, qns string) { ltag := tag + "-runsender" d := sngecomm.Dest() + "." + qns id := stompngo.Uuid() // A unique sender id ll.Printf("%stag:%s connsess:%s start id:%s dest:%s\n", exampid, ltag, conn.Session(), id, d) wh := stompngo.Headers{"destination", d, "senderId", id, "qnum", qns} // basic send Headers if senv.Persistent() { wh = wh.Add("persistent", "true") } tmr := time.NewTimer(100 * time.Hour) nmsgs := senv.Nmsgs() for mc := 1; mc <= nmsgs; mc++ { sh := append(wh, "msgnum", fmt.Sprintf("%d", mc)) // Generate a message to send ............... ll.Printf("%stag:%s connsess:%s send id:%s qns:%s mc:%d\n", exampid, ltag, conn.Session(), id, qns, mc) e := conn.Send(sh, string(sngecomm.Partial())) if e != nil { ll.Fatalf("%stag:%s connsess:%s send_error qns:%v error:%v", exampid, ltag, conn.Session(), qns, e.Error()) // Handle this ...... } if mc == nmsgs { break } if sw { dt := time.Duration(sngecomm.ValueBetween(min, max, sf)) ll.Printf("%stag:%s connsess:%s send_stagger dt:%v qns:%s mc:%d\n", exampid, ltag, conn.Session(), dt, qns, mc) tmr.Reset(dt) _ = <-tmr.C runtime.Gosched() } } ll.Printf("%stag:%s connsess:%s end id:%s dest:%s\n", exampid, ltag, conn.Session(), id, d) // wgs.Done() }
func sendMessages(conn *stompngo.Connection, qnum int, nc net.Conn) { ltag := tag + "-sendmessages" qns := fmt.Sprintf("%d", qnum) // queue number d := sngecomm.Dest() + "." + qns ll.Printf("%stag:%s connsess:%s start d:%s qnum:%d\n", exampid, ltag, conn.Session(), d, qnum) wh := stompngo.Headers{"destination", d, "qnum", qns} // send Headers if senv.Persistent() { wh = wh.Add("persistent", "true") } // tmr := time.NewTimer(100 * time.Hour) // Send messages for mc := 1; mc <= nmsgs; mc++ { mcs := fmt.Sprintf("%d", mc) sh := append(wh, "msgnum", mcs) // Generate a message to send ............... ll.Printf("%stag:%s connsess:%s message mc:%d qnum:%d\n", exampid, ltag, conn.Session(), mc, qnum) e := conn.Send(sh, string(sngecomm.Partial())) if e != nil { ll.Fatalf("%stag:%s connsess:%s send_error qnum:%v error:%v", exampid, ltag, conn.Session(), qnum, e.Error()) // Handle this ...... } if mc == nmsgs { break } if sw { runtime.Gosched() // yield for this example dt := time.Duration(sngecomm.ValueBetween(min, max, sf)) ll.Printf("%stag:%s connsess:%s send_stagger dt:%v qnum:%s mc:%d\n", exampid, ltag, conn.Session(), dt, qnum, mc) tmr.Reset(dt) _ = <-tmr.C } } }
func main() { fmt.Println("Start...") // create a net.Conn, and pass that into Connect nc, error := net.Dial("tcp", hap+os.Getenv("STOMP_PORT")) if error != nil { log.Fatal(error) } // Connect ch := stompngo.Headers{"login", "getter", "passcode", "recv1234"} ch = ch.Add("accept-version", "1.1") ch = ch.Add("host", host) c, error := stompngo.Connect(nc, ch) if error != nil { log.Fatal(error) } for i := 1; i <= mq; i++ { qn := fmt.Sprintf("%d", i) wg.Add(1) go recMessages(c, qname+qn) } wg.Wait() fmt.Printf("Num received: %d\n", numRecv) // Disconnect nh := stompngo.Headers{} error = c.Disconnect(nh) if error != nil { log.Fatalf("discerr %v\n", error) } fmt.Println("done nc.Close()") nc.Close() ngor := runtime.NumGoroutine() fmt.Printf("egor: %v\n", ngor) select { case v := <-c.MessageData: fmt.Printf("frame2: %s\n", v.Message.Command) fmt.Printf("header2: %v\n", v.Message.Headers) fmt.Printf("data2: %s\n", string(v.Message.Body)) default: fmt.Println("Nothing to show") } fmt.Println("End... mq:", mq) }
func recMessages(c *stompngo.Connection, q string, k int) { var error error ks := fmt.Sprintf("%d", k) // Receive phase headers := stompngo.Headers{"destination", q} sh := headers.Add("id", q) // log.Println("start subscribe", q) sc, error := c.Subscribe(sh) log.Println("end subscribe", q) if error != nil { log.Fatal(error) } for input := range sc { inmsg := input.Message.BodyString() if printMsgs { log.Println("Receive:", q, " / ", inmsg) } if inmsg == "***EOF***" { break } if !strings.HasPrefix(inmsg, ks) { log.Printf("bad prefix: [%v], [%v], [%v]\n", q, inmsg, ks) log.Fatal("bad prefix ....") } // d := time.Duration(getStagger(1e9/10, 1e9/5)) time.Sleep(d) } log.Println("quit for", q) error = c.Unsubscribe(headers) log.Println("end unsubscribe", q) if error != nil { log.Fatal(error) } wgrecv.Done() }
// Handle a subscribe for the different protocol levels. func HandleSubscribe(c *stompngo.Connection, d, i, a string) <-chan stompngo.MessageData { h := stompngo.Headers{"destination", d, "ack", a} // switch c.Protocol() { case stompngo.SPL_12: // Add required id header h = h.Add("id", i) case stompngo.SPL_11: // Add required id header h = h.Add("id", i) case stompngo.SPL_10: // Nothing else to do here default: llu.Fatalf("v1:%v v2:%v\n", "subscribe invalid protocol level, should not happen") } // r, e := c.Subscribe(h) if e != nil { llu.Fatalf("v1:%v v2:%v\n", "subscribe failed", e) } return r }
func (m *Mediator) Subscribe(h stompngo.Headers) error { m.mu.Lock() defer m.mu.Unlock() m.subId = stompngo.Uuid() m.subHeaders = h. Add("id", m.subId) var err error m.sub, err = m.conn.Subscribe(m.subHeaders) return err }
// Handle ACKs for the different protocol levels. func HandleAck(c *stompngo.Connection, h stompngo.Headers, id string) { ah := stompngo.Headers{} // switch c.Protocol() { case stompngo.SPL_12: ah = ah.Add("id", h.Value("ack")) case stompngo.SPL_11: ah = ah.Add("message-id", h.Value("message-id")).Add("subscription", id) case stompngo.SPL_10: ah = ah.Add("message-id", h.Value("message-id")) default: llu.Fatalf("v1:%v v2:%v\n", "ack invalid protocol level, should not happen") } if cv, ok := h.Contains(stompngo.HK_RECEIPT); ok { ah = ah.Add(stompngo.HK_RECEIPT, cv) } e := c.Ack(ah) if e != nil { llu.Fatalf("v1:%v v2:%v v3:%v\n", "ack failed", e, c.Protocol()) } return }
// Provide connect headers func ConnectHeaders() stompngo.Headers { h := stompngo.Headers{} l := senv.Login() if l != "" { h = h.Add("login", l) } pc := senv.Passcode() if pc != "" { h = h.Add("passcode", pc) } // p := senv.Protocol() if p != stompngo.SPL_10 { // 1.1 and 1.2 h = h.Add("accept-version", p).Add("host", senv.Vhost()) hb := senv.Heartbeats() if hb != "" { h = h.Add("heart-beat", hb) } } // return h }
func New(host, port, user, pass string, connHeaders stompngo.Headers) (*Mediator, error) { if host == "" || port == "" || user == "" || pass == "" { return nil, fmt.Errorf("one or more values for Mediator initialization are blank") } m := &Mediator{ host: host, port: port, user: user, pass: pass, mu: new(sync.Mutex), reconnect: time.Duration(DefaultReconnect), } m.connHeaders = connHeaders. Add("login", m.user). Add("passcode", m.pass). Add("host", m.host) err := m.Connect() if err != nil { return nil, err } // Add reconnect to stack for accommodating DNS changes go func(m *Mediator) { for { select { case <-time.After(m.reconnect): m.Connect() } } }(m) return m, nil }
// Handle a unsubscribe for the different protocol levels. func HandleUnsubscribe(c *stompngo.Connection, d, i string) { sbh := stompngo.Headers{} // switch c.Protocol() { case stompngo.SPL_12: sbh = sbh.Add("id", i) case stompngo.SPL_11: sbh = sbh.Add("id", i) case stompngo.SPL_10: sbh = sbh.Add("destination", d) default: llu.Fatalf("v1:%v v2:%v\n", "unsubscribe invalid protocol level, should not happen") } e := c.Unsubscribe(sbh) if e != nil { llu.Fatalf("v1:%v v2:%v d:%v\n", "unsubscribe failed", e, d) } return }
// Handle a subscribe for the different protocol levels. func doSubscribe(c *stompngo.Connection, d, id, a string, h stompngo.Headers) <-chan stompngo.MessageData { h = h.Add("destination", d).Add("ack", a) // switch c.Protocol() { case stompngo.SPL_12: // Add required id header h = h.Add("id", id) case stompngo.SPL_11: // Add required id header h = h.Add("id", id) case stompngo.SPL_10: // Nothing else to do here default: ll.Fatalf("v1:%v\n", "subscribe invalid protocol level, should not happen") } // r, e := c.Subscribe(h) if e != nil { ll.Fatalf("subscribe failed err:[%v]\n", e) } return r }
func runNextQueue(qn int, conn *stompngo.Connection) { qns := fmt.Sprintf("%d", qn) // string number of the queue conn.SetLogger(ll) // stompngo logging pbc := sngecomm.Pbc() // Print byte count d := senv.Dest() + qns // Destination id := stompngo.Uuid() // A unique name/id nmsgs := qn // int number of messages to get, same as queue number am := sngecomm.AckMode() // ACK mode to use on SUBSCRIBE nfa := true // Need "final" ACK (possiby reset below) wh := stompngo.Headers{} // Starting SUBSCRIBE headers // Sanity check ACK mode if conn.Protocol() == stompngo.SPL_10 && am == stompngo.AckModeClientIndividual { ll.Fatalf("%stag:%s connsess:%s invalid_ack_mode am:%v proto:%v\n", exampid, tag, session, am, conn.Protocol()) // } // Do not do final ACK if running ACKs are issued if am == stompngo.AckModeClientIndividual || am == stompngo.AckModeAuto { nfa = false } // Show run parameters ll.Printf("%stag:%s connsess:%s run_parms\n\tqns:%v\n\tpbc:%v\n\td:%v\n\tid:%v\n\tnmsgs:%v\n\tam:%v\n\tnfa:%v\n\twh:%v\n", exampid, tag, session, qns, pbc, d, id, nmsgs, am, nfa, wh) // Run SUBSCRIBE sc := doSubscribe(conn, d, id, am, wh) ll.Printf("%stag:%s connsess:%s stomp_subscribe_complete\n", exampid, tag, session) var md stompngo.MessageData // Message data from basic read var lmd stompngo.MessageData // Possible save (copy) of received data mc := 1 // Initial message number // Loop for the requested number of messages GetLoop: for { ll.Printf("%stag:%s connsess:%s start_of_read_loop mc:%v nmsgs:%v\n", exampid, tag, session, mc, nmsgs) mcs := fmt.Sprintf("%d", mc) // string number message count // Get something from the stompngo read routine select { case md = <-sc: case md = <-conn.MessageData: // if md.Message.Command == stompngo.RECEIPT { ll.Printf("%stag:%s connsess:%s have_receipt md:%v\n", exampid, tag, session, md) continue GetLoop } ll.Fatalf("%stag:%s connsess:%s ERROR_frame hdrs:%v body:%v\n", exampid, tag, session, md.Message.Headers, string(md.Message.Body)) // Handle this ...... } // Save message data for possible use in the final ACK if mc == nmsgs && nfa { lmd = md // Save last message } // Basic loop logging ll.Printf("%stag:%s connsess:%s channel_read_complete qn:%d mc:%d\n", exampid, tag, session, qn, mc) ll.Printf("%stag:%s connsess:%s message_number:%v\n", exampid, tag, session, mc) // Check if reader returned any error if md.Error != nil { ll.Fatalf("%stag:%s connsess:%s error_read error:%v", exampid, tag, session, md.Error) // Handle this ...... } // Show frame type ll.Printf("%stag:%s connsess:%s frame_type cmd:%s\n", exampid, tag, session, md.Message.Command) // Pure sanity check: this should *never* happen based on logic // above. if md.Message.Command != stompngo.MESSAGE { ll.Fatalf("%stag:%s connsess:%s error_frame_type md:%v", exampid, tag, session, md) // Handle this ...... } // Show Message Headers 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, session, wh[j], wh[j+1]) } // Show (part of) Message Body 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, session, ss) } // Sanity check this message payload wm := wlp + mcs // The left part plus the (string) meassage number] bm := string(md.Message.Body) if bm != wm { ll.Fatalf("%stag:%s connsess:%s error_message_payload\n\tGot %s\n\tWant%s\n", exampid, tag, session, bm, wm) // Handle this ...... } else { ll.Printf("%stag:%s connsess:%s matched_body_string\n%s\n%s\n", exampid, tag, session, bm, wm) // Handle this ......) } // Run individual ACK if required if am == stompngo.AckModeClientIndividual { wh := md.Message.Headers // Copy Headers if ar { // ACK receipt wanted wh = wh.Add(stompngo.HK_RECEIPT, "rwanted-"+mcs) } sngecomm.HandleAck(conn, wh, id) ll.Printf("%stag:%s connsess:%s individual_ack_complete mc:%v headers:%v\n", exampid, tag, session, mc, md.Message.Headers) } // Check for end of loop condition if mc == nmsgs { break } // Increment loop/message counter mc++ } qc := make(chan bool) go drainSub(session, sc, qc, qn) dd := false // Issue the final ACK if needed if nfa { wh := lmd.Message.Headers // Copy Headers if ar { // ACK receipt wanted wh = wh.Add(stompngo.HK_RECEIPT, "rwanted-fin") } sngecomm.HandleAck(conn, wh, id) ll.Printf("%stag:%s connsess:%s final_ack_complete\n", exampid, tag, session) if ar { ll.Printf("%stag:%s connsess:%s ack_receive_wait_for_drain qn:%d\n", exampid, tag, session, qn) <-qc // Wait for drainSub ll.Printf("%stag:%s connsess:%s ack_receive_drain_complete qn:%d\n", exampid, tag, session, qn) dd = true getReceipt(conn) } } if !dd { ll.Printf("%stag:%s connsess:%s message_loop_wait_for_drain qn:%d\n", exampid, tag, session, qn) <-qc ll.Printf("%stag:%s connsess:%s message_loop_drain_complete qn:%d\n", exampid, tag, session, qn) } // Unsubscribe (may be skipped if requested) if unsub { sngecomm.HandleUnsubscribe(conn, d, id) ll.Printf("%stag:%s connsess:%s stomp_unsubscribe_complete\n", exampid, tag, session) } else { ll.Printf("%stag:%s connsess:%s skipping_unsubscribe\n", exampid, tag, session) } }
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 main() { st := time.Now() // **************************************** // 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 ..... // Send exactly one message. Ask for a receipt. d := sngecomm.Dest() ll.Printf("%stag:%s connsess:%s destination:%v\n", exampid, tag, conn.Session(), d) rid := "recipt-002" // The receipt ID sh := stompngo.Headers{"destination", d, "receipt", rid} // send headers if senv.Persistent() { sh = sh.Add("persistent", "true") } ms := exampid + " message: " t := ms + rid 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) // Look for the receipt ll.Printf("%stag:%s connsess:%s start_receipt_read\n", exampid, tag, conn.Session()) rd := <-conn.MessageData // The RECEIPT frame should be on this channel 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) 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)) }