prepare more reddit api

This commit is contained in:
Tigor Hutasuhut 2024-04-10 22:38:19 +07:00
parent 8ec1175fe4
commit 63f17437b7
12 changed files with 155 additions and 218 deletions

View file

@ -7,6 +7,7 @@ import (
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
"github.com/teivah/broadcast" "github.com/teivah/broadcast"
"github.com/tigorlazuardi/redmage/api/bmessage"
"github.com/tigorlazuardi/redmage/config" "github.com/tigorlazuardi/redmage/config"
"github.com/tigorlazuardi/redmage/db/queries" "github.com/tigorlazuardi/redmage/db/queries"
"github.com/tigorlazuardi/redmage/pkg/errs" "github.com/tigorlazuardi/redmage/pkg/errs"
@ -20,7 +21,7 @@ type API struct {
scheduler *cron.Cron scheduler *cron.Cron
scheduleMap map[cron.EntryID]queries.Subreddit scheduleMap map[cron.EntryID]queries.Subreddit
downloadBroadcast *broadcast.Relay[DownloadStatusMessage] downloadBroadcast *broadcast.Relay[bmessage.DownloadStatusMessage]
config *config.Config config *config.Config
} }
@ -31,7 +32,7 @@ func New(q *queries.Queries, db *sql.DB, cfg *config.Config) *API {
db: db, db: db,
scheduler: cron.New(), scheduler: cron.New(),
scheduleMap: make(map[cron.EntryID]queries.Subreddit, 8), scheduleMap: make(map[cron.EntryID]queries.Subreddit, 8),
downloadBroadcast: broadcast.NewRelay[DownloadStatusMessage](), downloadBroadcast: broadcast.NewRelay[bmessage.DownloadStatusMessage](),
config: cfg, config: cfg,
} }
} }

24
api/bmessage/bmessage.go Normal file
View file

@ -0,0 +1,24 @@
package bmessage
import (
"github.com/alecthomas/units"
)
type ImageMetadata struct {
URL string
Height int
Width int
ThumbnailURL string
ThumbnailHeight int
ThumbnailWidth int
}
type DownloadStatusMessage struct {
Metadata ImageMetadata
ContantLength units.MetricBytes
Downloaded units.MetricBytes
Subreddit string
PostURL string
PostID string
Error error
}

View file

@ -11,6 +11,6 @@ type DownloadSubredditPostsParams struct {
Limit int Limit int
} }
func (api *API) DownloadSubredditPosts(ctx context.Context, subredditName string, params DownloadSubredditParams) (posts []reddit.Post, err error) { func (api *API) DownloadSubredditPosts(ctx context.Context, subredditName string, params DownloadSubredditParams) (posts []reddit.Listing, err error) {
return posts, err return posts, err
} }

View file

@ -0,0 +1,27 @@
package reddit
import (
"context"
"io"
"github.com/tigorlazuardi/redmage/api/bmessage"
)
type DownloadStatusBroadcaster interface {
Broadcast(bmessage.DownloadStatusMessage)
}
type NullDownloadStatusBroadcaster struct{}
func (NullDownloadStatusBroadcaster) Broadcast(bmessage.DownloadStatusMessage) {}
type PostImage struct {
ImageURL string
ImageFile io.Reader
ThumbnailURL string
ThumbnailFile io.Reader
}
func (reddit *Reddit) DownloadImage(ctx context.Context, post Post, broadcaster DownloadStatusBroadcaster) (images PostImage, err error) {
return images, err
}

View file

@ -1 +1,39 @@
package reddit package reddit
import (
"io"
"net/http"
)
type ProgressReader struct {
OnProgress func(downloaded int64, contentLength int64, err error)
OnClose func(closeErr error)
reader io.ReadCloser
contentLength int64
downloaded int64
}
func (progressReader *ProgressReader) WrapHTTPResponse(resp *http.Response) *http.Response {
progressReader.reader = resp.Body
progressReader.contentLength = resp.ContentLength
resp.Body = progressReader
return resp
}
func (progressReader *ProgressReader) Read(p []byte) (n int, err error) {
n, err = progressReader.reader.Read(p)
progressReader.downloaded += int64(n)
if progressReader.OnProgress != nil {
progressReader.OnProgress(progressReader.downloaded, progressReader.contentLength, err)
}
return n, err
}
func (progressReader *ProgressReader) Close() error {
err := progressReader.reader.Close()
if progressReader.OnClose != nil {
progressReader.OnClose(err)
}
return err
}

View file

@ -7,6 +7,7 @@ import (
"io" "io"
"log/slog" "log/slog"
"net/http" "net/http"
"strings"
"github.com/tigorlazuardi/redmage/pkg/errs" "github.com/tigorlazuardi/redmage/pkg/errs"
) )
@ -34,7 +35,7 @@ type GetPostsParam struct {
SubredditType SubredditType SubredditType SubredditType
} }
func (reddit *Reddit) GetPosts(ctx context.Context, params GetPostsParam) (posts []Post, err error) { func (reddit *Reddit) GetPosts(ctx context.Context, params GetPostsParam) (posts Listing, err error) {
url := fmt.Sprintf("https://reddit.com/%s/%s.json?limit=%d&page=%d", params.SubredditType.Code(), params.Subreddit, params.Limit, params.Page) url := fmt.Sprintf("https://reddit.com/%s/%s.json?limit=%d&page=%d", params.SubredditType.Code(), params.Subreddit, params.Limit, params.Page)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, http.NoBody) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, http.NoBody)
if err != nil { if err != nil {
@ -51,7 +52,7 @@ func (reddit *Reddit) GetPosts(ctx context.Context, params GetPostsParam) (posts
body, _ := io.ReadAll(res.Body) body, _ := io.ReadAll(res.Body)
return posts, errs.Fail("reddit: unexpected status code when executing GetPosts", return posts, errs.Fail("reddit: unexpected status code when executing GetPosts",
slog.Group("request", "url", url, "params", params), slog.Group("request", "url", url, "params", params),
slog.Group("response", "status_code", res.StatusCode, "body", json.RawMessage(body)), slog.Group("response", "status_code", res.StatusCode, "body", formatLogBody(res, body)),
) )
} }
@ -62,3 +63,10 @@ func (reddit *Reddit) GetPosts(ctx context.Context, params GetPostsParam) (posts
return posts, nil return posts, nil
} }
func formatLogBody(res *http.Response, body []byte) any {
if strings.HasPrefix(res.Header.Get("Content-Type"), "application/json") {
return json.RawMessage(body)
}
return string(body)
}

View file

@ -1,10 +1,14 @@
package reddit package reddit
type Post struct { type Listing struct {
Kind string `json:"kind"` Kind string `json:"kind"`
Data Data `json:"data"` Data Data `json:"data"`
} }
func (l *Listing) GetPosts() []Post {
return l.Data.Children
}
type ( type (
MediaEmbed struct{} MediaEmbed struct{}
SecureMediaEmbed struct{} SecureMediaEmbed struct{}
@ -65,7 +69,7 @@ type AuthorFlairRichtext struct {
E string `json:"e"` E string `json:"e"`
T string `json:"t"` T string `json:"t"`
} }
type ChildrenData struct { type PostData struct {
ApprovedAtUtc any `json:"approved_at_utc"` ApprovedAtUtc any `json:"approved_at_utc"`
Subreddit string `json:"subreddit"` Subreddit string `json:"subreddit"`
Selftext string `json:"selftext"` Selftext string `json:"selftext"`
@ -176,16 +180,44 @@ type ChildrenData struct {
NumCrossposts int `json:"num_crossposts"` NumCrossposts int `json:"num_crossposts"`
Media any `json:"media"` Media any `json:"media"`
IsVideo bool `json:"is_video"` IsVideo bool `json:"is_video"`
PostHint string `json:"post_hint"`
Preview Preview `json:"preview"`
} }
type Children struct {
Kind string `json:"kind"` type Post struct {
Data ChildrenData `json:"data,omitempty"` Kind string `json:"kind"`
Data PostData `json:"data,omitempty"`
} }
func (post *Post) IsImagePost() bool {
return post.Data.PostHint == "image"
}
func (post *Post) GetImageURL() string {
return post.Data.URL
}
func (post *Post) GetImageSize() (height, width int) {
if len(post.Data.Preview.Images) == 0 {
return 0, 0
}
source := post.Data.Preview.Images[0].Source
return source.Height, source.Width
}
func (post *Post) GetThumbnailURL() string {
return post.Data.Thumbnail
}
func (post *Post) GetThumbnailSize() (height, width int) {
return post.Data.ThumbnailHeight, post.Data.ThumbnailWidth
}
type Data struct { type Data struct {
After string `json:"after"` After string `json:"after"`
Dist int `json:"dist"` Dist int `json:"dist"`
Modhash string `json:"modhash"` Modhash string `json:"modhash"`
GeoFilter any `json:"geo_filter"` GeoFilter any `json:"geo_filter"`
Children []Children `json:"children"` Children []Post `json:"children"`
Before any `json:"before"` Before any `json:"before"`
} }

View file

@ -1,191 +0,0 @@
package subredditpost
type SubredditPost struct {
Kind string `json:"kind"`
Data Data `json:"data"`
}
type (
MediaEmbed struct{}
SecureMediaEmbed struct{}
Gildings struct{}
Source struct {
URL string `json:"url"`
Width int `json:"width"`
Height int `json:"height"`
}
)
type Resolutions struct {
URL string `json:"url"`
Width int `json:"width"`
Height int `json:"height"`
}
type (
Variants struct{}
Images struct {
Source Source `json:"source"`
Resolutions []Resolutions `json:"resolutions"`
Variants Variants `json:"variants"`
ID string `json:"id"`
}
)
type Preview struct {
Images []Images `json:"images"`
Enabled bool `json:"enabled"`
}
type LinkFlairRichtext struct {
E string `json:"e"`
T string `json:"t"`
}
type ThumbnailPreview struct {
Y int `json:"y"`
X int `json:"x"`
U string `json:"u"`
}
type MediaMetadata struct {
Status string `json:"status"`
Kind string `json:"e"`
Mimetype string `json:"m"`
ExtraThumbnails []ThumbnailPreview `json:"p"`
Thumbnail ThumbnailPreview `json:"s"`
ID string `json:"id"`
}
type Items struct {
OutboundURL string `json:"outbound_url,omitempty"`
MediaID string `json:"media_id"`
ID int `json:"id"`
}
type GalleryData struct {
Items []Items `json:"items"`
}
type AuthorFlairRichtext struct {
E string `json:"e"`
T string `json:"t"`
}
type ChildrenData struct {
ApprovedAtUtc any `json:"approved_at_utc"`
Subreddit string `json:"subreddit"`
Selftext string `json:"selftext"`
AuthorFullname string `json:"author_fullname"`
Saved bool `json:"saved"`
ModReasonTitle any `json:"mod_reason_title"`
Gilded int `json:"gilded"`
Clicked bool `json:"clicked"`
IsGallery bool `json:"is_gallery"`
Title string `json:"title"`
LinkFlairRichtext []LinkFlairRichtext `json:"link_flair_richtext"`
SubredditNamePrefixed string `json:"subreddit_name_prefixed"`
Hidden bool `json:"hidden"`
Pwls int `json:"pwls"`
LinkFlairCSSClass string `json:"link_flair_css_class"`
Downs int `json:"downs"`
ThumbnailHeight int `json:"thumbnail_height"`
TopAwardedType any `json:"top_awarded_type"`
HideScore bool `json:"hide_score"`
MediaMetadata map[string]MediaMetadata `json:"media_metadata"`
Name string `json:"name"`
Quarantine bool `json:"quarantine"`
LinkFlairTextColor any `json:"link_flair_text_color"`
UpvoteRatio float64 `json:"upvote_ratio"`
AuthorFlairBackgroundColor any `json:"author_flair_background_color"`
Ups int `json:"ups"`
Domain string `json:"domain"`
MediaEmbed MediaEmbed `json:"media_embed"`
ThumbnailWidth int `json:"thumbnail_width"`
AuthorFlairTemplateID string `json:"author_flair_template_id"`
IsOriginalContent bool `json:"is_original_content"`
UserReports []any `json:"user_reports"`
SecureMedia any `json:"secure_media"`
IsRedditMediaDomain bool `json:"is_reddit_media_domain"`
IsMeta bool `json:"is_meta"`
Category any `json:"category"`
SecureMediaEmbed SecureMediaEmbed `json:"secure_media_embed"`
GalleryData GalleryData `json:"gallery_data"`
LinkFlairText string `json:"link_flair_text"`
CanModPost bool `json:"can_mod_post"`
Score int `json:"score"`
ApprovedBy any `json:"approved_by"`
IsCreatedFromAdsUI bool `json:"is_created_from_ads_ui"`
AuthorPremium bool `json:"author_premium"`
Thumbnail string `json:"thumbnail"`
Edited bool `json:"edited"`
AuthorFlairCSSClass string `json:"author_flair_css_class"`
AuthorFlairRichtext []AuthorFlairRichtext `json:"author_flair_richtext"`
Gildings Gildings `json:"gildings"`
ContentCategories any `json:"content_categories"`
IsSelf bool `json:"is_self"`
SubredditType string `json:"subreddit_type"`
Created int `json:"created"`
LinkFlairType string `json:"link_flair_type"`
Wls int `json:"wls"`
RemovedByCategory any `json:"removed_by_category"`
BannedBy any `json:"banned_by"`
AuthorFlairType string `json:"author_flair_type"`
TotalAwardsReceived int `json:"total_awards_received"`
AllowLiveComments bool `json:"allow_live_comments"`
SelftextHTML any `json:"selftext_html"`
Likes any `json:"likes"`
SuggestedSort any `json:"suggested_sort"`
BannedAtUtc any `json:"banned_at_utc"`
URLOverriddenByDest string `json:"url_overridden_by_dest"`
ViewCount any `json:"view_count"`
Archived bool `json:"archived"`
NoFollow bool `json:"no_follow"`
IsCrosspostable bool `json:"is_crosspostable"`
Pinned bool `json:"pinned"`
Over18 bool `json:"over_18"`
AllAwardings []any `json:"all_awardings"`
Awarders []any `json:"awarders"`
MediaOnly bool `json:"media_only"`
CanGild bool `json:"can_gild"`
Spoiler bool `json:"spoiler"`
Locked bool `json:"locked"`
AuthorFlairText string `json:"author_flair_text"`
TreatmentTags []any `json:"treatment_tags"`
Visited bool `json:"visited"`
RemovedBy any `json:"removed_by"`
ModNote any `json:"mod_note"`
Distinguished any `json:"distinguished"`
SubredditID string `json:"subreddit_id"`
AuthorIsBlocked bool `json:"author_is_blocked"`
ModReasonBy any `json:"mod_reason_by"`
NumReports any `json:"num_reports"`
RemovalReason any `json:"removal_reason"`
LinkFlairBackgroundColor any `json:"link_flair_background_color"`
ID string `json:"id"`
IsRobotIndexable bool `json:"is_robot_indexable"`
ReportReasons any `json:"report_reasons"`
Author string `json:"author"`
DiscussionType any `json:"discussion_type"`
NumComments int `json:"num_comments"`
SendReplies bool `json:"send_replies"`
WhitelistStatus string `json:"whitelist_status"`
ContestMode bool `json:"contest_mode"`
ModReports []any `json:"mod_reports"`
AuthorPatreonFlair bool `json:"author_patreon_flair"`
AuthorFlairTextColor string `json:"author_flair_text_color"`
Permalink string `json:"permalink"`
ParentWhitelistStatus string `json:"parent_whitelist_status"`
Stickied bool `json:"stickied"`
URL string `json:"url"`
SubredditSubscribers int `json:"subreddit_subscribers"`
CreatedUtc int `json:"created_utc"`
NumCrossposts int `json:"num_crossposts"`
Media any `json:"media"`
IsVideo bool `json:"is_video"`
}
type Children struct {
Kind string `json:"kind"`
Data ChildrenData `json:"data,omitempty"`
}
type Data struct {
After string `json:"after"`
Dist int `json:"dist"`
Modhash string `json:"modhash"`
GeoFilter any `json:"geo_filter"`
Children []Children `json:"children"`
Before any `json:"before"`
}

View file

@ -7,6 +7,7 @@ CREATE TABLE images(
title VARCHAR(255) NOT NULL, title VARCHAR(255) NOT NULL,
post_id VARCHAR(50) NOT NULL, post_id VARCHAR(50) NOT NULL,
post_url VARCHAR(255) NOT NULL, post_url VARCHAR(255) NOT NULL,
post_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
poster VARCHAR(50) NOT NULL, poster VARCHAR(50) NOT NULL,
poster_url VARCHAR(255) NOT NULL, poster_url VARCHAR(255) NOT NULL,
image_relative_path VARCHAR(255) NOT NULL, image_relative_path VARCHAR(255) NOT NULL,

7
go.mod
View file

@ -5,6 +5,7 @@ go 1.22.1
require ( require (
github.com/a-h/templ v0.2.648 github.com/a-h/templ v0.2.648
github.com/adrg/xdg v0.4.0 github.com/adrg/xdg v0.4.0
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9
github.com/fatih/color v1.16.0 github.com/fatih/color v1.16.0
github.com/go-chi/chi/v5 v5.0.12 github.com/go-chi/chi/v5 v5.0.12
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
@ -20,25 +21,23 @@ require (
github.com/mattn/go-isatty v0.0.20 github.com/mattn/go-isatty v0.0.20
github.com/mattn/go-sqlite3 v1.14.6 github.com/mattn/go-sqlite3 v1.14.6
github.com/pressly/goose/v3 v3.19.2 github.com/pressly/goose/v3 v3.19.2
github.com/robfig/cron/v3 v3.0.0
github.com/simukti/sqldb-logger v0.0.0-20230108155151-646c1a075551 github.com/simukti/sqldb-logger v0.0.0-20230108155151-646c1a075551
github.com/spf13/cobra v1.8.0 github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/teivah/broadcast v0.1.0
) )
require ( require (
github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jonboulle/clockwork v0.4.0 // indirect
github.com/knadh/koanf/maps v0.1.1 // indirect github.com/knadh/koanf/maps v0.1.1 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/mfridman/interpolate v0.0.2 // indirect github.com/mfridman/interpolate v0.0.2 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/robfig/cron/v3 v3.0.0 // indirect
github.com/sethvargo/go-retry v0.2.4 // indirect github.com/sethvargo/go-retry v0.2.4 // indirect
github.com/teivah/broadcast v0.1.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 // indirect golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 // indirect
golang.org/x/sync v0.6.0 // indirect golang.org/x/sync v0.6.0 // indirect

10
go.sum
View file

@ -14,6 +14,8 @@ github.com/a-h/templ v0.2.648 h1:A1ggHGIE7AONOHrFaDTM8SrqgqHL6fWgWCijQ21Zy9I=
github.com/a-h/templ v0.2.648/go.mod h1:SA7mtYwVEajbIXFRh3vKdYm/4FYyLQAtPH1+KxzGPA8= github.com/a-h/templ v0.2.648/go.mod h1:SA7mtYwVEajbIXFRh3vKdYm/4FYyLQAtPH1+KxzGPA8=
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 h1:ez/4by2iGztzR4L0zgAOR8lTQK9VlyBVVd7G4omaOQs=
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h1:goHVqTbFX3AIo0tzGr14pgfAW2ZfPChKO21Z9MGf/gk= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h1:goHVqTbFX3AIo0tzGr14pgfAW2ZfPChKO21Z9MGf/gk=
@ -47,8 +49,6 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-co-op/gocron/v2 v2.2.9 h1:aoKosYWSSdXFLecjFWX1i8+R6V7XdZb8sB2ZKAY5Yis=
github.com/go-co-op/gocron/v2 v2.2.9/go.mod h1:mZx3gMSlFnb97k3hRqX3+GdlG3+DUwTh6B8fnsTScXg=
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw= github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw=
github.com/go-faster/errors v0.6.1 h1:nNIPOBkprlKzkThvS/0YaX8Zs9KewLCOSFQS5BU06FI= github.com/go-faster/errors v0.6.1 h1:nNIPOBkprlKzkThvS/0YaX8Zs9KewLCOSFQS5BU06FI=
@ -158,8 +158,6 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E= github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E=
github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
@ -178,6 +176,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
@ -205,8 +204,6 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 h1:mchzmB1XO2pMaKFRqk/+MV3mgGG96aqaPXaMifQU47w=
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 h1:+iq7lrkxmFNBM7xx+Rae2W6uyPfhPeDWD+n+JgppptE= golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 h1:+iq7lrkxmFNBM7xx+Rae2W6uyPfhPeDWD+n+JgppptE=
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/exp v0.0.0-20231219180239-dc181d75b848/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
@ -233,6 +230,7 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View file

@ -67,7 +67,7 @@ func flatHeader(header http.Header) map[string]string {
m := make(map[string]string, len(header)) m := make(map[string]string, len(header))
for k := range header { for k := range header {
m[k] = strings.Join(header[k], "; ") m[k] = strings.Join(header[k], ", ")
} }
return m return m
} }