fix: truncate long activity fields to prevent Discord rejection #18
@@ -55,6 +55,30 @@ const (
|
||||
|
||||
const heartbeatInterval = 41 // Heartbeat interval in seconds
|
||||
|
||||
// Discord API field length limits
|
||||
const (
|
||||
maxTextLength = 128 // Max characters for text fields (details, state, name, large_text)
|
||||
maxURLLength = 256 // Max characters for URL fields (details_url, state_url, etc.)
|
||||
)
|
||||
|
||||
// truncateText truncates s to maxTextLength runes, appending "…" if truncated.
|
||||
func truncateText(s string) string {
|
||||
runes := []rune(s)
|
||||
if len(runes) <= maxTextLength {
|
||||
return s
|
||||
}
|
||||
return string(runes[:maxTextLength-1]) + "…"
|
||||
}
|
||||
|
||||
// truncateURL returns s unchanged if within maxURLLength, otherwise returns ""
|
||||
// (a truncated URL would be broken, so we omit it entirely).
|
||||
func truncateURL(s string) string {
|
||||
if len(s) <= maxURLLength {
|
||||
return s
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// activity represents a Discord activity sent via Gateway opcode 3.
|
||||
type activity struct {
|
||||
Name string `json:"name"`
|
||||
|
||||
+51
@@ -448,4 +448,55 @@ var _ = Describe("discordRPC", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("truncateText", func() {
|
||||
It("returns short strings unchanged", func() {
|
||||
Expect(truncateText("hello")).To(Equal("hello"))
|
||||
})
|
||||
|
||||
It("returns exactly 128-char strings unchanged", func() {
|
||||
s := strings.Repeat("a", 128)
|
||||
Expect(truncateText(s)).To(Equal(s))
|
||||
})
|
||||
|
||||
It("truncates strings over 128 chars to 127 + ellipsis", func() {
|
||||
s := strings.Repeat("a", 200)
|
||||
result := truncateText(s)
|
||||
Expect([]rune(result)).To(HaveLen(128))
|
||||
Expect(result).To(HaveSuffix("…"))
|
||||
})
|
||||
|
||||
It("handles multi-byte characters correctly", func() {
|
||||
// 130 Japanese characters — each is one rune but 3 bytes
|
||||
s := strings.Repeat("あ", 130)
|
||||
result := truncateText(s)
|
||||
runes := []rune(result)
|
||||
Expect(runes).To(HaveLen(128))
|
||||
Expect(string(runes[127])).To(Equal("…"))
|
||||
})
|
||||
|
||||
It("returns empty string unchanged", func() {
|
||||
Expect(truncateText("")).To(Equal(""))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("truncateURL", func() {
|
||||
It("returns short URLs unchanged", func() {
|
||||
Expect(truncateURL("https://example.com")).To(Equal("https://example.com"))
|
||||
|
|
||||
})
|
||||
|
||||
It("returns exactly 256-char URLs unchanged", func() {
|
||||
u := "https://example.com/" + strings.Repeat("a", 236)
|
||||
Expect(truncateURL(u)).To(Equal(u))
|
||||
})
|
||||
|
||||
It("returns empty string for URLs over 256 chars", func() {
|
||||
u := "https://example.com/" + strings.Repeat("a", 237)
|
||||
Expect(truncateURL(u)).To(Equal(""))
|
||||
})
|
||||
|
||||
It("returns empty string unchanged", func() {
|
||||
Expect(truncateURL("")).To(Equal(""))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user
The test validation using
strings.Containsis fragile. It could lead to false positives if the checked substring appears elsewhere in the JSON payload, or if JSON encoding adds escape characters. For example, it doesn't strictly check that the URL fields are omitted, only that the long URL string isn't present.A more robust approach would be to unmarshal the JSON message and assert on the specific field values. This would ensure the correct fields are being truncated and that the URL fields are correctly omitted (by checking for an empty string value, or that the key is not present due to
omitempty).Consider refactoring the check like this: