prepare more reddit api
This commit is contained in:
parent
8ec1175fe4
commit
63f17437b7
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/robfig/cron/v3"
|
||||
"github.com/teivah/broadcast"
|
||||
"github.com/tigorlazuardi/redmage/api/bmessage"
|
||||
"github.com/tigorlazuardi/redmage/config"
|
||||
"github.com/tigorlazuardi/redmage/db/queries"
|
||||
"github.com/tigorlazuardi/redmage/pkg/errs"
|
||||
|
@ -20,7 +21,7 @@ type API struct {
|
|||
scheduler *cron.Cron
|
||||
scheduleMap map[cron.EntryID]queries.Subreddit
|
||||
|
||||
downloadBroadcast *broadcast.Relay[DownloadStatusMessage]
|
||||
downloadBroadcast *broadcast.Relay[bmessage.DownloadStatusMessage]
|
||||
|
||||
config *config.Config
|
||||
}
|
||||
|
@ -31,7 +32,7 @@ func New(q *queries.Queries, db *sql.DB, cfg *config.Config) *API {
|
|||
db: db,
|
||||
scheduler: cron.New(),
|
||||
scheduleMap: make(map[cron.EntryID]queries.Subreddit, 8),
|
||||
downloadBroadcast: broadcast.NewRelay[DownloadStatusMessage](),
|
||||
downloadBroadcast: broadcast.NewRelay[bmessage.DownloadStatusMessage](),
|
||||
config: cfg,
|
||||
}
|
||||
}
|
||||
|
|
24
api/bmessage/bmessage.go
Normal file
24
api/bmessage/bmessage.go
Normal 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
|
||||
}
|
|
@ -11,6 +11,6 @@ type DownloadSubredditPostsParams struct {
|
|||
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
|
||||
}
|
||||
|
|
27
api/reddit/download_images.go
Normal file
27
api/reddit/download_images.go
Normal 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
|
||||
}
|
|
@ -1 +1,39 @@
|
|||
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
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/tigorlazuardi/redmage/pkg/errs"
|
||||
)
|
||||
|
@ -34,7 +35,7 @@ type GetPostsParam struct {
|
|||
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)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, http.NoBody)
|
||||
if err != nil {
|
||||
|
@ -51,7 +52,7 @@ func (reddit *Reddit) GetPosts(ctx context.Context, params GetPostsParam) (posts
|
|||
body, _ := io.ReadAll(res.Body)
|
||||
return posts, errs.Fail("reddit: unexpected status code when executing GetPosts",
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
package reddit
|
||||
|
||||
type Post struct {
|
||||
type Listing struct {
|
||||
Kind string `json:"kind"`
|
||||
Data Data `json:"data"`
|
||||
}
|
||||
|
||||
func (l *Listing) GetPosts() []Post {
|
||||
return l.Data.Children
|
||||
}
|
||||
|
||||
type (
|
||||
MediaEmbed struct{}
|
||||
SecureMediaEmbed struct{}
|
||||
|
@ -65,7 +69,7 @@ type AuthorFlairRichtext struct {
|
|||
E string `json:"e"`
|
||||
T string `json:"t"`
|
||||
}
|
||||
type ChildrenData struct {
|
||||
type PostData struct {
|
||||
ApprovedAtUtc any `json:"approved_at_utc"`
|
||||
Subreddit string `json:"subreddit"`
|
||||
Selftext string `json:"selftext"`
|
||||
|
@ -176,16 +180,44 @@ type ChildrenData struct {
|
|||
NumCrossposts int `json:"num_crossposts"`
|
||||
Media any `json:"media"`
|
||||
IsVideo bool `json:"is_video"`
|
||||
PostHint string `json:"post_hint"`
|
||||
Preview Preview `json:"preview"`
|
||||
}
|
||||
type Children struct {
|
||||
Kind string `json:"kind"`
|
||||
Data ChildrenData `json:"data,omitempty"`
|
||||
|
||||
type Post struct {
|
||||
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 {
|
||||
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"`
|
||||
After string `json:"after"`
|
||||
Dist int `json:"dist"`
|
||||
Modhash string `json:"modhash"`
|
||||
GeoFilter any `json:"geo_filter"`
|
||||
Children []Post `json:"children"`
|
||||
Before any `json:"before"`
|
||||
}
|
||||
|
|
|
@ -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"`
|
||||
}
|
|
@ -7,6 +7,7 @@ CREATE TABLE images(
|
|||
title VARCHAR(255) NOT NULL,
|
||||
post_id VARCHAR(50) NOT NULL,
|
||||
post_url VARCHAR(255) NOT NULL,
|
||||
post_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
poster VARCHAR(50) NOT NULL,
|
||||
poster_url VARCHAR(255) NOT NULL,
|
||||
image_relative_path VARCHAR(255) NOT NULL,
|
||||
|
|
7
go.mod
7
go.mod
|
@ -5,6 +5,7 @@ go 1.22.1
|
|||
require (
|
||||
github.com/a-h/templ v0.2.648
|
||||
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/go-chi/chi/v5 v5.0.12
|
||||
github.com/joho/godotenv v1.5.1
|
||||
|
@ -20,25 +21,23 @@ require (
|
|||
github.com/mattn/go-isatty v0.0.20
|
||||
github.com/mattn/go-sqlite3 v1.14.6
|
||||
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/spf13/cobra v1.8.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/teivah/broadcast v0.1.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.7.0 // 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/jonboulle/clockwork v0.4.0 // indirect
|
||||
github.com/knadh/koanf/maps v0.1.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/mfridman/interpolate v0.0.2 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // 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/teivah/broadcast v0.1.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 // indirect
|
||||
golang.org/x/sync v0.6.0 // indirect
|
||||
|
|
10
go.sum
10
go.sum
|
@ -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/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
|
||||
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/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
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/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-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/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw=
|
||||
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/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.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/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
||||
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.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
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=
|
||||
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/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/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
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 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/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/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -67,7 +67,7 @@ func flatHeader(header http.Header) map[string]string {
|
|||
m := make(map[string]string, len(header))
|
||||
|
||||
for k := range header {
|
||||
m[k] = strings.Join(header[k], "; ")
|
||||
m[k] = strings.Join(header[k], ", ")
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue