-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathutils.go
137 lines (120 loc) · 3.36 KB
/
utils.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
126
127
128
129
130
131
132
133
134
135
136
137
package wampus
import (
"context"
"errors"
"github.com/bwmarrin/discordgo"
"github.com/gammazero/nexus/v3/client"
"github.com/gammazero/nexus/v3/wamp"
"net/http"
"strconv"
"strings"
)
// raceContext races a context against a channel.
// If the context completes faster than the channel, the context's error is
// returned.
// In case the channel completes faster than the context nil is returned.
func raceContext(ctx context.Context, done <-chan struct{}) error {
select {
case <-done:
return nil
case <-ctx.Done():
return ctx.Err()
}
}
// fnRaceContext races a function against a context.
// If the context completes first, the context's error is returned.
// Otherwise, the result of the function is returned.
//
// This function primarily serves to make it possible to silently abort blocking
// functions without context support.
func fnRaceContext(ctx context.Context, fn func() error) error {
var fErr error
done := make(chan struct{})
go func() {
defer close(done)
fErr = fn()
}()
if err := raceContext(ctx, done); err != nil {
return err
}
return fErr
}
// emptyResult represents a completely empty invoke result.
var emptyResult = client.InvokeResult{}
// resultFromErrorURI creates an invoke result with the given error uri.
// Additional arguments are passed to the result's arguments.
func resultFromErrorURI(uri wamp.URI, args ...interface{}) client.InvokeResult {
return client.InvokeResult{
Err: uri,
Args: args,
}
}
// resultFromRESTError creates an invoke result from a discord rest error.
func resultFromRESTError(err discordgo.RESTError) client.InvokeResult {
var code int
if err.Message == nil {
code = err.Response.StatusCode
} else {
code = err.Message.Code
}
var res client.InvokeResult
switch code {
case http.StatusUnauthorized:
res = resultFromErrorURI(UnauthorizedURI)
case http.StatusNotFound:
res = resultFromErrorURI(NotFoundURI)
default:
res = resultFromErrorURI(ErrURI, "unexpected error response", err.Error())
}
if res.Kwargs == nil {
res.Kwargs = wamp.Dict{}
}
res.Kwargs["status_code"] = err.Response.StatusCode
return res
}
// resultFromDiscordErr creates a invoke result from an error returned by a
// discordgo function.
// Passing a nil error will cause the function to panic!
func resultFromDiscordErr(err error) client.InvokeResult {
if err == nil {
panic("passed nil error")
}
switch err := err.(type) {
case discordgo.RESTError:
return resultFromRESTError(err)
default:
return resultFromErrorURI(ErrURI, "unknown error", err.Error())
}
}
// joinErrors combines all non-nil errors into a single error.
// If no non-nil error is passed, the result is nil.
// If exactly one non-nil error is passed, the result is that error.
func joinErrors(errs ...error) error {
var lastErr error
var errStrings []string
for _, err := range errs {
if err != nil {
lastErr = err
errStrings = append(errStrings, err.Error())
}
}
switch len(errStrings) {
case 0:
return nil
case 1:
return lastErr
default:
return errors.New(strings.Join(errStrings, "\n"))
}
}
// asSnowflake is an extended type assertion which handles Twitter snowflakes.
// Either integers or strings are accepted.
func asSnowflake(v interface{}) (string, bool) {
if s, ok := wamp.AsString(v); ok {
return s, true
} else if i, ok := wamp.AsInt64(v); ok {
return strconv.FormatInt(i, 10), true
} else {
return "", false
}
}