forked from gmallard/stompngo
/
writer.go
125 lines (117 loc) · 2.72 KB
/
writer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//
// Copyright © 2011-2014 Guy M. Allard
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package stompngo
import (
"bufio"
"strconv"
"time"
)
/*
Logical network writer. Read wiredata structures from the communication
channel, and put them on the wire.
*/
func (c *Connection) writer() {
q := false
for {
select {
case d := <-c.output:
c.wireWrite(d)
case q = <-c.wsd:
break
}
if q {
break
}
}
c.log("writer shutdown", time.Now())
}
/*
Connection logical write.
*/
func (c *Connection) wireWrite(d wiredata) {
f := &d.frame
switch f.Command {
case "\n": // HeartBeat frame
if _, e := c.wtr.WriteString(f.Command); e != nil {
d.errchan <- e
return
}
default: // Other frames
if e := f.writeFrame(c.wtr, c.Protocol()); e != nil {
d.errchan <- e
return
}
if e := c.wtr.Flush(); e != nil {
d.errchan <- e
return
}
if e := c.wtr.WriteByte('\x00'); e != nil {
d.errchan <- e
return
}
}
if e := c.wtr.Flush(); e != nil {
d.errchan <- e
return
}
//
if c.hbd != nil {
c.hbd.ls = time.Now().UnixNano() // Latest good send
}
c.mets.tfw += 1 // Frame written count
c.mets.tbw += f.Size(false) // Bytes written count
//
d.errchan <- nil
return
}
/*
Frame physical write.
*/
func (f *Frame) writeFrame(w *bufio.Writer, l string) error {
// Write the frame Command
if _, e := w.WriteString(f.Command + "\n"); e != nil {
return e
}
// Content length - Always add it if client does not suppress it and
// does not supply it.
if _, ok := f.Headers.Contains("suppress-content-length"); !ok {
if _, clok := f.Headers.Contains("content-length"); !clok {
f.Headers = append(f.Headers, "content-length", strconv.Itoa(len(f.Body)))
}
}
// Write the frame Headers
for i := 0; i < len(f.Headers); i += 2 {
if l > SPL_10 && f.Command != CONNECT {
f.Headers[i] = encode(f.Headers[i])
f.Headers[i+1] = encode(f.Headers[i+1])
}
_, e := w.WriteString(f.Headers[i] + ":" + f.Headers[i+1] + "\n")
if e != nil {
return e
}
}
// Write the last Header LF
if e := w.WriteByte('\n'); e != nil {
return e
}
// Write the body
if len(f.Body) != 0 { // Foolish to write 0 length data
if _, e := w.Write(f.Body); e != nil {
return e
}
}
return nil
}