Version bump.
[stompngo.git] / disconnect.go
blobd1a0061223c138e2d8416423d7d1a12ca9dddff4
1 //
2 // Copyright © 2011-2019 Guy M. Allard
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
17 package stompngo
19 import (
20 "fmt"
21 "os"
22 "time"
26 Disconnect from a STOMP broker.
28 Shut down heart beats if necessary.
29 Set connection status to false to disable further actions with this
30 connection.
33 Obtain a receipt unless the client specifically indicates a receipt request
34 should be excluded. If the client actually asks for a receipt, use the
35 supplied receipt id. Otherwise generate a unique receipt id and add that
36 to the DISCONNECT headers.
38 Example:
39 h := stompngo.Headers{HK_RECEIPT, "receipt-id1"} // Ask for a receipt
40 e := c.Disconnect(h)
41 if e != nil {
42 // Do something sane ...
44 fmt.Printf("%q\n", c.DisconnectReceipt)
45 // Or:
46 h := stompngo.Headers{"noreceipt", "true"} // Ask for a receipt
47 e := c.Disconnect(h)
48 if e != nil {
49 // Do something sane ...
51 fmt.Printf("%q\n", c.DisconnectReceipt)
54 func (c *Connection) Disconnect(h Headers) error {
55 c.discLock.Lock()
56 defer c.discLock.Unlock()
58 if !c.isConnected() {
59 return ECONBAD
61 c.log(DISCONNECT, "start", h)
62 e := checkHeaders(h, c.Protocol())
63 if e != nil {
64 return e
66 ch := h.Clone()
67 // If the caller does not want a receipt do not ask for one. Otherwise,
68 // add a receipt request if caller did not specifically ask for one. This is
69 // in the spirit of the specification, and allows reasonable resource cleanup
70 // in both the client and the message broker.
71 _, cwr := ch.Contains("noreceipt")
72 if !cwr {
73 if _, ok := ch.Contains(HK_RECEIPT); !ok {
74 ch = append(ch, HK_RECEIPT, Uuid())
77 wrid := ""
78 wrid, _ = ch.Contains(HK_RECEIPT)
79 _ = wrid
81 f := Frame{DISCONNECT, ch, NULLBUFF}
83 r := make(chan error)
84 if e = c.writeWireData(wiredata{f, r}); e != nil {
85 return e
87 e = <-r
88 // Drive shutdown logic
89 // Only set DisconnectReceipt if we sucessfully received one, and it is
90 // the one we were expecting.
91 if !cwr && e == nil {
92 // Can be RECEIPT or ERROR frame
93 mds, e := c.getMessageData()
95 // fmt.Println(DISCONNECT, "sanchek", mds)
97 switch mds.Message.Command {
98 case ERROR:
99 e = fmt.Errorf("DISBRKERR -> %q", mds.Message)
100 c.log(DISCONNECT, "errf", e)
101 case RECEIPT:
102 gr := mds.Message.Headers.Value(HK_RECEIPT_ID)
103 if wrid != gr {
104 e = fmt.Errorf("%s wanted:%s got:%s", EBADRID, wrid, gr)
105 c.log(DISCONNECT, "nadrid", e)
106 } else {
107 c.DisconnectReceipt = mds
108 c.log(DISCONNECT, "OK")
110 default:
111 e = fmt.Errorf("DISBADFRM -> %q", mds.Message)
112 c.log(DISCONNECT, "badf", e)
115 c.log(DISCONNECT, "ends", ch)
116 c.shutdown()
117 c.sysAbort()
118 c.log(DISCONNECT, "system shutdown cannel closed")
119 return e
122 func (c *Connection) getMessageData() (MessageData, error) {
123 var md MessageData
124 var me error
125 me = nil
126 if os.Getenv("STOMP_MAXDISCTO") != "" {
127 d, e := time.ParseDuration(os.Getenv("STOMP_MAXDISCTO"))
128 if e != nil {
129 c.log("DISCGETMD PDERROR -> ", e)
130 md = <-c.input
131 } else {
132 c.log("DISCGETMD DUR -> ", d)
133 ticker := time.NewTicker(d)
134 select {
135 case _ = <-ticker.C:
136 me = EDISCTO
137 ticker.Stop()
138 case md = <-c.input:
139 ticker.Stop()
142 } else {
143 c.log("DISNOMAX", me)
144 md = <-c.input
147 return md, me