-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrunner_comments.go
More file actions
115 lines (109 loc) · 2.47 KB
/
Copy pathrunner_comments.go
File metadata and controls
115 lines (109 loc) · 2.47 KB
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
package main
import (
"bufio"
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"strings"
"time"
)
var shareCommentNotifier = newCommentNotifier()
func listenShareComments(ctx context.Context, eventsURL, filename string, n *commentNotifier) {
backoff := time.Second
for {
err := consumeCommentSSE(ctx, eventsURL, filename, n)
if ctx.Err() != nil {
return
}
if err != nil && err != io.EOF {
log.Printf("comment sse %s: %v", filename, err)
}
select {
case <-ctx.Done():
return
case <-time.After(backoff):
}
if backoff < 30*time.Second {
backoff *= 2
}
}
}
func consumeCommentSSE(ctx context.Context, eventsURL, filename string, n *commentNotifier) error {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, eventsURL, nil)
if err != nil {
return err
}
req.Header.Set("Accept", "text/event-stream")
client := &http.Client{Timeout: 0}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("HTTP %d", resp.StatusCode)
}
return readCommentSSE(resp.Body, filename, n)
}
func readCommentSSE(r io.Reader, filename string, n *commentNotifier) error {
sc := bufio.NewScanner(r)
sc.Buffer(make([]byte, 0, 64*1024), 8*1024*1024)
var event string
var data bytes.Buffer
flush := func() {
if event == "comment" && data.Len() > 0 {
handleCommentEvent(data.Bytes(), filename, n)
}
event = ""
data.Reset()
}
for sc.Scan() {
line := sc.Text()
if line == "" {
flush()
continue
}
if strings.HasPrefix(line, "event:") {
event = strings.TrimSpace(strings.TrimPrefix(line, "event:"))
continue
}
if strings.HasPrefix(line, "data:") {
if data.Len() > 0 {
data.WriteByte('\n')
}
data.WriteString(strings.TrimSpace(strings.TrimPrefix(line, "data:")))
}
}
flush()
return sc.Err()
}
func handleCommentEvent(raw []byte, filename string, n *commentNotifier) {
var payload struct {
Op string `json:"op"`
Thread struct {
Comments []commentView `json:"comments"`
} `json:"thread"`
}
if err := json.Unmarshal(raw, &payload); err != nil {
return
}
if payload.Op != "created" && payload.Op != "replied" {
return
}
if len(payload.Thread.Comments) == 0 {
return
}
last := payload.Thread.Comments[len(payload.Thread.Comments)-1]
if last.AuthorKind == "author" || last.AuthorKind == "agent" {
return
}
name := last.AuthorName
if name == "" {
name = "Someone"
}
n.note(filename, filename, name)
}