-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
101 lines (86 loc) · 2.3 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
package main
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"log"
"net/http"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
"google.golang.org/protobuf/proto"
greetv1 "github.com/sudorandom/sudorandom.dev/grpc-from-scratch-part-2/gen"
)
var (
gRPCStatusHeader = "Grpc-Status"
gRPCMessageHeader = "Grpc-Message"
)
func main() {
mux := http.NewServeMux()
mux.Handle("/greet.v1.GreetService/Greet", http.HandlerFunc(greetHandler))
log.Fatal(http.ListenAndServe(
"localhost:9000",
h2c.NewHandler(mux, &http2.Server{}),
))
}
func greetHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Trailer", gRPCStatusHeader+", "+gRPCMessageHeader)
w.Header().Set("Content-Type", "application/grpc+proto")
w.WriteHeader(http.StatusOK)
defer r.Body.Close()
// Read Request
req := &greetv1.GreetRequest{}
if err := readMessage(r.Body, req); err != nil {
writeError(w, err)
return
}
// Write Response
if err := writeMessage(w, &greetv1.GreetResponse{
Greeting: fmt.Sprintf("Hello, %s!", req.Name),
}); err != nil {
writeError(w, err)
return
}
w.Header().Set(gRPCStatusHeader, "0")
w.Header().Set(gRPCMessageHeader, "")
}
func writeError(w http.ResponseWriter, err error) {
log.Printf("read err: %s", err)
w.Header().Set(gRPCStatusHeader, "1")
w.Header().Set(gRPCMessageHeader, err.Error())
}
func writeMessage(w io.Writer, protoMsg proto.Message) error {
fmt.Println("send->", protoMsg)
msg, err := proto.Marshal(protoMsg)
if err != nil {
return err
}
prefix := make([]byte, 5)
binary.BigEndian.PutUint32(prefix[1:], uint32(len(msg)))
if _, err := w.Write(prefix); err != nil {
return err
}
if _, err := w.Write(msg); err != nil {
return err
}
return nil
}
func readMessage(body io.Reader, protoResp proto.Message) error {
prefixes := [5]byte{}
if _, err := io.ReadFull(body, prefixes[:]); err != nil {
if err == io.EOF {
return err
}
return fmt.Errorf("failed to read envelope: %w", err)
}
buffer := &bytes.Buffer{}
msgSize := int64(binary.BigEndian.Uint32(prefixes[1:5]))
if _, err := io.CopyN(buffer, body, msgSize); err != nil {
return fmt.Errorf("failed to read msg: %w", err)
}
if err := proto.Unmarshal(buffer.Bytes(), protoResp); err != nil {
return fmt.Errorf("failed to unmarshal resp: %w", err)
}
fmt.Println("recv<-", protoResp)
return nil
}