mirror of
https://github.com/ergochat/ergo.git
synced 2025-12-20 02:00:11 -08:00
tidy up a bit
This commit is contained in:
parent
db4b23bb48
commit
6d94aa1591
10 changed files with 112 additions and 67 deletions
|
|
@ -238,7 +238,7 @@ CAPDEFS = [
|
||||||
standard="Soju/Goguma vendor",
|
standard="Soju/Goguma vendor",
|
||||||
),
|
),
|
||||||
CapDef(
|
CapDef(
|
||||||
identifier="MetadataTwoJudgementDay",
|
identifier="Metadata",
|
||||||
name="draft/metadata-2",
|
name="draft/metadata-2",
|
||||||
url="https://ircv3.net/specs/extensions/metadata",
|
url="https://ircv3.net/specs/extensions/metadata",
|
||||||
standard="draft IRCv3",
|
standard="draft IRCv3",
|
||||||
|
|
|
||||||
|
|
@ -65,9 +65,9 @@ const (
|
||||||
// https://github.com/progval/ircv3-specifications/blob/redaction/extensions/message-redaction.md
|
// https://github.com/progval/ircv3-specifications/blob/redaction/extensions/message-redaction.md
|
||||||
MessageRedaction Capability = iota
|
MessageRedaction Capability = iota
|
||||||
|
|
||||||
// MetadataTwoJudgementDay is the draft IRCv3 capability named "draft/metadata-2":
|
// Metadata is the draft IRCv3 capability named "draft/metadata-2":
|
||||||
// https://ircv3.net/specs/extensions/metadata
|
// https://ircv3.net/specs/extensions/metadata
|
||||||
MetadataTwoJudgementDay Capability = iota
|
Metadata Capability = iota
|
||||||
|
|
||||||
// Multiline is the proposed IRCv3 capability named "draft/multiline":
|
// Multiline is the proposed IRCv3 capability named "draft/multiline":
|
||||||
// https://github.com/ircv3/ircv3-specifications/pull/398
|
// https://github.com/ircv3/ircv3-specifications/pull/398
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ type Channel struct {
|
||||||
dirtyBits uint
|
dirtyBits uint
|
||||||
settings ChannelSettings
|
settings ChannelSettings
|
||||||
uuid utils.UUID
|
uuid utils.UUID
|
||||||
metadata MetadataStore
|
metadata map[string]string
|
||||||
// these caches are paired to allow iteration over channel members without holding the lock
|
// these caches are paired to allow iteration over channel members without holding the lock
|
||||||
membersCache []*Client
|
membersCache []*Client
|
||||||
memberDataCache []*memberData
|
memberDataCache []*memberData
|
||||||
|
|
@ -895,6 +895,10 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
||||||
rb.Add(nil, client.server.name, "MARKREAD", chname, client.GetReadMarker(chcfname))
|
rb.Add(nil, client.server.name, "MARKREAD", chname, client.GetReadMarker(chcfname))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if rb.session.capabilities.Has(caps.Metadata) {
|
||||||
|
syncChannelMetadata(client.server, rb, channel)
|
||||||
|
}
|
||||||
|
|
||||||
if rb.session.client == client {
|
if rb.session.client == client {
|
||||||
// don't send topic and names for a SAJOIN of a different client
|
// don't send topic and names for a SAJOIN of a different client
|
||||||
channel.SendTopic(client, rb, false)
|
channel.SendTopic(client, rb, false)
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ type RegisteredChannel struct {
|
||||||
// Settings are the chanserv-modifiable settings
|
// Settings are the chanserv-modifiable settings
|
||||||
Settings ChannelSettings
|
Settings ChannelSettings
|
||||||
// Metadata set using the METADATA command
|
// Metadata set using the METADATA command
|
||||||
Metadata MetadataStore
|
Metadata map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RegisteredChannel) Serialize() ([]byte, error) {
|
func (r *RegisteredChannel) Serialize() ([]byte, error) {
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ type Client struct {
|
||||||
clearablePushMessages map[string]time.Time
|
clearablePushMessages map[string]time.Time
|
||||||
pushSubscriptionsExist atomic.Uint32 // this is a cache on len(pushSubscriptions) != 0
|
pushSubscriptionsExist atomic.Uint32 // this is a cache on len(pushSubscriptions) != 0
|
||||||
pushQueue pushQueue
|
pushQueue pushQueue
|
||||||
metadata MetadataStore
|
metadata map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
type saslStatus struct {
|
type saslStatus struct {
|
||||||
|
|
@ -216,7 +216,7 @@ type Session struct {
|
||||||
|
|
||||||
webPushEndpoint string // goroutine-local: web push endpoint registered by the current session
|
webPushEndpoint string // goroutine-local: web push endpoint registered by the current session
|
||||||
|
|
||||||
metadataSubscriptions []string
|
metadataSubscriptions utils.HashSet[string]
|
||||||
}
|
}
|
||||||
|
|
||||||
// MultilineBatch tracks the state of a client-to-server multiline batch.
|
// MultilineBatch tracks the state of a client-to-server multiline batch.
|
||||||
|
|
|
||||||
|
|
@ -1646,7 +1646,7 @@ func LoadConfig(filename string) (config *Config, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !config.Metadata.Enabled {
|
if !config.Metadata.Enabled {
|
||||||
config.Server.supportedCaps.Disable(caps.MetadataTwoJudgementDay)
|
config.Server.supportedCaps.Disable(caps.Metadata)
|
||||||
} else {
|
} else {
|
||||||
var metadataValues []string
|
var metadataValues []string
|
||||||
if config.Metadata.MaxSubs >= 0 {
|
if config.Metadata.MaxSubs >= 0 {
|
||||||
|
|
@ -1659,7 +1659,7 @@ func LoadConfig(filename string) (config *Config, err error) {
|
||||||
metadataValues = append(metadataValues, fmt.Sprintf("max-value-bytes=%d", config.Metadata.MaxValueBytes))
|
metadataValues = append(metadataValues, fmt.Sprintf("max-value-bytes=%d", config.Metadata.MaxValueBytes))
|
||||||
}
|
}
|
||||||
if len(metadataValues) != 0 {
|
if len(metadataValues) != 0 {
|
||||||
config.Server.capValues[caps.MetadataTwoJudgementDay] = strings.Join(metadataValues, ",")
|
config.Server.capValues[caps.Metadata] = strings.Join(metadataValues, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -833,24 +833,32 @@ func (session *Session) isSubscribedTo(key string) bool {
|
||||||
session.client.stateMutex.RLock()
|
session.client.stateMutex.RLock()
|
||||||
defer session.client.stateMutex.RUnlock()
|
defer session.client.stateMutex.RUnlock()
|
||||||
|
|
||||||
return slices.Contains(session.metadataSubscriptions, key)
|
if session.metadataSubscriptions == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return session.metadataSubscriptions.Has(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *Session) SubscribeTo(keys ...string) ([]string, error) {
|
func (session *Session) SubscribeTo(keys ...string) ([]string, error) {
|
||||||
session.client.stateMutex.Lock()
|
session.client.stateMutex.Lock()
|
||||||
defer session.client.stateMutex.Unlock()
|
defer session.client.stateMutex.Unlock()
|
||||||
|
|
||||||
|
if session.metadataSubscriptions == nil {
|
||||||
|
session.metadataSubscriptions = make(utils.HashSet[string])
|
||||||
|
}
|
||||||
|
|
||||||
var added []string
|
var added []string
|
||||||
|
|
||||||
maxSubs := session.client.server.Config().Metadata.MaxSubs
|
maxSubs := session.client.server.Config().Metadata.MaxSubs
|
||||||
|
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
if !slices.Contains(session.metadataSubscriptions, k) {
|
if !session.metadataSubscriptions.Has(k) {
|
||||||
if len(session.metadataSubscriptions) > maxSubs {
|
if len(session.metadataSubscriptions) > maxSubs {
|
||||||
return added, errMetadataTooManySubs
|
return added, errMetadataTooManySubs
|
||||||
}
|
}
|
||||||
added = append(added, k)
|
added = append(added, k)
|
||||||
session.metadataSubscriptions = append(session.metadataSubscriptions, k)
|
session.metadataSubscriptions.Add(k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -863,27 +871,25 @@ func (session *Session) UnsubscribeFrom(keys ...string) []string {
|
||||||
|
|
||||||
var removed []string
|
var removed []string
|
||||||
|
|
||||||
new := slices.DeleteFunc(session.metadataSubscriptions,
|
if session.metadataSubscriptions == nil {
|
||||||
func(keyName string) bool {
|
return []string{}
|
||||||
if slices.Contains(keys, keyName) {
|
}
|
||||||
removed = append(removed, keyName)
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
session.metadataSubscriptions = new
|
for k := range session.metadataSubscriptions {
|
||||||
|
if slices.Contains(keys, k) {
|
||||||
|
removed = append(removed, k)
|
||||||
|
session.metadataSubscriptions.Remove(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return removed
|
return removed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *Session) MetadataSubscriptions() []string {
|
func (session *Session) MetadataSubscriptions() utils.HashSet[string] {
|
||||||
session.client.stateMutex.Lock()
|
session.client.stateMutex.Lock()
|
||||||
defer session.client.stateMutex.Unlock()
|
defer session.client.stateMutex.Unlock()
|
||||||
|
|
||||||
return slices.Clone(session.metadataSubscriptions)
|
return maps.Clone(session.metadataSubscriptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) GetMetadata(key string) (string, error) {
|
func (channel *Channel) GetMetadata(key string) (string, error) {
|
||||||
|
|
@ -901,7 +907,7 @@ func (channel *Channel) SetMetadata(key string, value string) {
|
||||||
channel.stateMutex.Lock()
|
channel.stateMutex.Lock()
|
||||||
|
|
||||||
if channel.metadata == nil {
|
if channel.metadata == nil {
|
||||||
channel.metadata = make(MetadataStore)
|
channel.metadata = make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.metadata[key] = value
|
channel.metadata[key] = value
|
||||||
|
|
@ -909,7 +915,7 @@ func (channel *Channel) SetMetadata(key string, value string) {
|
||||||
channel.MarkDirty(IncludeAllAttrs)
|
channel.MarkDirty(IncludeAllAttrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) ListMetadata() MetadataStore {
|
func (channel *Channel) ListMetadata() map[string]string {
|
||||||
channel.stateMutex.RLock()
|
channel.stateMutex.RLock()
|
||||||
defer channel.stateMutex.RUnlock()
|
defer channel.stateMutex.RUnlock()
|
||||||
|
|
||||||
|
|
@ -924,11 +930,11 @@ func (channel *Channel) DeleteMetadata(key string) {
|
||||||
channel.MarkDirty(IncludeAllAttrs)
|
channel.MarkDirty(IncludeAllAttrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) ClearMetadata() MetadataStore {
|
func (channel *Channel) ClearMetadata() map[string]string {
|
||||||
channel.stateMutex.Lock()
|
channel.stateMutex.Lock()
|
||||||
|
|
||||||
oldMap := channel.metadata
|
oldMap := channel.metadata
|
||||||
channel.metadata = make(MetadataStore)
|
channel.metadata = make(map[string]string)
|
||||||
|
|
||||||
channel.stateMutex.Unlock()
|
channel.stateMutex.Unlock()
|
||||||
channel.MarkDirty(IncludeAllAttrs)
|
channel.MarkDirty(IncludeAllAttrs)
|
||||||
|
|
@ -962,15 +968,13 @@ func (client *Client) SetMetadata(key string, value string) {
|
||||||
defer client.stateMutex.Unlock()
|
defer client.stateMutex.Unlock()
|
||||||
|
|
||||||
if client.metadata == nil {
|
if client.metadata == nil {
|
||||||
client.metadata = make(MetadataStore)
|
client.metadata = make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
client.metadata[key] = value
|
client.metadata[key] = value
|
||||||
|
|
||||||
// coming soon: https://www.youtube.com/watch?v=K14JkFfWUzc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) ListMetadata() MetadataStore {
|
func (client *Client) ListMetadata() map[string]string {
|
||||||
client.stateMutex.RLock()
|
client.stateMutex.RLock()
|
||||||
defer client.stateMutex.RUnlock()
|
defer client.stateMutex.RUnlock()
|
||||||
|
|
||||||
|
|
@ -984,12 +988,12 @@ func (client *Client) DeleteMetadata(key string) {
|
||||||
delete(client.metadata, key)
|
delete(client.metadata, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) ClearMetadata() MetadataStore {
|
func (client *Client) ClearMetadata() map[string]string {
|
||||||
client.stateMutex.Lock()
|
client.stateMutex.Lock()
|
||||||
defer client.stateMutex.Unlock()
|
defer client.stateMutex.Unlock()
|
||||||
|
|
||||||
oldMap := client.metadata
|
oldMap := client.metadata
|
||||||
client.metadata = make(MetadataStore)
|
client.metadata = make(map[string]string)
|
||||||
|
|
||||||
return oldMap
|
return oldMap
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,13 @@ package irc
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -3248,10 +3250,10 @@ func metadataHandler(server *Server, client *Client, msg ircmsg.Message, rb *Res
|
||||||
|
|
||||||
lineLength := MaxLineLen - len(server.name) - len(RPL_METADATASUBOK) - len(client.Nick()) - 10
|
lineLength := MaxLineLen - len(server.name) - len(RPL_METADATASUBOK) - len(client.Nick()) - 10
|
||||||
|
|
||||||
chunked := utils.ChunkifyParams(added, lineLength)
|
chunked := utils.ChunkifyParams(slices.Values(added), lineLength)
|
||||||
for _, line := range chunked {
|
for _, line := range chunked {
|
||||||
params := append([]string{client.Nick()}, line...)
|
params := append([]string{client.Nick()}, line...)
|
||||||
rb.Add(nil, server.name, RPL_METADATASUBS, params...)
|
rb.Add(nil, server.name, RPL_METADATASUBOK, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "unsub":
|
case "unsub":
|
||||||
|
|
@ -3260,42 +3262,29 @@ func metadataHandler(server *Server, client *Client, msg ircmsg.Message, rb *Res
|
||||||
removed := rb.session.UnsubscribeFrom(keys...)
|
removed := rb.session.UnsubscribeFrom(keys...)
|
||||||
|
|
||||||
lineLength := MaxLineLen - len(server.name) - len(RPL_METADATAUNSUBOK) - len(client.Nick()) - 10
|
lineLength := MaxLineLen - len(server.name) - len(RPL_METADATAUNSUBOK) - len(client.Nick()) - 10
|
||||||
chunked := utils.ChunkifyParams(removed, lineLength)
|
chunked := utils.ChunkifyParams(slices.Values(removed), lineLength)
|
||||||
for _, line := range chunked {
|
for _, line := range chunked {
|
||||||
params := append([]string{client.Nick()}, line...)
|
params := append([]string{client.Nick()}, line...)
|
||||||
rb.Add(nil, server.name, RPL_METADATASUBS, params...)
|
rb.Add(nil, server.name, RPL_METADATAUNSUBOK, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "subs":
|
case "subs":
|
||||||
lineLength := MaxLineLen - len(server.name) - len(RPL_METADATASUBS) - len(client.Nick()) - 10 // for safety
|
lineLength := MaxLineLen - len(server.name) - len(RPL_METADATASUBS) - len(client.Nick()) - 10 // for safety
|
||||||
|
|
||||||
chunked := utils.ChunkifyParams(rb.session.MetadataSubscriptions(), lineLength)
|
subs := rb.session.MetadataSubscriptions()
|
||||||
|
|
||||||
|
chunked := utils.ChunkifyParams(maps.Keys(subs), lineLength)
|
||||||
for _, line := range chunked {
|
for _, line := range chunked {
|
||||||
params := append([]string{client.Nick()}, line...)
|
params := append([]string{client.Nick()}, line...)
|
||||||
rb.Add(nil, server.name, RPL_METADATASUBS, params...)
|
rb.Add(nil, server.name, RPL_METADATASUBS, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "sync":
|
case "sync":
|
||||||
batchId := rb.StartNestedBatch("metadata")
|
|
||||||
defer rb.EndNestedBatch(batchId)
|
|
||||||
|
|
||||||
values := t.ListMetadata()
|
|
||||||
for k, v := range values {
|
|
||||||
if rb.session.isSubscribedTo(k) {
|
|
||||||
visibility := "*"
|
|
||||||
rb.Add(nil, server.name, "METADATA", target, k, visibility, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if targetChannel != nil {
|
if targetChannel != nil {
|
||||||
for _, client := range targetChannel.Members() {
|
syncChannelMetadata(server, rb, targetChannel)
|
||||||
values := client.ListMetadata()
|
}
|
||||||
for k, v := range values {
|
if targetClient != nil {
|
||||||
if rb.session.isSubscribedTo(k) {
|
syncClientMetadata(server, rb, targetClient)
|
||||||
visibility := "*"
|
|
||||||
rb.Add(nil, server.name, "METADATA", client.Nick(), k, visibility, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,12 @@ var (
|
||||||
errMetadataNotFound = errors.New("key not found")
|
errMetadataNotFound = errors.New("key not found")
|
||||||
)
|
)
|
||||||
|
|
||||||
type MetadataStore = map[string]string
|
|
||||||
|
|
||||||
type MetadataHaver = interface {
|
type MetadataHaver = interface {
|
||||||
SetMetadata(key string, value string)
|
SetMetadata(key string, value string)
|
||||||
GetMetadata(key string) (string, error)
|
GetMetadata(key string) (string, error)
|
||||||
DeleteMetadata(key string)
|
DeleteMetadata(key string)
|
||||||
ListMetadata() MetadataStore
|
ListMetadata() map[string]string
|
||||||
ClearMetadata() MetadataStore
|
ClearMetadata() map[string]string
|
||||||
CountMetadata() int
|
CountMetadata() int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,7 +30,7 @@ func notifySubscribers(server *Server, session *Session, target string, key stri
|
||||||
targetClient := server.clients.Get(target)
|
targetClient := server.clients.Get(target)
|
||||||
|
|
||||||
if targetClient != nil {
|
if targetClient != nil {
|
||||||
notify = targetClient.FriendsMonitors(caps.MetadataTwoJudgementDay)
|
notify = targetClient.FriendsMonitors(caps.Metadata)
|
||||||
// notify clients about changes regarding themselves
|
// notify clients about changes regarding themselves
|
||||||
for _, s := range targetClient.Sessions() {
|
for _, s := range targetClient.Sessions() {
|
||||||
notify.Add(s)
|
notify.Add(s)
|
||||||
|
|
@ -42,7 +40,7 @@ func notifySubscribers(server *Server, session *Session, target string, key stri
|
||||||
members := targetChannel.Members()
|
members := targetChannel.Members()
|
||||||
for _, m := range members {
|
for _, m := range members {
|
||||||
for _, s := range m.Sessions() {
|
for _, s := range m.Sessions() {
|
||||||
if s.capabilities.Has(caps.MetadataTwoJudgementDay) {
|
if s.capabilities.Has(caps.Metadata) {
|
||||||
notify.Add(s)
|
notify.Add(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -65,6 +63,50 @@ func notifySubscribers(server *Server, session *Session, target string, key stri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func syncClientMetadata(server *Server, rb *ResponseBuffer, target *Client) {
|
||||||
|
if len(rb.session.MetadataSubscriptions()) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
batchId := rb.StartNestedBatch("metadata")
|
||||||
|
defer rb.EndNestedBatch(batchId)
|
||||||
|
|
||||||
|
values := target.ListMetadata()
|
||||||
|
for k, v := range values {
|
||||||
|
if rb.session.isSubscribedTo(k) {
|
||||||
|
visibility := "*"
|
||||||
|
rb.Add(nil, server.name, "METADATA", target.Nick(), k, visibility, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func syncChannelMetadata(server *Server, rb *ResponseBuffer, target *Channel) {
|
||||||
|
if len(rb.session.MetadataSubscriptions()) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
batchId := rb.StartNestedBatch("metadata")
|
||||||
|
defer rb.EndNestedBatch(batchId)
|
||||||
|
|
||||||
|
values := target.ListMetadata()
|
||||||
|
for k, v := range values {
|
||||||
|
if rb.session.isSubscribedTo(k) {
|
||||||
|
visibility := "*"
|
||||||
|
rb.Add(nil, server.name, "METADATA", target.Name(), k, visibility, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, client := range target.Members() {
|
||||||
|
values := client.ListMetadata()
|
||||||
|
for k, v := range values {
|
||||||
|
if rb.session.isSubscribedTo(k) {
|
||||||
|
visibility := "*"
|
||||||
|
rb.Add(nil, server.name, "METADATA", client.Nick(), k, visibility, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var metadataEvilCharsRegexp = regexp.MustCompile("[^A-Za-z0-9_./:-]+")
|
var metadataEvilCharsRegexp = regexp.MustCompile("[^A-Za-z0-9_./:-]+")
|
||||||
|
|
||||||
func metadataKeyIsEvil(key string) bool {
|
func metadataKeyIsEvil(key string) bool {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
func ChunkifyParams(params []string, maxChars int) [][]string {
|
import "iter"
|
||||||
|
|
||||||
|
func ChunkifyParams(params iter.Seq[string], maxChars int) [][]string {
|
||||||
var chunked [][]string
|
var chunked [][]string
|
||||||
|
|
||||||
var acc []string
|
var acc []string
|
||||||
var length = 0
|
var length = 0
|
||||||
|
|
||||||
for _, p := range params {
|
for p := range params {
|
||||||
length = length + len(p) + 1 // (accounting for the space)
|
length = length + len(p) + 1 // (accounting for the space)
|
||||||
|
|
||||||
if length > maxChars {
|
if length > maxChars {
|
||||||
|
|
@ -18,5 +20,9 @@ func ChunkifyParams(params []string, maxChars int) [][]string {
|
||||||
acc = append(acc, p)
|
acc = append(acc, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(acc) != 0 {
|
||||||
|
chunked = append(chunked, acc)
|
||||||
|
}
|
||||||
|
|
||||||
return chunked
|
return chunked
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue