forked from mhewedy/ews
-
Notifications
You must be signed in to change notification settings - Fork 1
/
request.go
111 lines (90 loc) · 2.32 KB
/
request.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
package ews
import (
"context"
"crypto/md5"
"encoding/hex"
"encoding/xml"
"io"
"strconv"
"sync/atomic"
"github.com/Abovo-Media/go-ews/ewsxml"
"github.com/go-pogo/errors"
"github.com/go-pogo/writing"
)
const panicNilBody = "ews.NewRequest: body must be a non-nil value"
type Request struct {
ctx context.Context
head *ewsxml.Header
body interface{}
}
func NewRequest(ctx context.Context, head *ewsxml.Header, body interface{}) *Request {
if ctx == nil {
ctx = context.Background()
}
if head == nil {
head = new(ewsxml.Header)
}
if body == nil {
panic(panicNilBody)
}
return &Request{
ctx: context.WithValue(ctx, requestIdKey{}, genRequestId()),
head: head,
body: body,
}
}
func (r *Request) Header() *ewsxml.Header { return r.head }
func (r *Request) Body() interface{} { return r.body }
//goland:noinspection HttpUrlsUsage
var (
soapStart = []byte(xml.Header + `<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns="http://schemas.microsoft.com/exchange/services/2006/types">`)
soapBodyStart = []byte(`<soap:Body>`)
soapEnd = []byte(`</soap:Body></soap:Envelope>`)
)
func (r *Request) WriteTo(w io.Writer) (int64, error) {
x, err := xml.Marshal(r.head)
if err != nil {
return 0, errors.WithStack(err)
}
cw := writing.ToCountingStringWriter(w)
_, _ = cw.Write(soapStart)
_, _ = cw.Write(x)
_, _ = cw.Write(soapBodyStart)
switch b := r.body.(type) {
case []byte:
_, _ = cw.Write(b)
case string:
_, _ = cw.WriteString(b)
case io.WriterTo:
_, _ = b.WriteTo(cw)
default:
if x, err = xml.Marshal(b); err != nil {
return 0, errors.WithStack(err)
} else {
_, _ = cw.Write(x)
}
}
_, _ = cw.Write(soapEnd)
return int64(cw.Count()), errors.Combine(cw.Errors()...)
}
type (
requestIdKey struct{}
attemptKey struct{}
)
func RequestId(ctx context.Context) (string, bool) {
v, ok := ctx.Value(requestIdKey{}).(string)
return v, ok
}
func RequestAttempt(ctx context.Context) (uint8, bool) {
v, ok := ctx.Value(attemptKey{}).(uint8)
return v, ok
}
var atomicRequestId atomic.Uint64
func genRequestId() string {
uid := strconv.FormatUint(atomicRequestId.Add(1), 10)
h := md5.Sum([]byte(uid))
return hex.EncodeToString(h[:])
}