-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
127 lines (108 loc) · 3.94 KB
/
main.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
package main
import (
"bytes"
"context"
"encoding/base64"
"io"
"log"
"net/http"
"raycat/internal/pkg/stats"
"raycat/internal/pkg/tinypool"
"strconv"
"strings"
"github.com/ServiceWeaver/weaver"
"github.com/ServiceWeaver/weaver/metadata"
)
//go:generate weaver generate ./...
var (
bufPool = tinypool.New[bytes.Buffer](tinypool.BufReset)
)
func main() {
if err := weaver.Run(context.Background(), serve); err != nil {
log.Fatal(err)
}
}
// app implements the main component, the entry point to a Service Weaver app.
type app struct {
weaver.Implements[weaver.Main]
configure weaver.Ref[subConfigureProvider]
fileSub weaver.Ref[subFileSourceProvider]
urlSub weaver.Ref[subURLSourceProvider]
lis weaver.Listener `weaver:"lis"`
}
// serve serves HTTP traffic.
func serve(ctx context.Context, app *app) error {
config := app.configure.Get()
subPublishPath, err := config.GetSubPublishPath(ctx)
if err != nil {
app.Logger(ctx).Warn("failed to get sub publish path,will use /subscribe as default", "err", err)
subPublishPath = "/subscribe"
}
if !strings.HasPrefix(subPublishPath, "/") {
subPublishPath = "/" + subPublishPath
}
http.HandleFunc("/stats", stats.Handler)
http.Handle(subPublishPath, weaver.InstrumentHandlerFunc("subscribeCallCount", subShareHandlerApp(app)))
app.Logger(ctx).Info("Listening on...", "address", app.lis)
return http.Serve(app.lis, nil)
}
func subShareHandlerApp(app *app) func(w http.ResponseWriter, _ *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization,profile-web-page-url,profile-update-interval")
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
encoder := base64.NewEncoder(base64.StdEncoding, w)
defer encoder.Close()
buf := bufPool.Get()
defer bufPool.Free(buf)
authParamName, err := app.configure.Get().GetSubAuthParamName(context.Background())
if err != nil {
app.Logger(context.Background()).Warn("failed to get sub auth param name,use default name token", "err", err)
authParamName = "token"
}
privateToken := r.URL.Query().Get(authParamName)
ctx := context.Background()
ctx = metadata.NewContext(ctx, map[string]string{"privateToken": privateToken})
subFilePaths, _ := app.configure.Get().GetSubFilePaths(ctx)
urlSubPaths, timeout, _ := app.configure.Get().GetUrlSubs(ctx)
fileSub, err := app.fileSub.Get().UpdateFileSub(context.Background(), subFilePaths)
if err != nil {
app.Logger(context.Background()).Error("failed to get file sub update", "error", err)
}
urlSub, err := app.urlSub.Get().UpdateUrlSub(context.Background(), urlSubPaths, timeout)
if err != nil {
app.Logger(context.Background()).Error("failed to get url sub update", "error", err)
}
if len(fileSub) > 0 {
if _, err = buf.Write(fileSub); err != nil {
app.Logger(context.Background()).Error("failed to write file sub to buffer", "error", err)
}
}
if len(urlSub) > 0 {
if _, err = buf.Write(urlSub); err != nil {
app.Logger(context.Background()).Error("failed to write url sub to buffer", "error", err)
}
}
// handle for client experience
responseOpt, err := app.configure.Get().GetResponseOption(context.Background())
if err != nil {
app.Logger(context.Background()).Warn("failed to get response option", "error", err)
}
if responseOpt != nil {
if responseOpt.ProfileWebPage != "" {
w.Header().Set("profile-web-page-url", responseOpt.ProfileWebPage)
}
if responseOpt.UpdateIntervalHours > 0 {
w.Header().Set("profile-update-interval", strconv.Itoa(responseOpt.UpdateIntervalHours))
}
}
_, err = io.Copy(encoder, buf)
if err != nil {
app.Logger(context.Background()).Error("failed to copy file to http response", "error", err)
}
}
}