hydrocarbon

package module
v0.0.0-...-9b45353 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 30, 2018 License: MIT Imports: 22 Imported by: 6

README

hydrocarbon

not just an rss reader.

development

Run a copy of postgres somewhere with

docker run -p 5432:5432 postgres:alpine
go get -u github.com/fortytw2/hydrocarbon/...
cd $GOPATH/src/github.com/fortytw2/hydrocarbon/ui
yarn
cd $GOPATH/src/github.com/fortytw2/hydrocarbon/cmd/hydrocarbon
go generate $(go list ../../... | grep -v vendor) && go build -i . && POSTGRES_DSN=postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable ./hydrocarbon -autoexplain

then open port :8080, enter an email, get the login token from hydrocarbon STDOUT and proceed to develop.

Configuring Image Server

Hydrocarbon has two modes for downloading and rehosting images, a local server and a Google Cloud Storage backed server. To use the local server, configure nothing.

To configure google cloud storage, set GCP_SERVICE_ACCOUNT, IMAGE_BUCKET_NAME and IMAGE_DOMAIN.

license

mit

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetRemoteIP

func GetRemoteIP(r *http.Request) string

func NewRouter

func NewRouter(ua *UserAPI, fa *FeedAPI, rs *ReadStatusAPI, domain string) http.Handler

NewRouter configures a new http.Handler that serves hydrocarbon

Types

type ErrorHandler

type ErrorHandler func(w http.ResponseWriter, r *http.Request) error

ErrorHandler wraps up common error handling patterns for http routers

func (ErrorHandler) ServeHTTP

func (eh ErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

type Feed

type Feed struct {
	ID        string    `json:"id"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
	Title     string    `json:"title"`
	Plugin    string    `json:"plugin"`
	BaseURL   string    `json:"base_url"`

	Unread int `json:"unread"`

	Posts []*Post `json:"posts"`
}

A Feed is a collection of posts

type FeedAPI

type FeedAPI struct {
	// contains filtered or unexported fields
}

FeedAPI encapsulates everything related to user management

func NewFeedAPI

func NewFeedAPI(s FeedStore, dc *discollect.Discollector, ks *KeySigner) *FeedAPI

NewFeedAPI returns a new Feed API

func (*FeedAPI) AddFeed

func (fa *FeedAPI) AddFeed(w http.ResponseWriter, r *http.Request) error

AddFeed adds the specified feed to the given user if folder_id is left out, the feed is added to the users "default" folder

func (*FeedAPI) AddFolder

func (fa *FeedAPI) AddFolder(w http.ResponseWriter, r *http.Request) error

AddFolder creates a new folder

func (*FeedAPI) GetFeed

func (fa *FeedAPI) GetFeed(w http.ResponseWriter, r *http.Request) error

GetFeed writes a specific feed

func (*FeedAPI) GetFolders

func (fa *FeedAPI) GetFolders(w http.ResponseWriter, r *http.Request) error

GetFolders writes all of a users folders out

func (*FeedAPI) GetPost

func (fa *FeedAPI) GetPost(w http.ResponseWriter, r *http.Request) error

GetPost writes a single post out

func (*FeedAPI) RemoveFeed

func (fa *FeedAPI) RemoveFeed(w http.ResponseWriter, r *http.Request) error

RemoveFeed removes the given feed from the users list

type FeedStore

type FeedStore interface {
	AddFeed(ctx context.Context, sessionKey, folderID, title, plugin, feedURL string, initConf *discollect.Config) (string, error)
	CheckIfFeedExists(ctx context.Context, sessionKey, folderID, plugin, url string) (*Feed, bool, error)
	RemoveFeed(ctx context.Context, sessionKey, folderID, feedID string) error

	AddFolder(ctx context.Context, sessionKey, name string) (string, error)

	// GetFolders should not return any Posts in the nested Feeds
	GetFoldersWithFeeds(ctx context.Context, sessionKey string) ([]*Folder, error)
	// Return Post Title, PostedAt, Read, and ID
	GetFeedPosts(ctx context.Context, sessionKey, feedID string, limit, offset int) (*Feed, error)
	GetPost(ctx context.Context, sessionKey, postID string) (*Post, error)
}

A FeedStore is an interface used to seperate the FeedAPI from knowledge of the actual underlying database

type Folder

type Folder struct {
	ID    string  `json:"id"`
	Title string  `json:"title"`
	Feeds []*Feed `json:"feeds"`
}

A Folder holds a collection of feeds

type KeySigner

type KeySigner struct {
	// contains filtered or unexported fields
}

A KeySigner is used to verify the integrity of SessionKeys at the system borders

func NewKeySigner

func NewKeySigner(key string) *KeySigner

NewKeySigner creates a new KeySigner with the given key

func (*KeySigner) Sign

func (ks *KeySigner) Sign(val string) (string, error)

Sign appends an HMAC to a value

func (*KeySigner) Verify

func (ks *KeySigner) Verify(pubVal string) (string, error)

Verify checks a value signed with Sign

type Mailer

type Mailer interface {
	Send(email, subject, body string) error
	RootDomain() string
}

A Mailer sends mail

type MockMailer

type MockMailer struct {
	Mails []string
}

MockMailer is a fake mailer that records all mails sent

func (*MockMailer) RootDomain

func (mm *MockMailer) RootDomain() string

RootDomain returns the MockMailer's rootdomain, always localhost TODO: this is probably broken

func (*MockMailer) Send

func (mm *MockMailer) Send(email, subject, body string) error

Send stores a mail in the local MockMailer

type Post

type Post struct {
	ID        string    `json:"id"`
	CreatedAt time.Time `json:"created_at"`
	PostedAt  time.Time `json:"posted_at"`
	UpdatedAt time.Time `json:"updated_at"`

	// TODO(fortytw2): normalize this
	OriginalURL string `json:"original_url"`
	URL         string `json:"url"`

	Title  string `json:"title"`
	Author string `json:"author"`
	Body   string `json:"body"`

	Read bool `json:"read"`

	Extra map[string]interface{} `json:"extra"`
}

A Post is a single post on a feed

func (*Post) ContentHash

func (p *Post) ContentHash() string

ContentHash returns the stable hex encoded SHA256 of a post

type ReadStatusAPI

type ReadStatusAPI struct {
	// contains filtered or unexported fields
}

func NewReadStatusAPI

func NewReadStatusAPI(s ReadStatusStore, ks *KeySigner) *ReadStatusAPI

NewReadStatusAPI returns a new Feed API

func (*ReadStatusAPI) MarkRead

func (rs *ReadStatusAPI) MarkRead(w http.ResponseWriter, r *http.Request) error

MarkRead marks the given post as read

type ReadStatusStore

type ReadStatusStore interface {
	MarkRead(ctx context.Context, postID, sessionKey string) error
}

ReadStatusStore tracks read_statuses

type Session

type Session struct {
	CreatedAt time.Time `json:"created_at"`
	UserAgent string    `json:"user_agent"`
	IP        string    `json:"ip"`
	Active    bool      `json:"active"`
}

A Session is a session

type StdoutMailer

type StdoutMailer struct {
	Domain string
}

StdoutMailer writes all emails to Stdout, perfect for dev / debugging

func (*StdoutMailer) RootDomain

func (sm *StdoutMailer) RootDomain() string

RootDomain returns the StdoutMailer root domain

func (*StdoutMailer) Send

func (*StdoutMailer) Send(email, subject, body string) error

Send writes the email to stdout

type UserAPI

type UserAPI struct {
	// contains filtered or unexported fields
}

UserAPI encapsulates everything related to user management

func NewUserAPI

func NewUserAPI(s UserStore, ks *KeySigner, m Mailer, stripePlanID, stripeKey string, paymentRequired bool) *UserAPI

NewUserAPI sets up a new UserAPI used for user/session management

func (*UserAPI) Activate

func (ua *UserAPI) Activate(w http.ResponseWriter, r *http.Request) error

Activate exchanges a token for a session key that can be used to make authenticated requests

func (*UserAPI) CreatePayment

func (ua *UserAPI) CreatePayment(w http.ResponseWriter, r *http.Request) error

CreatePayment sets up the initial stripe stuff for a user

func (*UserAPI) Deactivate

func (ua *UserAPI) Deactivate(w http.ResponseWriter, r *http.Request) error

Deactivate disables a key that the user is currently using

func (*UserAPI) DisableEmailVerification

func (ua *UserAPI) DisableEmailVerification()

func (*UserAPI) ListSessions

func (ua *UserAPI) ListSessions(w http.ResponseWriter, r *http.Request) error

ListSessions writes out all of a users current / past sessions

func (*UserAPI) RequestToken

func (ua *UserAPI) RequestToken(w http.ResponseWriter, r *http.Request) error

RequestToken emails a token that can be exchanged for a session

func (*UserAPI) VerifyKey

func (ua *UserAPI) VerifyKey(w http.ResponseWriter, r *http.Request) error

VerifyKey validates that the session currently exists in the database

type UserStore

type UserStore interface {
	// ensure the given session key exists
	VerifyKey(ctx context.Context, key string) error

	CreateOrGetUser(ctx context.Context, email string) (string, bool, error)
	SetStripeIDs(ctx context.Context, userID, customerID, subscriptionID string) error

	CreateLoginToken(ctx context.Context, userID, userAgent, ip string) (string, error)
	ActivateLoginToken(ctx context.Context, token string) (string, error)

	CreateSession(ctx context.Context, userID, userAgent, ip string) (string, string, error)
	ListSessions(ctx context.Context, key string, page int) ([]*Session, error)
	DeactivateSession(ctx context.Context, key string) error
}

A UserStore is an interface used to seperate the UserAPI from knowledge of the actual underlying database

Directories

Path Synopsis
cmd
redis
package redis implements a lightweight queue on top of RPOPLPUSH for hydrocarbon to use
package redis implements a lightweight queue on top of RPOPLPUSH for hydrocarbon to use
plugins
jsonfeed
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
rss

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL