|
1d3caa2…
|
lmata
|
1 |
package sessionrelay |
|
1d3caa2…
|
lmata
|
2 |
|
|
1d3caa2…
|
lmata
|
3 |
import ( |
|
1d3caa2…
|
lmata
|
4 |
"fmt" |
|
1d3caa2…
|
lmata
|
5 |
"os" |
|
1d3caa2…
|
lmata
|
6 |
"path/filepath" |
|
1d3caa2…
|
lmata
|
7 |
"strings" |
|
1d3caa2…
|
lmata
|
8 |
) |
|
1d3caa2…
|
lmata
|
9 |
|
|
1d3caa2…
|
lmata
|
10 |
type BrokerCommand struct { |
|
1d3caa2…
|
lmata
|
11 |
Name string |
|
1d3caa2…
|
lmata
|
12 |
Channel string |
|
1d3caa2…
|
lmata
|
13 |
} |
|
1d3caa2…
|
lmata
|
14 |
|
|
1d3caa2…
|
lmata
|
15 |
func ParseEnvChannels(primary, raw string) []string { |
|
1d3caa2…
|
lmata
|
16 |
if strings.TrimSpace(raw) == "" { |
|
1d3caa2…
|
lmata
|
17 |
return normalizeChannels(primary, nil) |
|
1d3caa2…
|
lmata
|
18 |
} |
|
1d3caa2…
|
lmata
|
19 |
|
|
1d3caa2…
|
lmata
|
20 |
parts := strings.Split(raw, ",") |
|
1d3caa2…
|
lmata
|
21 |
return normalizeChannels(primary, parts) |
|
1d3caa2…
|
lmata
|
22 |
} |
|
1d3caa2…
|
lmata
|
23 |
|
|
1d3caa2…
|
lmata
|
24 |
func ChannelSlugs(channels []string) []string { |
|
1d3caa2…
|
lmata
|
25 |
out := make([]string, 0, len(channels)) |
|
1d3caa2…
|
lmata
|
26 |
for _, channel := range channels { |
|
1d3caa2…
|
lmata
|
27 |
if slug := channelSlug(channel); slug != "" { |
|
1d3caa2…
|
lmata
|
28 |
out = append(out, slug) |
|
1d3caa2…
|
lmata
|
29 |
} |
|
1d3caa2…
|
lmata
|
30 |
} |
|
1d3caa2…
|
lmata
|
31 |
return out |
|
1d3caa2…
|
lmata
|
32 |
} |
|
1d3caa2…
|
lmata
|
33 |
|
|
1d3caa2…
|
lmata
|
34 |
func FormatChannels(channels []string) string { |
|
1d3caa2…
|
lmata
|
35 |
if len(channels) == 0 { |
|
1d3caa2…
|
lmata
|
36 |
return "(none)" |
|
1d3caa2…
|
lmata
|
37 |
} |
|
1d3caa2…
|
lmata
|
38 |
return strings.Join(normalizeChannels("", channels), ", ") |
|
1d3caa2…
|
lmata
|
39 |
} |
|
1d3caa2…
|
lmata
|
40 |
|
|
1d3caa2…
|
lmata
|
41 |
func WriteChannelStateFile(path, control string, channels []string) error { |
|
1d3caa2…
|
lmata
|
42 |
if path == "" { |
|
1d3caa2…
|
lmata
|
43 |
return nil |
|
1d3caa2…
|
lmata
|
44 |
} |
|
1d3caa2…
|
lmata
|
45 |
control = channelSlug(control) |
|
1d3caa2…
|
lmata
|
46 |
channels = normalizeChannels(control, channels) |
|
1d3caa2…
|
lmata
|
47 |
if len(channels) == 0 { |
|
1d3caa2…
|
lmata
|
48 |
return fmt.Errorf("sessionrelay: channel state requires at least one channel") |
|
1d3caa2…
|
lmata
|
49 |
} |
|
1d3caa2…
|
lmata
|
50 |
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { |
|
1d3caa2…
|
lmata
|
51 |
return err |
|
1d3caa2…
|
lmata
|
52 |
} |
|
1d3caa2…
|
lmata
|
53 |
|
|
1d3caa2…
|
lmata
|
54 |
data := strings.Join([]string{ |
|
1d3caa2…
|
lmata
|
55 |
"SCUTTLEBOT_CHANNEL=" + control, |
|
1d3caa2…
|
lmata
|
56 |
"SCUTTLEBOT_CHANNELS=" + strings.Join(ChannelSlugs(channels), ","), |
|
1d3caa2…
|
lmata
|
57 |
"", |
|
1d3caa2…
|
lmata
|
58 |
}, "\n") |
|
1d3caa2…
|
lmata
|
59 |
|
|
1d3caa2…
|
lmata
|
60 |
tmp := path + ".tmp" |
|
1d3caa2…
|
lmata
|
61 |
if err := os.WriteFile(tmp, []byte(data), 0o600); err != nil { |
|
1d3caa2…
|
lmata
|
62 |
return err |
|
1d3caa2…
|
lmata
|
63 |
} |
|
1d3caa2…
|
lmata
|
64 |
return os.Rename(tmp, path) |
|
1d3caa2…
|
lmata
|
65 |
} |
|
1d3caa2…
|
lmata
|
66 |
|
|
1d3caa2…
|
lmata
|
67 |
func RemoveChannelStateFile(path string) error { |
|
1d3caa2…
|
lmata
|
68 |
if path == "" { |
|
1d3caa2…
|
lmata
|
69 |
return nil |
|
1d3caa2…
|
lmata
|
70 |
} |
|
1d3caa2…
|
lmata
|
71 |
if err := os.Remove(path); err != nil && !os.IsNotExist(err) { |
|
1d3caa2…
|
lmata
|
72 |
return err |
|
1d3caa2…
|
lmata
|
73 |
} |
|
1d3caa2…
|
lmata
|
74 |
return nil |
|
1d3caa2…
|
lmata
|
75 |
} |
|
1d3caa2…
|
lmata
|
76 |
|
|
1d3caa2…
|
lmata
|
77 |
func ParseBrokerCommand(text string) (BrokerCommand, bool) { |
|
1d3caa2…
|
lmata
|
78 |
fields := strings.Fields(strings.TrimSpace(text)) |
|
1d3caa2…
|
lmata
|
79 |
if len(fields) == 0 { |
|
1d3caa2…
|
lmata
|
80 |
return BrokerCommand{}, false |
|
1d3caa2…
|
lmata
|
81 |
} |
|
1d3caa2…
|
lmata
|
82 |
|
|
1d3caa2…
|
lmata
|
83 |
switch strings.ToLower(fields[0]) { |
|
1d3caa2…
|
lmata
|
84 |
case "/join": |
|
1d3caa2…
|
lmata
|
85 |
cmd := BrokerCommand{Name: "join"} |
|
1d3caa2…
|
lmata
|
86 |
if len(fields) > 1 { |
|
1d3caa2…
|
lmata
|
87 |
cmd.Channel = normalizeChannel(fields[1]) |
|
1d3caa2…
|
lmata
|
88 |
} |
|
1d3caa2…
|
lmata
|
89 |
return cmd, true |
|
1d3caa2…
|
lmata
|
90 |
case "/part": |
|
1d3caa2…
|
lmata
|
91 |
cmd := BrokerCommand{Name: "part"} |
|
1d3caa2…
|
lmata
|
92 |
if len(fields) > 1 { |
|
1d3caa2…
|
lmata
|
93 |
cmd.Channel = normalizeChannel(fields[1]) |
|
1d3caa2…
|
lmata
|
94 |
} |
|
1d3caa2…
|
lmata
|
95 |
return cmd, true |
|
1d3caa2…
|
lmata
|
96 |
case "/channels": |
|
1d3caa2…
|
lmata
|
97 |
return BrokerCommand{Name: "channels"}, true |
|
1d3caa2…
|
lmata
|
98 |
default: |
|
1d3caa2…
|
lmata
|
99 |
return BrokerCommand{}, false |
|
1d3caa2…
|
lmata
|
100 |
} |
|
1d3caa2…
|
lmata
|
101 |
} |