From 70f5fb82f936e9c62c9d1ea35397882c68e16b56 Mon Sep 17 00:00:00 2001 From: Peter Stuifzand Date: Thu, 7 Mar 2019 20:55:25 +0100 Subject: [PATCH] Improve source code --- .pre-commit-config.yaml | 18 ++++++++ cmd/eksterd/main.go | 18 +------- cmd/eksterd/memory.go | 59 +++++++++++++----------- cmd/eksterd/timeline.go | 6 ++- pkg/client/requests.go | 8 ++-- pkg/microsub/protocol.go | 20 +-------- pkg/microsub/protocol_test.go | 84 +++++++++++++++++++++++++++++++++++ pkg/server/microsub.go | 21 +++------ pkg/server/microsub_test.go | 2 +- pkg/server/null.go | 10 +++-- 10 files changed, 159 insertions(+), 87 deletions(-) create mode 100644 .pre-commit-config.yaml create mode 100644 pkg/microsub/protocol_test.go diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..0d19b3e --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,18 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.1.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-merge-conflict + - id: check-added-large-files +- repo: https://github.com/dnephin/pre-commit-golang + rev: master + hooks: + - id: go-vet + - id: go-fmt + - id: go-lint + - id: go-unit-tests diff --git a/cmd/eksterd/main.go b/cmd/eksterd/main.go index 8268efa..4f454bc 100644 --- a/cmd/eksterd/main.go +++ b/cmd/eksterd/main.go @@ -1,19 +1,5 @@ /* - Microsub server - Copyright (C) 2018 Peter Stuifzand - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . +Package main contains the main command for the Microsub server. */ package main @@ -77,7 +63,7 @@ func WithAuth(handler http.Handler, b *memoryBackend) http.Handler { return } - if token.Me != b.Me { + if token.Me != b.Me { // FIXME: Me should be part of the request log.Printf("Missing \"me\" in token response: %#v\n", token) http.Error(w, "Wrong me", 403) return diff --git a/cmd/eksterd/memory.go b/cmd/eksterd/memory.go index e778ccc..bc49687 100644 --- a/cmd/eksterd/memory.go +++ b/cmd/eksterd/memory.go @@ -1,19 +1,20 @@ /* - Microsub server - Copyright (C) 2018 Peter Stuifzand +Package main runs the microsub server - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. +Copyright (C) 2018 Peter Stuifzand - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. - You should have received a copy of the GNU General Public License - along with this program. If not, see . +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . */ package main @@ -42,6 +43,7 @@ import ( "willnorris.com/go/microformats" ) +// DefaultPrio is the priority value for new channels const DefaultPrio = 9999999 type memoryBackend struct { @@ -51,10 +53,10 @@ type memoryBackend struct { Channels map[string]microsub.Channel Feeds map[string][]microsub.Feed Settings map[string]channelSetting - NextUid int + NextUID int - Me string - TokenEndpoint string + Me string // FIXME: should be removed + TokenEndpoint string // FIXME: should be removed AuthEnabled bool ticker *time.Ticker @@ -68,6 +70,7 @@ type channelSetting struct { IncludeRegex string } +// Debug interface for easy of use in other packages type Debug interface { Debug() } @@ -176,7 +179,8 @@ func createMemoryBackend() { backend.Channels[c.UID] = c } - backend.NextUid = 1000000 + backend.NextUID = 1000000 + // FIXME: can't be used in Backend backend.Me = "https://example.com/" backend.lock.Unlock() @@ -443,24 +447,24 @@ func (b *memoryBackend) Search(query string) ([]microsub.Feed, error) { } defer resp.Body.Close() - fetchUrl, err := url.Parse(u) - md := microformats.Parse(resp.Body, fetchUrl) + fetchURL, err := url.Parse(u) + md := microformats.Parse(resp.Body, fetchURL) if err != nil { log.Printf("Error while fetching %s: %v\n", u, err) continue } - feedResp, err := Fetch2(fetchUrl.String()) + feedResp, err := Fetch2(fetchURL.String()) if err != nil { - log.Printf("Error in fetch of %s - %v\n", fetchUrl, err) + log.Printf("Error in fetch of %s - %v\n", fetchURL, err) continue } defer feedResp.Body.Close() // TODO: Combine FeedHeader and FeedItems so we can use it here - parsedFeed, err := fetch.FeedHeader(&fetch2{}, fetchUrl.String(), feedResp.Header.Get("Content-Type"), feedResp.Body) + parsedFeed, err := fetch.FeedHeader(&fetch2{}, fetchURL.String(), feedResp.Header.Get("Content-Type"), feedResp.Body) if err != nil { - log.Printf("Error in parse of %s - %v\n", fetchUrl, err) + log.Printf("Error in parse of %s - %v\n", fetchURL, err) continue } @@ -706,7 +710,7 @@ func Fetch2(fetchURL string) (*http.Response, error) { client := http.Client{} resp, err := client.Do(req) if err != nil { - return nil, fmt.Errorf("fetch failed: %s", u, err) + return nil, fmt.Errorf("fetch failed: %s: %s", u, err) } defer resp.Body.Close() @@ -724,10 +728,11 @@ func Fetch2(fetchURL string) (*http.Response, error) { } func (b *memoryBackend) createChannel(name string) microsub.Channel { - uid := fmt.Sprintf("%012d", b.NextUid) + uid := fmt.Sprintf("%012d", b.NextUID) channel := microsub.Channel{ - UID: uid, - Name: name, + UID: uid, + Name: name, + Unread: microsub.Unread{microsub.UnreadCount, false, 0}, } return channel } @@ -737,7 +742,7 @@ func (b *memoryBackend) setChannel(channel microsub.Channel) { defer b.lock.Unlock() b.Channels[channel.UID] = channel b.Feeds[channel.UID] = []microsub.Feed{} - b.NextUid++ + b.NextUID++ } func updateChannelInRedis(conn redis.Conn, uid string, prio int) { diff --git a/cmd/eksterd/timeline.go b/cmd/eksterd/timeline.go index 2fff6ca..c1c5768 100644 --- a/cmd/eksterd/timeline.go +++ b/cmd/eksterd/timeline.go @@ -291,8 +291,10 @@ func (timeline *redisStreamTimeline) Items(before, after string) (microsub.Timel } return microsub.Timeline{ - Items: items, - Paging: microsub.Pagination{}, + Items: items, + Paging: microsub.Pagination{ + After: items[len(items)-1].ID, + }, }, nil } diff --git a/pkg/client/requests.go b/pkg/client/requests.go index 48a918e..6afdcb5 100644 --- a/pkg/client/requests.go +++ b/pkg/client/requests.go @@ -13,6 +13,7 @@ import ( "p83.nl/go/ekster/pkg/microsub" ) +// Client is a HTTP client for Microsub type Client struct { Me *url.URL MicrosubEndpoint *url.URL @@ -120,6 +121,7 @@ func (c *Client) microsubPostFormRequest(action string, args map[string]string, return res, err } +// ChannelsGetList gets the channels from a Microsub server func (c *Client) ChannelsGetList() ([]microsub.Channel, error) { args := make(map[string]string) res, err := c.microsubGetRequest("channels", args) @@ -146,6 +148,7 @@ func (c *Client) ChannelsGetList() ([]microsub.Channel, error) { return channels.Channels, err } +// TimelineGet gets a timeline from a Microsub server func (c *Client) TimelineGet(before, after, channel string) (microsub.Timeline, error) { args := make(map[string]string) args["after"] = after @@ -172,6 +175,7 @@ func (c *Client) TimelineGet(before, after, channel string) (microsub.Timeline, return timeline, nil } +// PreviewURL gets a Timeline for a url from a Microsub server func (c *Client) PreviewURL(url string) (microsub.Timeline, error) { args := make(map[string]string) args["url"] = url @@ -338,7 +342,3 @@ func (c *Client) MarkRead(channel string, uids []string) error { res.Body.Close() return nil } - -func (c *Client) AddEventListener(el microsub.EventListener) error { - panic("implement me") -} diff --git a/pkg/microsub/protocol.go b/pkg/microsub/protocol.go index f62ec18..7b96e58 100644 --- a/pkg/microsub/protocol.go +++ b/pkg/microsub/protocol.go @@ -1,21 +1,3 @@ -/* - Microsub server - Copyright (C) 2018 Peter Stuifzand - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - // Package microsub describes the protocol methods of the Microsub protocol package microsub @@ -34,11 +16,13 @@ import ( block / unblock */ +// Constants for Unread const ( UnreadBool = 0 UnreadCount = 1 ) +// Unread is a special int/bool value for the JSON response type Unread struct { Type int Unread bool diff --git a/pkg/microsub/protocol_test.go b/pkg/microsub/protocol_test.go new file mode 100644 index 0000000..1a911e2 --- /dev/null +++ b/pkg/microsub/protocol_test.go @@ -0,0 +1,84 @@ +package microsub + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_UnmarshalUnreadBool(t *testing.T) { + var x Unread + err := json.Unmarshal([]byte("false"), &x) + if assert.NoError(t, err) { + assert.Equal(t, UnreadBool, x.Type) + assert.False(t, x.Unread) + } +} + +func Test_UnmarshalUnreadBoolTrue(t *testing.T) { + var x Unread + err := json.Unmarshal([]byte("true"), &x) + if assert.NoError(t, err) { + assert.Equal(t, UnreadBool, x.Type) + assert.True(t, x.Unread) + } +} + +func Test_UnmarshalUnreadIntZero(t *testing.T) { + var x Unread + err := json.Unmarshal([]byte("0"), &x) + if assert.NoError(t, err) { + assert.Equal(t, UnreadCount, x.Type) + assert.Equal(t, 0, x.UnreadCount) + } +} + +func Test_UnmarshalUnreadIntNonZero(t *testing.T) { + var x Unread + err := json.Unmarshal([]byte("209449"), &x) + if assert.NoError(t, err) { + assert.Equal(t, UnreadCount, x.Type) + assert.Equal(t, 209449, x.UnreadCount) + } +} + +func Test_MarshalUnreadEmpty(t *testing.T) { + x := Unread{} + bytes, err := json.Marshal(x) + if assert.NoError(t, err) { + assert.Equal(t, "false", string(bytes)) + } +} + +func Test_MarshalUnreadBoolFalse(t *testing.T) { + x := Unread{Type: UnreadBool, Unread: false} + bytes, err := json.Marshal(x) + if assert.NoError(t, err) { + assert.Equal(t, "false", string(bytes)) + } +} + +func Test_MarshalUnreadBoolTrue(t *testing.T) { + x := Unread{Type: UnreadBool, Unread: true} + bytes, err := json.Marshal(x) + if assert.NoError(t, err) { + assert.Equal(t, "true", string(bytes)) + } +} + +func Test_MarshalUnreadIntZero(t *testing.T) { + x := Unread{Type: UnreadCount, UnreadCount: 0} + bytes, err := json.Marshal(x) + if assert.NoError(t, err) { + assert.Equal(t, "0", string(bytes)) + } +} + +func Test_MarshalUnreadIntNonZero(t *testing.T) { + x := Unread{Type: UnreadCount, UnreadCount: 1884844} + bytes, err := json.Marshal(x) + if assert.NoError(t, err) { + assert.Equal(t, "1884844", string(bytes)) + } +} diff --git a/pkg/server/microsub.go b/pkg/server/microsub.go index 9133f1b..02abd68 100644 --- a/pkg/server/microsub.go +++ b/pkg/server/microsub.go @@ -1,19 +1,6 @@ /* - ekster - microsub server - Copyright (C) 2018 Peter Stuifzand - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . +Package server contains the microsub server itself. It implements http.Handler. +It follows the spec at https://indieweb.org/Microsub-spec. */ package server @@ -31,6 +18,7 @@ var ( entryRegex = regexp.MustCompile("^entry\\[\\d+\\]$") ) +// Constants used for the responses const ( OutputContentType = "application/json; charset=utf-8" ) @@ -51,11 +39,14 @@ func respondJSON(w http.ResponseWriter, value interface{}) { } } +// NewMicrosubHandler is the main entry point for the microsub server +// It returns a handler for HTTP and a broker that will send events. func NewMicrosubHandler(backend microsub.Microsub) (http.Handler, *Broker) { broker := NewServer() return µsubHandler{backend, broker}, broker } +// Methods required by http.Handler func (h *microsubHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { r.ParseForm() diff --git a/pkg/server/microsub_test.go b/pkg/server/microsub_test.go index 4be0dd5..57bbb41 100644 --- a/pkg/server/microsub_test.go +++ b/pkg/server/microsub_test.go @@ -14,7 +14,7 @@ import ( func createServerClient() (*httptest.Server, *client.Client) { backend := &NullBackend{} - handler := NewMicrosubHandler(backend) + handler, _ := NewMicrosubHandler(backend) server := httptest.NewServer(handler) diff --git a/pkg/server/null.go b/pkg/server/null.go index 9e3f6a3..6e347bd1 100644 --- a/pkg/server/null.go +++ b/pkg/server/null.go @@ -25,10 +25,6 @@ import ( type NullBackend struct { } -func (b *NullBackend) AddEventListener(el microsub.EventListener) error { - panic("implement me") -} - // ChannelsGetList gets no channels func (b *NullBackend) ChannelsGetList() ([]microsub.Channel, error) { return []microsub.Channel{ @@ -66,26 +62,31 @@ func (b *NullBackend) TimelineGet(before, after, channel string) (microsub.Timel }, nil } +// FollowGetList implements the follow list command func (b *NullBackend) FollowGetList(uid string) ([]microsub.Feed, error) { return []microsub.Feed{ {Name: "test", Type: "feed", URL: "https://example.com/"}, }, nil } +// FollowURL follows a new url func (b *NullBackend) FollowURL(uid string, url string) (microsub.Feed, error) { return microsub.Feed{Type: "feed", URL: url}, nil } +// UnfollowURL unfollows a url func (b *NullBackend) UnfollowURL(uid string, url string) error { return nil } +// Search search for a query and return an example list of feeds func (b *NullBackend) Search(query string) ([]microsub.Feed, error) { return []microsub.Feed{ {"feed", "https://example.com/", "Example", "test.jpg", "test", microsub.Card{}}, }, nil } +// PreviewURL shows an empty feed func (b *NullBackend) PreviewURL(url string) (microsub.Timeline, error) { return microsub.Timeline{ Paging: microsub.Pagination{}, @@ -93,6 +94,7 @@ func (b *NullBackend) PreviewURL(url string) (microsub.Timeline, error) { }, nil } +// MarkRead marks no items as read func (b *NullBackend) MarkRead(channel string, uids []string) error { return nil }