-
Notifications
You must be signed in to change notification settings - Fork 0
/
timeline.go
124 lines (103 loc) · 2.88 KB
/
timeline.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
package main
import (
"mime"
"net/http"
"strconv"
"time"
"github.com/jackc/pgx/v5/pgtype"
auth "github.com/jaydee029/Verses/internal/auth"
"github.com/jaydee029/Verses/internal/database"
)
type timeline_item struct {
Id int `json:"id"`
Userid pgtype.UUID `json:"userid,omitempty"`
Post Prose `json:"prose"`
}
type timelineclient struct {
timeline chan timeline_item
Userid pgtype.UUID
}
func (cfg *apiconfig) timeline(w http.ResponseWriter, r *http.Request) {
token, err := auth.BearerHeader(r.Header)
if err != nil {
respondWithError(w, http.StatusUnauthorized, err.Error())
return
}
authorid, err := auth.ValidateToken(token, cfg.jwtsecret)
if err != nil {
respondWithError(w, http.StatusUnauthorized, err.Error())
return
}
var pgUUID pgtype.UUID
err = pgUUID.Scan(authorid)
if err != nil {
respondWithError(w, http.StatusInternalServerError, err.Error())
return
}
if content_type, _, err := mime.ParseMediaType(r.Header.Get("Accept")); err == nil && content_type == "text/event-stream" {
cfg.subscribeTotimeline(w, r.Context(), pgUUID)
return
}
var before pgtype.Timestamp
beforestr := r.URL.Query().Get("before")
if beforestr != "" {
parsedTime, err := time.Parse(time.RFC3339, beforestr)
if err != nil {
respondWithError(w, http.StatusBadRequest, "Invalid timestamp format")
return
}
err = before.Scan(parsedTime)
if err != nil {
respondWithError(w, http.StatusInternalServerError, err.Error())
}
}
limitstr := r.URL.Query().Get("limit")
if limitstr == "" {
limitstr = "20"
}
limit, err := strconv.ParseInt(limitstr, 10, 32)
if err != nil {
respondWithError(w, http.StatusInternalServerError, err.Error())
}
err = before.Scan(beforestr)
if err != nil {
respondWithError(w, http.StatusInternalServerError, err.Error())
return
}
tl_items, err := cfg.DB.GetTimeline(r.Context(), database.GetTimelineParams{
AuthorID: pgUUID,
Column2: before,
Limit: int32(limit),
})
if err != nil {
respondWithError(w, http.StatusInternalServerError, "timeline items couldn't be fetched")
return
}
var timeline []timeline_item
for _, k := range tl_items {
timeline = append(timeline, timeline_item{
Id: int(k.ID),
Post: Prose{
ID: k.ProseID,
Username: k.Username,
Body: k.Body,
Created_at: k.CreatedAt,
Updated_at: k.UpdatedAt,
Mine: k.Mine,
Liked: k.Liked,
Likes_count: int(k.Likes),
Comments: int(k.Comments),
},
})
respondWithJson(w, http.StatusOK, timeline)
}
}
func (cfg *apiconfig) Broadcasttimeline(ti timeline_item) {
cfg.Clients.timelineClients.Range(func(key, _ any) bool {
client := key.(*timelineclient)
if client.Userid == ti.Userid {
client.timeline <- ti
}
return true
})
}