Sfoglia il codice sorgente

Merge pull request #664 from slingamn/sort_defs.2

tweaks to cap listing
tags/v1.2.0
Shivaram Lingamneni 4 anni fa
parent
commit
cbb3fe51b9
Nessun account collegato all'indirizzo email del committer
8 ha cambiato i file con 145 aggiunte e 94 eliminazioni
  1. 1
    0
      gencapdefs.py
  2. 52
    52
      irc/caps/defs.go
  3. 13
    33
      irc/caps/set.go
  4. 2
    2
      irc/caps/set_test.go
  5. 8
    3
      irc/handlers.go
  6. 4
    4
      irc/server.go
  7. 41
    0
      irc/utils/text.go
  8. 24
    0
      irc/utils/text_test.go

+ 1
- 0
gencapdefs.py Vedi File

@@ -180,6 +180,7 @@ CAPDEFS = [
180 180
 ]
181 181
 
182 182
 def validate_defs():
183
+    CAPDEFS.sort(key=lambda d: d.name)
183 184
     numCaps = len(CAPDEFS)
184 185
     numNames = len(set(capdef.name for capdef in CAPDEFS))
185 186
     if numCaps != numNames:

+ 52
- 52
irc/caps/defs.go Vedi File

@@ -13,10 +13,6 @@ const (
13 13
 )
14 14
 
15 15
 const (
16
-	// Acc is the proposed IRCv3 capability named "draft/acc":
17
-	// https://github.com/ircv3/ircv3-specifications/pull/276
18
-	Acc Capability = iota
19
-
20 16
 	// AccountNotify is the IRCv3 capability named "account-notify":
21 17
 	// https://ircv3.net/specs/extensions/account-notify-3.1.html
22 18
 	AccountNotify Capability = iota
@@ -41,6 +37,34 @@ const (
41 37
 	// https://ircv3.net/specs/extensions/chghost-3.2.html
42 38
 	ChgHost Capability = iota
43 39
 
40
+	// Acc is the proposed IRCv3 capability named "draft/acc":
41
+	// https://github.com/ircv3/ircv3-specifications/pull/276
42
+	Acc Capability = iota
43
+
44
+	// EventPlayback is the Proposed IRCv3 capability named "draft/event-playback":
45
+	// https://github.com/ircv3/ircv3-specifications/pull/362
46
+	EventPlayback Capability = iota
47
+
48
+	// LabeledResponse is the draft IRCv3 capability named "draft/labeled-response-0.2":
49
+	// https://ircv3.net/specs/extensions/labeled-response.html
50
+	LabeledResponse Capability = iota
51
+
52
+	// Languages is the proposed IRCv3 capability named "draft/languages":
53
+	// https://gist.github.com/DanielOaks/8126122f74b26012a3de37db80e4e0c6
54
+	Languages Capability = iota
55
+
56
+	// Rename is the proposed IRCv3 capability named "draft/rename":
57
+	// https://github.com/SaberUK/ircv3-specifications/blob/rename/extensions/rename.md
58
+	Rename Capability = iota
59
+
60
+	// Resume is the proposed IRCv3 capability named "draft/resume-0.5":
61
+	// https://github.com/DanielOaks/ircv3-specifications/blob/master+resume/extensions/resume.md
62
+	Resume Capability = iota
63
+
64
+	// SetName is the proposed IRCv3 capability named "draft/setname":
65
+	// https://github.com/ircv3/ircv3-specifications/pull/361
66
+	SetName Capability = iota
67
+
44 68
 	// EchoMessage is the IRCv3 capability named "echo-message":
45 69
 	// https://ircv3.net/specs/extensions/echo-message-3.2.html
46 70
 	EchoMessage Capability = iota
@@ -53,18 +77,6 @@ const (
53 77
 	// https://ircv3.net/specs/extensions/invite-notify-3.2.html
54 78
 	InviteNotify Capability = iota
55 79
 
56
-	// LabeledResponse is the draft IRCv3 capability named "draft/labeled-response-0.2":
57
-	// https://ircv3.net/specs/extensions/labeled-response.html
58
-	LabeledResponse Capability = iota
59
-
60
-	// Languages is the proposed IRCv3 capability named "draft/languages":
61
-	// https://gist.github.com/DanielOaks/8126122f74b26012a3de37db80e4e0c6
62
-	Languages Capability = iota
63
-
64
-	// MaxLine is the Oragono-specific capability named "oragono.io/maxline-2":
65
-	// https://oragono.io/maxline-2
66
-	MaxLine Capability = iota
67
-
68 80
 	// MessageTags is the IRCv3 capability named "message-tags":
69 81
 	// https://ircv3.net/specs/extensions/message-tags.html
70 82
 	MessageTags Capability = iota
@@ -73,13 +85,17 @@ const (
73 85
 	// https://ircv3.net/specs/extensions/multi-prefix-3.1.html
74 86
 	MultiPrefix Capability = iota
75 87
 
76
-	// Rename is the proposed IRCv3 capability named "draft/rename":
77
-	// https://github.com/SaberUK/ircv3-specifications/blob/rename/extensions/rename.md
78
-	Rename Capability = iota
88
+	// Bouncer is the Oragono-specific capability named "oragono.io/bnc":
89
+	// https://oragono.io/bnc
90
+	Bouncer Capability = iota
79 91
 
80
-	// Resume is the proposed IRCv3 capability named "draft/resume-0.5":
81
-	// https://github.com/DanielOaks/ircv3-specifications/blob/master+resume/extensions/resume.md
82
-	Resume Capability = iota
92
+	// MaxLine is the Oragono-specific capability named "oragono.io/maxline-2":
93
+	// https://oragono.io/maxline-2
94
+	MaxLine Capability = iota
95
+
96
+	// Nope is the Oragono vendor capability named "oragono.io/nope":
97
+	// https://oragono.io/nope
98
+	Nope Capability = iota
83 99
 
84 100
 	// SASL is the IRCv3 capability named "sasl":
85 101
 	// https://ircv3.net/specs/extensions/sasl-3.2.html
@@ -89,10 +105,6 @@ const (
89 105
 	// https://ircv3.net/specs/extensions/server-time-3.2.html
90 106
 	ServerTime Capability = iota
91 107
 
92
-	// SetName is the proposed IRCv3 capability named "draft/setname":
93
-	// https://github.com/ircv3/ircv3-specifications/pull/361
94
-	SetName Capability = iota
95
-
96 108
 	// STS is the IRCv3 capability named "sts":
97 109
 	// https://ircv3.net/specs/extensions/sts.html
98 110
 	STS Capability = iota
@@ -101,56 +113,44 @@ const (
101 113
 	// https://ircv3.net/specs/extensions/userhost-in-names-3.2.html
102 114
 	UserhostInNames Capability = iota
103 115
 
104
-	// Bouncer is the Oragono-specific capability named "oragono.io/bnc":
105
-	// https://oragono.io/bnc
106
-	Bouncer Capability = iota
107
-
108
-	// ZNCSelfMessage is the ZNC vendor capability named "znc.in/self-message":
109
-	// https://wiki.znc.in/Query_buffers
110
-	ZNCSelfMessage Capability = iota
111
-
112
-	// EventPlayback is the Proposed IRCv3 capability named "draft/event-playback":
113
-	// https://github.com/ircv3/ircv3-specifications/pull/362
114
-	EventPlayback Capability = iota
115
-
116 116
 	// ZNCPlayback is the ZNC vendor capability named "znc.in/playback":
117 117
 	// https://wiki.znc.in/Playback
118 118
 	ZNCPlayback Capability = iota
119 119
 
120
-	// Nope is the Oragono vendor capability named "oragono.io/nope":
121
-	// https://oragono.io/nope
122
-	Nope Capability = iota
120
+	// ZNCSelfMessage is the ZNC vendor capability named "znc.in/self-message":
121
+	// https://wiki.znc.in/Query_buffers
122
+	ZNCSelfMessage Capability = iota
123 123
 )
124 124
 
125 125
 // `capabilityNames[capab]` is the string name of the capability `capab`
126 126
 var (
127 127
 	capabilityNames = [numCapabs]string{
128
-		"draft/acc",
129 128
 		"account-notify",
130 129
 		"account-tag",
131 130
 		"away-notify",
132 131
 		"batch",
133 132
 		"cap-notify",
134 133
 		"chghost",
134
+		"draft/acc",
135
+		"draft/event-playback",
136
+		"draft/labeled-response-0.2",
137
+		"draft/languages",
138
+		"draft/rename",
139
+		"draft/resume-0.5",
140
+		"draft/setname",
135 141
 		"echo-message",
136 142
 		"extended-join",
137 143
 		"invite-notify",
138
-		"draft/labeled-response-0.2",
139
-		"draft/languages",
140
-		"oragono.io/maxline-2",
141 144
 		"message-tags",
142 145
 		"multi-prefix",
143
-		"draft/rename",
144
-		"draft/resume-0.5",
146
+		"oragono.io/bnc",
147
+		"oragono.io/maxline-2",
148
+		"oragono.io/nope",
145 149
 		"sasl",
146 150
 		"server-time",
147
-		"draft/setname",
148 151
 		"sts",
149 152
 		"userhost-in-names",
150
-		"oragono.io/bnc",
151
-		"znc.in/self-message",
152
-		"draft/event-playback",
153 153
 		"znc.in/playback",
154
-		"oragono.io/nope",
154
+		"znc.in/self-message",
155 155
 	}
156 156
 )

+ 13
- 33
irc/caps/set.go Vedi File

@@ -4,9 +4,7 @@
4 4
 package caps
5 5
 
6 6
 import (
7
-	"bytes"
8
-	"sort"
9
-
7
+	"fmt"
10 8
 	"github.com/oragono/oragono/irc/utils"
11 9
 )
12 10
 
@@ -91,11 +89,15 @@ func (s *Set) Empty() bool {
91 89
 	return utils.BitsetEmpty(s[:])
92 90
 }
93 91
 
94
-const maxPayloadLength = 440
92
+const defaultMaxPayloadLength = 450
95 93
 
96 94
 // Strings returns all of our enabled capabilities as a slice of strings.
97
-func (s *Set) Strings(version Version, values Values) (result []string) {
98
-	var strs sort.StringSlice
95
+func (s *Set) Strings(version Version, values Values, maxLen int) (result []string) {
96
+	if maxLen == 0 {
97
+		maxLen = defaultMaxPayloadLength
98
+	}
99
+	var t utils.TokenLineBuilder
100
+	t.Initialize(maxLen, " ")
99 101
 
100 102
 	var capab Capability
101 103
 	asSlice := s[:]
@@ -108,37 +110,15 @@ func (s *Set) Strings(version Version, values Values) (result []string) {
108 110
 		if version >= Cap302 {
109 111
 			val, exists := values[capab]
110 112
 			if exists {
111
-				capString += "=" + val
113
+				capString = fmt.Sprintf("%s=%s", capString, val)
112 114
 			}
113 115
 		}
114
-		strs = append(strs, capString)
116
+		t.Add(capString)
115 117
 	}
116 118
 
117
-	if len(strs) == 0 {
118
-		return []string{""}
119
-	}
120
-
121
-	// sort the cap string before we send it out
122
-	sort.Sort(strs)
123
-
124
-	var buf bytes.Buffer
125
-	for _, str := range strs {
126
-		tokenLen := len(str)
127
-		if buf.Len() != 0 {
128
-			tokenLen += 1
129
-		}
130
-		if maxPayloadLength < buf.Len()+tokenLen {
131
-			result = append(result, buf.String())
132
-			buf.Reset()
133
-		}
134
-		if buf.Len() != 0 {
135
-			buf.WriteByte(' ')
136
-		}
137
-		buf.WriteString(str)
119
+	result = t.Lines()
120
+	if result == nil {
121
+		result = []string{""}
138 122
 	}
139
-	if buf.Len() != 0 {
140
-		result = append(result, buf.String())
141
-	}
142
-
143 123
 	return
144 124
 }

+ 2
- 2
irc/caps/set_test.go Vedi File

@@ -47,13 +47,13 @@ func TestSets(t *testing.T) {
47 47
 	values := make(Values)
48 48
 	values[InviteNotify] = "invitemepls"
49 49
 
50
-	actualCap301ValuesString := s1.Strings(Cap301, values)
50
+	actualCap301ValuesString := s1.Strings(Cap301, values, 0)
51 51
 	expectedCap301ValuesString := []string{"invite-notify userhost-in-names"}
52 52
 	if !reflect.DeepEqual(actualCap301ValuesString, expectedCap301ValuesString) {
53 53
 		t.Errorf("Generated Cap301 values string [%v] did not match expected values string [%v]", actualCap301ValuesString, expectedCap301ValuesString)
54 54
 	}
55 55
 
56
-	actualCap302ValuesString := s1.Strings(Cap302, values)
56
+	actualCap302ValuesString := s1.Strings(Cap302, values, 0)
57 57
 	expectedCap302ValuesString := []string{"invite-notify=invitemepls userhost-in-names"}
58 58
 	if !reflect.DeepEqual(actualCap302ValuesString, expectedCap302ValuesString) {
59 59
 		t.Errorf("Generated Cap302 values string [%s] did not match expected values string [%s]", actualCap302ValuesString, expectedCap302ValuesString)

+ 8
- 3
irc/handlers.go Vedi File

@@ -569,9 +569,14 @@ func capHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo
569 569
 
570 570
 	sendCapLines := func(cset *caps.Set, values caps.Values) {
571 571
 		version := rb.session.capVersion
572
-		capLines := cset.Strings(version, values)
573
-		// weechat 1.4 has a bug here where it won't accept the CAP reply unless it contains
574
-		// the server.name source:
572
+		// we're working around two bugs:
573
+		// 1. weechat 1.4 won't accept the CAP reply unless it contains the server.name source
574
+		// 2. old versions of Kiwi and The Lounge can't parse multiline CAP LS 302 (#661),
575
+		// so try as hard as possible to get the response to fit on one line.
576
+		// :server.name CAP * LS * :<tokens>
577
+		// 1           7         4
578
+		maxLen := 510 - 1 - len(server.name) - 7 - len(subCommand) - 4
579
+		capLines := cset.Strings(version, values, maxLen)
575 580
 		for i, capStr := range capLines {
576 581
 			if version >= caps.Cap302 && i < len(capLines)-1 {
577 582
 				rb.Add(nil, server.name, "CAP", details.nick, subCommand, "*", capStr)

+ 4
- 4
irc/server.go Vedi File

@@ -710,17 +710,17 @@ func (server *Server) applyConfig(config *Config, initial bool) (err error) {
710 710
 
711 711
 	// updated caps get DEL'd and then NEW'd
712 712
 	// so, we can just add updated ones to both removed and added lists here and they'll be correctly handled
713
-	server.logger.Debug("server", "Updated Caps", strings.Join(updatedCaps.Strings(caps.Cap301, config.Server.capValues), " "))
713
+	server.logger.Debug("server", "Updated Caps", strings.Join(updatedCaps.Strings(caps.Cap301, config.Server.capValues, 0), " "))
714 714
 	addedCaps.Union(updatedCaps)
715 715
 	removedCaps.Union(updatedCaps)
716 716
 
717 717
 	if !addedCaps.Empty() || !removedCaps.Empty() {
718 718
 		capBurstSessions = server.clients.AllWithCapsNotify()
719 719
 
720
-		added[caps.Cap301] = addedCaps.Strings(caps.Cap301, config.Server.capValues)
721
-		added[caps.Cap302] = addedCaps.Strings(caps.Cap302, config.Server.capValues)
720
+		added[caps.Cap301] = addedCaps.Strings(caps.Cap301, config.Server.capValues, 0)
721
+		added[caps.Cap302] = addedCaps.Strings(caps.Cap302, config.Server.capValues, 0)
722 722
 		// removed never has values, so we leave it as Cap301
723
-		removed = removedCaps.Strings(caps.Cap301, config.Server.capValues)
723
+		removed = removedCaps.Strings(caps.Cap301, config.Server.capValues, 0)
724 724
 	}
725 725
 
726 726
 	for _, sSession := range capBurstSessions {

+ 41
- 0
irc/utils/text.go Vedi File

@@ -83,3 +83,44 @@ func MakeSplitMessage(original string, origIs512 bool) (result SplitMessage) {
83 83
 
84 84
 	return
85 85
 }
86
+
87
+// TokenLineBuilder is a helper for building IRC lines composed of delimited tokens,
88
+// with a maximum line length.
89
+type TokenLineBuilder struct {
90
+	lineLen int
91
+	delim   string
92
+	buf     bytes.Buffer
93
+	result  []string
94
+}
95
+
96
+func (t *TokenLineBuilder) Initialize(lineLen int, delim string) {
97
+	t.lineLen = lineLen
98
+	t.delim = delim
99
+}
100
+
101
+// Add adds a token to the line, creating a new line if necessary.
102
+func (t *TokenLineBuilder) Add(token string) {
103
+	tokenLen := len(token)
104
+	if t.buf.Len() != 0 {
105
+		tokenLen += len(t.delim)
106
+	}
107
+	if t.lineLen < t.buf.Len()+tokenLen {
108
+		t.result = append(t.result, t.buf.String())
109
+		t.buf.Reset()
110
+	}
111
+	if t.buf.Len() != 0 {
112
+		t.buf.WriteString(t.delim)
113
+	}
114
+	t.buf.WriteString(token)
115
+}
116
+
117
+// Lines terminates the line-building and returns all the lines.
118
+func (t *TokenLineBuilder) Lines() (result []string) {
119
+	result = t.result
120
+	t.result = nil
121
+	if t.buf.Len() != 0 {
122
+		result = append(result, t.buf.String())
123
+		t.buf.Reset()
124
+	}
125
+	return
126
+}

+ 24
- 0
irc/utils/text_test.go Vedi File

@@ -58,3 +58,27 @@ func BenchmarkWordWrap(b *testing.B) {
58 58
 		WordWrap(monteCristo, 60)
59 59
 	}
60 60
 }
61
+
62
+func TestTokenLineBuilder(t *testing.T) {
63
+	lineLen := 400
64
+	var tl TokenLineBuilder
65
+	tl.Initialize(lineLen, " ")
66
+	for _, token := range strings.Fields(monteCristo) {
67
+		tl.Add(token)
68
+	}
69
+
70
+	lines := tl.Lines()
71
+	if len(lines) != 4 {
72
+		t.Errorf("expected 4 lines, got %d", len(lines))
73
+	}
74
+	for _, line := range lines {
75
+		if len(line) > lineLen {
76
+			t.Errorf("line length %d exceeds maximum of %d", len(line), lineLen)
77
+		}
78
+	}
79
+
80
+	joined := strings.Join(lines, " ")
81
+	if joined != monteCristo {
82
+		t.Errorf("text incorrectly split into lines: %s instead of %s", joined, monteCristo)
83
+	}
84
+}

Loading…
Annulla
Salva