-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathserver.go
122 lines (107 loc) · 3.15 KB
/
server.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
package mongo
import (
"context"
"errors"
"fmt"
"io"
"net/url"
"regexp"
"strings"
"go.mongodb.org/mongo-driver/bson"
driver "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// Connect to mongo url and return client. Supports expanded url params to pass a set of custom values in the url
func Connect(ctx context.Context, opts *options.ClientOptions, u string, extras ...string) (*driver.Client, map[string]interface{}, error) {
mongoURL, extMap, err := parseExtMongoURI(u, extras)
if err != nil {
return nil, nil, fmt.Errorf("can't parse mongo url: %w", err)
}
res, err := driver.Connect(ctx, opts.ApplyURI(mongoURL))
if err != nil {
return nil, nil, fmt.Errorf("can't connect to mongo: %w", err)
}
if err = res.Ping(ctx, nil); err != nil {
return nil, nil, fmt.Errorf("can't ping mongo: %w", err)
}
return res, extMap, nil
}
// parseExtMongoURI extracts extra params from extras list and remove them from the url.
// Input example: mongodb://user:[email protected]:27017/test?ssl=true&ava_db=db1&ava_coll=coll1
func parseExtMongoURI(u string, extras []string) (host string, ex map[string]interface{}, err error) {
if u == "" {
return "", nil, errors.New("empty url")
}
if len(extras) == 0 {
return u, nil, nil
}
exMap := map[string]interface{}{}
uu, err := url.Parse(u)
if err != nil {
return "", nil, err
}
q := uu.Query()
for _, ex := range extras {
if val := uu.Query().Get(ex); val != "" {
exMap[ex] = val
}
q.Del(ex)
}
uu.RawQuery = q.Encode()
return uu.String(), exMap, nil
}
// PrepSort prepares sort params for mongo driver and returns bson.D
// Input string provided as [+|-]field1,[+|-]field2,[+|-]field3...
// + means ascending, - means descending. Lack of + or - in the beginning of the field name means ascending sort.
func PrepSort(sort ...string) bson.D {
res := bson.D{}
for _, s := range sort {
if s == "" {
continue
}
s = strings.TrimSpace(s)
switch s[0] {
case '-':
res = append(res, bson.E{Key: s[1:], Value: -1})
case '+':
res = append(res, bson.E{Key: s[1:], Value: 1})
default:
res = append(res, bson.E{Key: s, Value: 1})
}
}
return res
}
// PrepIndex prepares index params for mongo driver and returns IndexModel
func PrepIndex(keys ...string) driver.IndexModel {
return driver.IndexModel{Keys: PrepSort(keys...)}
}
// Bind request json body from io.Reader to bson record
func Bind(r io.Reader, v interface{}) error {
body, err := io.ReadAll(r)
if err != nil {
return err
}
return bson.UnmarshalExtJSON(body, false, v)
}
var reMongoURL = regexp.MustCompile(`mongodb(\+srv)?://([^:]+):([^@]+)@[^/]+/?.*`)
// SecretsMongoUrls retrieves passwords from mongo urls.
// this is needed to pass mongo password to the logging masking function
func SecretsMongoUrls(urls ...string) (res []string) {
res = []string{}
mongoPasswd := func(murl string) (string, bool) {
if !reMongoURL.MatchString(murl) {
return "", false
}
elems := reMongoURL.FindStringSubmatch(murl)
if len(elems) < 4 {
return "", false
}
return elems[3], true
}
for _, u := range urls {
if secret, ok := mongoPasswd(u); ok {
res = append(res, secret)
}
}
return res
}