103 lines
2.1 KiB
Go
103 lines
2.1 KiB
Go
package hnblogs
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"math/rand"
|
|
"net/http"
|
|
"sync"
|
|
)
|
|
|
|
const BlogsURL = "https://raw.githubusercontent.com/surprisetalk/blogs.hn/main/blogs.json"
|
|
|
|
// Blog represents a single blog entry.
|
|
type Blog struct {
|
|
URL string `json:"url"`
|
|
Title string `json:"title"`
|
|
About string `json:"about"`
|
|
Now string `json:"now"`
|
|
Feed string `json:"feed"`
|
|
Desc string `json:"desc"`
|
|
}
|
|
|
|
var (
|
|
blogs []Blog
|
|
fetchError error
|
|
once sync.Once
|
|
)
|
|
|
|
// FetchBlogs fetches the list of blogs and memoizes it in RAM.
|
|
func FetchBlogs() ([]Blog, error) {
|
|
once.Do(func() {
|
|
resp, err := http.Get(BlogsURL)
|
|
if err != nil {
|
|
fetchError = fmt.Errorf("failed to fetch blogs: %v", err)
|
|
return
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
fetchError = fmt.Errorf("failed to fetch blogs: status code %d", resp.StatusCode)
|
|
return
|
|
}
|
|
|
|
var fetchedBlogs []Blog
|
|
if err := json.NewDecoder(resp.Body).Decode(&fetchedBlogs); err != nil {
|
|
fetchError = fmt.Errorf("failed to decode blogs JSON: %v", err)
|
|
return
|
|
}
|
|
|
|
blogs = fetchedBlogs
|
|
})
|
|
|
|
return blogs, fetchError
|
|
}
|
|
|
|
// GetBlogs returns the memoized list of blogs.
|
|
func GetBlogs() ([]Blog, error) {
|
|
return FetchBlogs()
|
|
}
|
|
|
|
// RandomBlog returns a random blog from the list of blogs.
|
|
func RandomBlog() (Blog, error) {
|
|
blogs, err := GetBlogs()
|
|
if err != nil {
|
|
return Blog{}, err
|
|
}
|
|
|
|
return blogs[rand.Intn(len(blogs))], nil
|
|
}
|
|
|
|
// RandomBlogs returns n random blogs from the list of blogs.
|
|
func RandomBlogs(n int) ([]Blog, error) {
|
|
blogs, err := GetBlogs()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if n <= 0 || n > len(blogs) {
|
|
return nil, fmt.Errorf("invalid number of blogs requested")
|
|
}
|
|
|
|
selected := make([]Blog, n)
|
|
for i := range selected {
|
|
selected[i] = blogs[rand.Intn(len(blogs))]
|
|
}
|
|
|
|
return selected, nil
|
|
}
|
|
|
|
// NthBlog returns the nth blog from the list of blogs.
|
|
func NthBlog(n int) (Blog, error) {
|
|
blogs, err := GetBlogs()
|
|
if err != nil {
|
|
return Blog{}, err
|
|
}
|
|
|
|
if n < 0 || n >= len(blogs) {
|
|
return Blog{}, fmt.Errorf("index out of range")
|
|
}
|
|
|
|
return blogs[n], nil
|
|
}
|