Compare commits

...

2 Commits

Author SHA1 Message Date
6677bd95ab Use errors in protocol
- Rewrite all api's and clients to use the new calls which allows errors
in the responses
2018-07-07 16:40:04 +02:00
bf645f33ef Move microsub to pkg/microsub 2018-07-07 16:03:49 +02:00
10 changed files with 316 additions and 153 deletions

View File

@ -7,9 +7,9 @@ import (
"net/url"
"os"
"github.com/pstuifzand/ekster/microsub"
"github.com/pstuifzand/ekster/pkg/client"
"github.com/pstuifzand/ekster/pkg/indieauth"
"github.com/pstuifzand/ekster/pkg/microsub"
)
func init() {
@ -173,7 +173,11 @@ Commands:
}
if len(commands) == 1 && commands[0] == "channels" {
channels := sub.ChannelsGetList()
channels, err := sub.ChannelsGetList()
if err != nil {
log.Fatalf("An error occurred: %s\n", err)
}
for _, ch := range channels {
fmt.Printf("%-20s %s\n", ch.UID, ch.Name)
}
@ -181,7 +185,10 @@ Commands:
if len(commands) == 2 && commands[0] == "channels" {
name := commands[1]
channel := sub.ChannelsCreate(name)
channel, err := sub.ChannelsCreate(name)
if err != nil {
log.Fatalf("An error occurred: %s\n", err)
}
fmt.Printf("%s\n", channel.UID)
}
@ -189,11 +196,17 @@ Commands:
uid := commands[1]
if uid == "-delete" {
uid = commands[2]
sub.ChannelsDelete(uid)
err := sub.ChannelsDelete(uid)
if err != nil {
log.Fatalf("An error occurred: %s\n", err)
}
fmt.Printf("Channel %s deleted\n", uid)
} else {
name := commands[2]
channel := sub.ChannelsUpdate(uid, name)
channel, err := sub.ChannelsUpdate(uid, name)
if err != nil {
log.Fatalf("An error occurred: %s\n", err)
}
fmt.Printf("Channel updated %s %s\n", channel.Name, channel.UID)
}
}
@ -202,13 +215,18 @@ Commands:
channel := commands[1]
var timeline microsub.Timeline
var err error
if len(commands) == 4 && commands[2] == "-after" {
timeline = sub.TimelineGet("", commands[3], channel)
timeline, err = sub.TimelineGet("", commands[3], channel)
} else if len(commands) == 4 && commands[2] == "-before" {
timeline = sub.TimelineGet(commands[3], "", channel)
timeline, err = sub.TimelineGet(commands[3], "", channel)
} else {
timeline = sub.TimelineGet("", "", channel)
timeline, err = sub.TimelineGet("", "", channel)
}
if err != nil {
log.Fatalf("An error occurred: %s\n", err)
}
for _, item := range timeline.Items {
@ -220,7 +238,10 @@ Commands:
if len(commands) == 2 && commands[0] == "search" {
query := commands[1]
feeds := sub.Search(query)
feeds, err := sub.Search(query)
if err != nil {
log.Fatalf("An error occurred: %s\n", err)
}
for _, feed := range feeds {
fmt.Println(feed.Name, " ", feed.URL)
@ -229,8 +250,11 @@ Commands:
if len(commands) == 2 && commands[0] == "preview" {
url := commands[1]
timeline := sub.PreviewURL(url)
timeline, err := sub.PreviewURL(url)
if err != nil {
log.Fatalf("An error occurred: %s\n", err)
}
for _, item := range timeline.Items {
showItem(&item)
}
@ -238,7 +262,10 @@ Commands:
if len(commands) == 2 && commands[0] == "follow" {
uid := commands[1]
feeds := sub.FollowGetList(uid)
feeds, err := sub.FollowGetList(uid)
if err != nil {
log.Fatalf("An error occurred: %s\n", err)
}
for _, feed := range feeds {
fmt.Println(feed.Name, " ", feed.URL)
}
@ -247,13 +274,20 @@ Commands:
if len(commands) == 3 && commands[0] == "follow" {
uid := commands[1]
url := commands[2]
sub.FollowURL(uid, url)
_, err := sub.FollowURL(uid, url)
if err != nil {
log.Fatalf("An error occurred: %s\n", err)
}
// NOTE(peter): should we show the returned feed here?
}
if len(commands) == 3 && commands[0] == "unfollow" {
uid := commands[1]
url := commands[2]
sub.UnfollowURL(uid, url)
err := sub.UnfollowURL(uid, url)
if err != nil {
log.Fatalf("An error occurred: %s\n", err)
}
}
}

View File

@ -34,7 +34,7 @@ import (
"time"
"github.com/garyburd/redigo/redis"
"github.com/pstuifzand/ekster/microsub"
"github.com/pstuifzand/ekster/pkg/microsub"
"willnorris.com/go/microformats"
)

View File

@ -28,7 +28,7 @@ import (
"time"
"github.com/garyburd/redigo/redis"
"github.com/pstuifzand/ekster/microsub"
"github.com/pstuifzand/ekster/pkg/microsub"
"github.com/pstuifzand/ekster/pkg/util"
"github.com/pstuifzand/ekster/pkg/websub"
)

View File

@ -29,8 +29,8 @@ import (
"time"
"github.com/garyburd/redigo/redis"
"github.com/pstuifzand/ekster/microsub"
"github.com/pstuifzand/ekster/pkg/feedbin"
"github.com/pstuifzand/ekster/pkg/microsub"
"willnorris.com/go/microformats"
)
@ -138,7 +138,7 @@ func createMemoryBackend() microsub.Microsub {
}
// ChannelsGetList gets channels
func (b *memoryBackend) ChannelsGetList() []microsub.Channel {
func (b *memoryBackend) ChannelsGetList() ([]microsub.Channel, error) {
conn := pool.Get()
defer conn.Close()
@ -156,11 +156,11 @@ func (b *memoryBackend) ChannelsGetList() []microsub.Channel {
}
}
}
return channels
return channels, nil
}
// ChannelsCreate creates a channels
func (b *memoryBackend) ChannelsCreate(name string) microsub.Channel {
func (b *memoryBackend) ChannelsCreate(name string) (microsub.Channel, error) {
defer b.save()
conn := pool.Get()
@ -178,22 +178,23 @@ func (b *memoryBackend) ChannelsCreate(name string) microsub.Channel {
conn.Do("SADD", "channels", uid)
conn.Do("SETNX", "channel_sortorder_"+uid, 99999)
return channel
return channel, nil
}
// ChannelsUpdate updates a channels
func (b *memoryBackend) ChannelsUpdate(uid, name string) microsub.Channel {
func (b *memoryBackend) ChannelsUpdate(uid, name string) (microsub.Channel, error) {
defer b.save()
if c, e := b.Channels[uid]; e {
c.Name = name
b.Channels[uid] = c
return c
return c, nil
}
return microsub.Channel{}
return microsub.Channel{}, fmt.Errorf("Channel %s does not exist", uid)
}
// ChannelsDelete deletes a channel
func (b *memoryBackend) ChannelsDelete(uid string) {
func (b *memoryBackend) ChannelsDelete(uid string) error {
defer b.save()
conn := pool.Get()
@ -204,6 +205,8 @@ func (b *memoryBackend) ChannelsDelete(uid string) {
delete(b.Channels, uid)
delete(b.Feeds, uid)
return nil
}
func mapToAuthor(result map[string]string) *microsub.Card {
@ -391,7 +394,7 @@ func (b *memoryBackend) run() {
}()
}
func (b *memoryBackend) TimelineGet(before, after, channel string) microsub.Timeline {
func (b *memoryBackend) TimelineGet(before, after, channel string) (microsub.Timeline, error) {
conn := pool.Get()
defer conn.Close()
@ -430,11 +433,14 @@ func (b *memoryBackend) TimelineGet(before, after, channel string) microsub.Time
return microsub.Timeline{
Paging: microsub.Pagination{},
Items: items,
}
}, nil
}
log.Printf("TimelineGet %s\n", channel)
feeds := b.FollowGetList(channel)
feeds, err := b.FollowGetList(channel)
if err != nil {
return microsub.Timeline{}, err
}
log.Println(feeds)
items := []microsub.Item{}
@ -476,11 +482,10 @@ func (b *memoryBackend) TimelineGet(before, after, channel string) microsub.Time
)
if err != nil {
log.Println(err)
return microsub.Timeline{
Paging: microsub.Pagination{},
Items: items,
}
}, err
}
if len(itemScores) >= 2 {
@ -502,6 +507,7 @@ func (b *memoryBackend) TimelineGet(before, after, channel string) microsub.Time
item := microsub.Item{}
err := json.Unmarshal(obj, &item)
if err != nil {
// FIXME: what should we do if one of the items doen't unmarshal?
log.Println(err)
continue
}
@ -516,7 +522,7 @@ func (b *memoryBackend) TimelineGet(before, after, channel string) microsub.Time
return microsub.Timeline{
Paging: paging,
Items: items,
}
}, nil
}
//panic if s is not a slice
@ -553,17 +559,17 @@ func reverseSlice(s interface{}) {
// return false
// }
func (b *memoryBackend) FollowGetList(uid string) []microsub.Feed {
return b.Feeds[uid]
func (b *memoryBackend) FollowGetList(uid string) ([]microsub.Feed, error) {
return b.Feeds[uid], nil
}
func (b *memoryBackend) FollowURL(uid string, url string) microsub.Feed {
func (b *memoryBackend) FollowURL(uid string, url string) (microsub.Feed, error) {
defer b.save()
feed := microsub.Feed{Type: "feed", URL: url}
resp, err := b.Fetch3(uid, feed.URL)
if err != nil {
return feed
return feed, err
}
defer resp.Body.Close()
@ -571,10 +577,10 @@ func (b *memoryBackend) FollowURL(uid string, url string) microsub.Feed {
b.ProcessContent(uid, feed.URL, resp.Header.Get("Content-Type"), resp.Body)
return feed
return feed, nil
}
func (b *memoryBackend) UnfollowURL(uid string, url string) {
func (b *memoryBackend) UnfollowURL(uid string, url string) error {
defer b.save()
index := -1
for i, f := range b.Feeds[uid] {
@ -587,6 +593,8 @@ func (b *memoryBackend) UnfollowURL(uid string, url string) {
feeds := b.Feeds[uid]
b.Feeds[uid] = append(feeds[:index], feeds[index+1:]...)
}
return nil
}
func checkURL(u string) bool {
@ -625,7 +633,7 @@ func getPossibleURLs(query string) []string {
return urls
}
func (b *memoryBackend) Search(query string) []microsub.Feed {
func (b *memoryBackend) Search(query string) ([]microsub.Feed, error) {
urls := getPossibleURLs(query)
feeds := []microsub.Feed{}
@ -684,27 +692,25 @@ func (b *memoryBackend) Search(query string) []microsub.Feed {
}
}
return feeds
return feeds, nil
}
func (b *memoryBackend) PreviewURL(previewURL string) microsub.Timeline {
func (b *memoryBackend) PreviewURL(previewURL string) (microsub.Timeline, error) {
resp, err := Fetch2(previewURL)
if err != nil {
log.Printf("Error while fetching %s: %v\n", previewURL, err)
return microsub.Timeline{}
return microsub.Timeline{}, fmt.Errorf("error while fetching %s: %v", previewURL, err)
}
items, err := b.feedItems(previewURL, resp.Header.Get("content-type"), resp.Body)
if err != nil {
log.Printf("Error while fetching %s: %v\n", previewURL, err)
return microsub.Timeline{}
return microsub.Timeline{}, fmt.Errorf("error while fetching %s: %v", previewURL, err)
}
return microsub.Timeline{
Items: items,
}
}, nil
}
func (b *memoryBackend) MarkRead(channel string, uids []string) {
func (b *memoryBackend) MarkRead(channel string, uids []string) error {
conn := pool.Get()
defer conn.Close()
@ -720,6 +726,7 @@ func (b *memoryBackend) MarkRead(channel string, uids []string) {
if _, err := conn.Do("SADD", args...); err != nil {
log.Printf("Marking read for channel %s has failed\n", channel)
return err
}
zchannelKey := fmt.Sprintf("zchannel:%s:posts", channel)
@ -727,6 +734,7 @@ func (b *memoryBackend) MarkRead(channel string, uids []string) {
if _, err := conn.Do("ZREM", args...); err != nil {
log.Printf("Marking read for channel %s has failed\n", channel)
return err
}
unread, _ := redis.Int(conn.Do("ZCARD", zchannelKey))
@ -741,4 +749,6 @@ func (b *memoryBackend) MarkRead(channel string, uids []string) {
}
log.Printf("Marking read success for %s %v\n", channel, itemUIDs)
return nil
}

View File

@ -9,7 +9,7 @@ import (
"strings"
"github.com/garyburd/redigo/redis"
"github.com/pstuifzand/ekster/microsub"
"github.com/pstuifzand/ekster/pkg/microsub"
"willnorris.com/go/microformats"
)

View File

@ -8,7 +8,7 @@ import (
"os"
"github.com/garyburd/redigo/redis"
"github.com/pstuifzand/ekster/microsub"
"github.com/pstuifzand/ekster/pkg/microsub"
)
type microsubHandler struct {
@ -49,34 +49,67 @@ func (h *microsubHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
values := r.URL.Query()
action := values.Get("action")
if action == "channels" {
channels := h.Backend.ChannelsGetList()
channels, err := h.Backend.ChannelsGetList()
if err != nil {
http.Error(w, err.Error(), 500)
return
}
jw := json.NewEncoder(w)
w.Header().Add("Content-Type", "application/json")
jw.Encode(map[string][]microsub.Channel{
err = jw.Encode(map[string][]microsub.Channel{
"channels": channels,
})
if err != nil {
http.Error(w, err.Error(), 500)
return
}
} else if action == "timeline" {
timeline := h.Backend.TimelineGet(values.Get("before"), values.Get("after"), values.Get("channel"))
timeline, err := h.Backend.TimelineGet(values.Get("before"), values.Get("after"), values.Get("channel"))
if err != nil {
http.Error(w, err.Error(), 500)
return
}
jw := json.NewEncoder(w)
w.Header().Add("Content-Type", "application/json")
jw.SetIndent("", " ")
jw.Encode(timeline)
err = jw.Encode(timeline)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
} else if action == "preview" {
timeline := h.Backend.PreviewURL(values.Get("url"))
timeline, err := h.Backend.PreviewURL(values.Get("url"))
if err != nil {
http.Error(w, err.Error(), 500)
return
}
jw := json.NewEncoder(w)
jw.SetIndent("", " ")
w.Header().Add("Content-Type", "application/json")
jw.Encode(timeline)
err = jw.Encode(timeline)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
} else if action == "follow" {
channel := values.Get("channel")
following := h.Backend.FollowGetList(channel)
following, err := h.Backend.FollowGetList(channel)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
jw := json.NewEncoder(w)
w.Header().Add("Content-Type", "application/json")
jw.Encode(map[string][]microsub.Feed{
err = jw.Encode(map[string][]microsub.Feed{
"items": following,
})
if err != nil {
http.Error(w, err.Error(), 500)
return
}
} else {
log.Printf("unknown action %s\n", action)
http.Error(w, fmt.Sprintf("unknown action %s\n", action), 500)
return
}
return
} else if r.Method == http.MethodPost {
@ -87,7 +120,11 @@ func (h *microsubHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
method := values.Get("method")
uid := values.Get("channel")
if method == "delete" {
h.Backend.ChannelsDelete(uid)
err := h.Backend.ChannelsDelete(uid)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
w.Header().Add("Content-Type", "application/json")
fmt.Fprintln(w, "[]")
h.Backend.(Debug).Debug()
@ -96,37 +133,73 @@ func (h *microsubHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
jw := json.NewEncoder(w)
if uid == "" {
channel := h.Backend.ChannelsCreate(name)
channel, err := h.Backend.ChannelsCreate(name)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
w.Header().Add("Content-Type", "application/json")
jw.Encode(channel)
err = jw.Encode(channel)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
} else {
channel := h.Backend.ChannelsUpdate(uid, name)
channel, err := h.Backend.ChannelsUpdate(uid, name)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
w.Header().Add("Content-Type", "application/json")
jw.Encode(channel)
err = jw.Encode(channel)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
}
h.Backend.(Debug).Debug()
} else if action == "follow" {
uid := values.Get("channel")
url := values.Get("url")
h.HubIncomingBackend.CreateFeed(url, uid)
feed := h.Backend.FollowURL(uid, url)
feed, err := h.Backend.FollowURL(uid, url)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
w.Header().Add("Content-Type", "application/json")
jw := json.NewEncoder(w)
jw.Encode(feed)
err = jw.Encode(feed)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
} else if action == "unfollow" {
uid := values.Get("channel")
url := values.Get("url")
h.Backend.UnfollowURL(uid, url)
err := h.Backend.UnfollowURL(uid, url)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
w.Header().Add("Content-Type", "application/json")
fmt.Fprintln(w, "[]")
} else if action == "search" {
query := values.Get("query")
feeds := h.Backend.Search(query)
feeds, err := h.Backend.Search(query)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
jw := json.NewEncoder(w)
w.Header().Add("Content-Type", "application/json")
jw.Encode(map[string][]microsub.Feed{
err = jw.Encode(map[string][]microsub.Feed{
"results": feeds,
})
if err != nil {
http.Error(w, err.Error(), 500)
return
}
} else if action == "timeline" || r.PostForm.Get("action") == "timeline" {
method := values.Get("method")
@ -134,9 +207,17 @@ func (h *microsubHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
values = r.Form
channel := values.Get("channel")
if uids, e := values["entry"]; e {
h.Backend.MarkRead(channel, uids)
err := h.Backend.MarkRead(channel, uids)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
} else if uids, e := values["entry[]"]; e {
h.Backend.MarkRead(channel, uids)
err := h.Backend.MarkRead(channel, uids)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
} else {
uids := []string{}
for k, v := range values {
@ -144,15 +225,20 @@ func (h *microsubHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
uids = append(uids, v...)
}
}
h.Backend.MarkRead(channel, uids)
err := h.Backend.MarkRead(channel, uids)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
}
} else {
log.Printf("unknown method in timeline %s\n", method)
http.Error(w, fmt.Sprintf("unknown method in timeline %s\n", method), 500)
return
}
w.Header().Add("Content-Type", "application/json")
fmt.Fprintln(w, "[]")
} else {
log.Printf("unknown action %s\n", action)
http.Error(w, fmt.Sprintf("unknown action %s\n", action), 500)
}
return

View File

@ -18,7 +18,7 @@
package main
import (
"github.com/pstuifzand/ekster/microsub"
"github.com/pstuifzand/ekster/pkg/microsub"
)
// NullBackend is the simplest possible backend
@ -26,64 +26,67 @@ type NullBackend struct {
}
// ChannelsGetList gets no channels
func (b *NullBackend) ChannelsGetList() []microsub.Channel {
func (b *NullBackend) ChannelsGetList() ([]microsub.Channel, error) {
return []microsub.Channel{
microsub.Channel{UID: "0000", Name: "default", Unread: 0},
microsub.Channel{UID: "0001", Name: "notifications", Unread: 0},
microsub.Channel{UID: "1000", Name: "Friends", Unread: 0},
microsub.Channel{UID: "1001", Name: "Family", Unread: 0},
}
}, nil
}
// ChannelsCreate creates no channels
func (b *NullBackend) ChannelsCreate(name string) microsub.Channel {
func (b *NullBackend) ChannelsCreate(name string) (microsub.Channel, error) {
return microsub.Channel{
UID: "1234",
Name: name,
}
}, nil
}
// ChannelsUpdate updates no channels
func (b *NullBackend) ChannelsUpdate(uid, name string) microsub.Channel {
func (b *NullBackend) ChannelsUpdate(uid, name string) (microsub.Channel, error) {
return microsub.Channel{
UID: uid,
Name: name,
}
}, nil
}
// ChannelsDelete delets no channels
func (b *NullBackend) ChannelsDelete(uid string) {
func (b *NullBackend) ChannelsDelete(uid string) error {
return nil
}
// TimelineGet gets no timeline
func (b *NullBackend) TimelineGet(before, after, channel string) microsub.Timeline {
func (b *NullBackend) TimelineGet(before, after, channel string) (microsub.Timeline, error) {
return microsub.Timeline{
Paging: microsub.Pagination{},
Items: []microsub.Item{},
}
}, nil
}
func (b *NullBackend) FollowGetList(uid string) []microsub.Feed {
return []microsub.Feed{}
func (b *NullBackend) FollowGetList(uid string) ([]microsub.Feed, error) {
return []microsub.Feed{}, nil
}
func (b *NullBackend) FollowURL(uid string, url string) microsub.Feed {
return microsub.Feed{Type: "feed", URL: url}
func (b *NullBackend) FollowURL(uid string, url string) (microsub.Feed, error) {
return microsub.Feed{Type: "feed", URL: url}, nil
}
func (b *NullBackend) UnfollowURL(uid string, url string) {
func (b *NullBackend) UnfollowURL(uid string, url string) error {
return nil
}
func (b *NullBackend) Search(query string) []microsub.Feed {
return []microsub.Feed{}
func (b *NullBackend) Search(query string) ([]microsub.Feed, error) {
return []microsub.Feed{}, nil
}
func (b *NullBackend) PreviewURL(url string) microsub.Timeline {
func (b *NullBackend) PreviewURL(url string) (microsub.Timeline, error) {
return microsub.Timeline{
Paging: microsub.Pagination{},
Items: []microsub.Item{},
}
}, nil
}
func (b *NullBackend) MarkRead(channel string, uids []string) {
func (b *NullBackend) MarkRead(channel string, uids []string) error {
return nil
}

View File

@ -3,12 +3,11 @@ package client
import (
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"strings"
"github.com/pstuifzand/ekster/microsub"
"github.com/pstuifzand/ekster/pkg/microsub"
)
type Client struct {
@ -80,12 +79,11 @@ func (c *Client) microsubPostFormRequest(action string, args map[string]string,
return client.Do(req)
}
func (c *Client) ChannelsGetList() []microsub.Channel {
func (c *Client) ChannelsGetList() ([]microsub.Channel, error) {
args := make(map[string]string)
res, err := c.microsubGetRequest("channels", args)
if err != nil {
log.Println(err)
return []microsub.Channel{}
return []microsub.Channel{}, err
}
defer res.Body.Close()
@ -95,52 +93,56 @@ func (c *Client) ChannelsGetList() []microsub.Channel {
dec := json.NewDecoder(res.Body)
var channels channelsResponse
dec.Decode(&channels)
return channels.Channels
err = dec.Decode(&channels)
if err != nil {
return channels.Channels, err
}
return channels.Channels, nil
}
func (c *Client) TimelineGet(before, after, channel string) microsub.Timeline {
func (c *Client) TimelineGet(before, after, channel string) (microsub.Timeline, error) {
args := make(map[string]string)
args["after"] = after
args["before"] = before
args["channel"] = channel
res, err := c.microsubGetRequest("timeline", args)
if err != nil {
log.Println(err)
return microsub.Timeline{}
return microsub.Timeline{}, err
}
defer res.Body.Close()
dec := json.NewDecoder(res.Body)
var timeline microsub.Timeline
err = dec.Decode(&timeline)
if err != nil {
log.Fatal(err)
return microsub.Timeline{}, err
}
return timeline
return timeline, nil
}
func (c *Client) PreviewURL(url string) microsub.Timeline {
func (c *Client) PreviewURL(url string) (microsub.Timeline, error) {
args := make(map[string]string)
args["url"] = url
res, err := c.microsubGetRequest("preview", args)
if err != nil {
log.Println(err)
return microsub.Timeline{}
return microsub.Timeline{}, err
}
defer res.Body.Close()
dec := json.NewDecoder(res.Body)
var timeline microsub.Timeline
dec.Decode(&timeline)
return timeline
err = dec.Decode(&timeline)
if err != nil {
return microsub.Timeline{}, err
}
return timeline, nil
}
func (c *Client) FollowGetList(channel string) []microsub.Feed {
func (c *Client) FollowGetList(channel string) ([]microsub.Feed, error) {
args := make(map[string]string)
args["channel"] = channel
res, err := c.microsubGetRequest("follow", args)
if err != nil {
log.Println(err)
return []microsub.Feed{}
return []microsub.Feed{}, nil
}
defer res.Body.Close()
dec := json.NewDecoder(res.Body)
@ -148,88 +150,96 @@ func (c *Client) FollowGetList(channel string) []microsub.Feed {
Items []microsub.Feed `json:"items"`
}
var response followResponse
dec.Decode(&response)
return response.Items
err = dec.Decode(&response)
if err != nil {
return []microsub.Feed{}, nil
}
return response.Items, nil
}
func (c *Client) ChannelsCreate(name string) microsub.Channel {
func (c *Client) ChannelsCreate(name string) (microsub.Channel, error) {
args := make(map[string]string)
args["name"] = name
res, err := c.microsubPostRequest("channels", args)
if err != nil {
log.Println(err)
return microsub.Channel{}
return microsub.Channel{}, nil
}
defer res.Body.Close()
var channel microsub.Channel
dec := json.NewDecoder(res.Body)
dec.Decode(&channel)
return channel
err = dec.Decode(&channel)
if err != nil {
return microsub.Channel{}, nil
}
return channel, nil
}
func (c *Client) ChannelsUpdate(uid, name string) microsub.Channel {
func (c *Client) ChannelsUpdate(uid, name string) (microsub.Channel, error) {
args := make(map[string]string)
args["name"] = name
args["uid"] = uid
res, err := c.microsubPostRequest("channels", args)
if err != nil {
log.Println(err)
return microsub.Channel{}
return microsub.Channel{}, err
}
defer res.Body.Close()
var channel microsub.Channel
dec := json.NewDecoder(res.Body)
dec.Decode(&channel)
return channel
err = dec.Decode(&channel)
if err != nil {
return microsub.Channel{}, err
}
return channel, nil
}
func (c *Client) ChannelsDelete(uid string) {
func (c *Client) ChannelsDelete(uid string) error {
args := make(map[string]string)
args["channel"] = uid
args["method"] = "delete"
res, err := c.microsubPostRequest("channels", args)
if err != nil {
log.Println(err)
return
return err
}
res.Body.Close()
return nil
}
func (c *Client) FollowURL(channel, url string) microsub.Feed {
func (c *Client) FollowURL(channel, url string) (microsub.Feed, error) {
args := make(map[string]string)
args["channel"] = channel
args["url"] = url
res, err := c.microsubPostRequest("follow", args)
if err != nil {
log.Println(err)
return microsub.Feed{}
return microsub.Feed{}, err
}
defer res.Body.Close()
var feed microsub.Feed
dec := json.NewDecoder(res.Body)
dec.Decode(&feed)
return feed
err = dec.Decode(&feed)
if err != nil {
return microsub.Feed{}, err
}
return feed, nil
}
func (c *Client) UnfollowURL(channel, url string) {
func (c *Client) UnfollowURL(channel, url string) error {
args := make(map[string]string)
args["channel"] = channel
args["url"] = url
res, err := c.microsubPostRequest("unfollow", args)
if err != nil {
log.Println(err)
return
return err
}
res.Body.Close()
return nil
}
func (c *Client) Search(query string) []microsub.Feed {
func (c *Client) Search(query string) ([]microsub.Feed, error) {
args := make(map[string]string)
args["query"] = query
res, err := c.microsubPostRequest("search", args)
if err != nil {
log.Println(err)
return []microsub.Feed{}
return []microsub.Feed{}, err
}
type searchResponse struct {
Results []microsub.Feed `json:"results"`
@ -237,11 +247,14 @@ func (c *Client) Search(query string) []microsub.Feed {
defer res.Body.Close()
var response searchResponse
dec := json.NewDecoder(res.Body)
dec.Decode(&response)
return response.Results
err = dec.Decode(&response)
if err != nil {
return []microsub.Feed{}, err
}
return response.Results, nil
}
func (c *Client) MarkRead(channel string, uids []string) {
func (c *Client) MarkRead(channel string, uids []string) error {
args := make(map[string]string)
args["channel"] = channel
@ -251,7 +264,9 @@ func (c *Client) MarkRead(channel string, uids []string) {
}
res, err := c.microsubPostFormRequest("mark_read", args, data)
if err == nil {
defer res.Body.Close()
if err != nil {
return err
}
res.Body.Close()
return nil
}

View File

@ -102,20 +102,20 @@ type Feed struct {
// Microsub is the main protocol that should be implemented by a backend
type Microsub interface {
ChannelsGetList() []Channel
ChannelsCreate(name string) Channel
ChannelsUpdate(uid, name string) Channel
ChannelsDelete(uid string)
ChannelsGetList() ([]Channel, error)
ChannelsCreate(name string) (Channel, error)
ChannelsUpdate(uid, name string) (Channel, error)
ChannelsDelete(uid string) error
TimelineGet(before, after, channel string) Timeline
TimelineGet(before, after, channel string) (Timeline, error)
MarkRead(channel string, entry []string)
MarkRead(channel string, entry []string) error
FollowGetList(uid string) []Feed
FollowURL(uid string, url string) Feed
FollowGetList(uid string) ([]Feed, error)
FollowURL(uid string, url string) (Feed, error)
UnfollowURL(uid string, url string)
UnfollowURL(uid string, url string) error
Search(query string) []Feed
PreviewURL(url string) Timeline
Search(query string) ([]Feed, error)
PreviewURL(url string) (Timeline, error)
}

View File

@ -0,0 +1,15 @@
package microsub
import (
"encoding/json"
"fmt"
"testing"
"github.com/pstuifzand/ekster/microsub"
)
func TestJson(t *testing.T) {
item := microsub.Item{Type: "entry"}
result, err := json.Marshal(item)
fmt.Println(string(result), err)
}