usecases

package
v0.0.0-...-1fa16a9 Latest Latest
Warning

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

Go to latest
Published: May 26, 2023 License: AGPL-3.0 Imports: 13 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AggregateVotes

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

func NewAggregateVotesUseCase

func NewAggregateVotesUseCase(logger common.Logger, database Database) *AggregateVotes

func (*AggregateVotes) Execute

func (u *AggregateVotes) Execute(ctx context.Context, input AggregateVotesInput)

votes are deduped in several ways:

  • first we could have many votes for the same thread/comment, so we mark them as dirty based on votes for that id and only aggregate once
  • secondly, there is no guarantee that the votes in the slice are in-order or that the vote we are processing is the latest vote for that thread/comment. so we check the vote's updatedAt timestamp against the latest vote for that thread/comment in the db and only aggregate if the vote is newer

TODO: Could do some batch processing in the db here

type AggregateVotesInput

type AggregateVotesInput struct {
	Votes []entities.Vote
}

type Authenticate

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

func NewAuthenticateUseCase

func NewAuthenticateUseCase(settings settings.Settings) *Authenticate

func (*Authenticate) Execute

func (u *Authenticate) Execute(ctx context.Context, input *AuthenticateInput) (string, error)

type AuthenticateInput

type AuthenticateInput struct {
	Token string
}

type Blockchain

type Blockchain interface {
	Start(ctx context.Context)
	Shutdown(ctx context.Context)
	GetNameByAddress(ctx context.Context, address string) (*string, error)
	GetAvatarURIByName(ctx context.Context, name string) (*string, error)
	GetNFTURI(ctx context.Context, standard string, address string, id string) (string, error)
}

type Buffer

type Buffer map[string]AggregateVotesInput

type Cache

type Cache interface {
	Start(ctx context.Context)
	Shutdown(ctx context.Context)
	VerifyRateLimit(ctx context.Context, key string, rate int, period time.Duration) error
}

type CreateComment

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

func NewCreateCommentUseCase

func NewCreateCommentUseCase(database Database, storage Storage) *CreateComment

func (*CreateComment) Execute

type CreateCommentInput

type CreateCommentInput struct {
	ThreadId           int64  `validate:"gt=0"`
	RepliedToCommentId *int64 `validate:"omitempty,gt=0"`
	Address            string `validate:"eth_addr"`
	Content            string `validate:"max=1000"`
	ImageFileName      string `validate:"max=100"`
}

type CreateThread

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

func NewCreateThreadUseCase

func NewCreateThreadUseCase(logger common.Logger, storage Storage, database Database) *CreateThread

func (*CreateThread) Execute

type CreateThreadInput

type CreateThreadInput struct {
	Address       string `validate:"eth_addr"`
	Title         string `validate:"max=100"`
	Content       string `validate:"max=1000"`
	ImageFileName string `validate:"max=100"`
}

type CreateVote

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

func NewCreateVoteUseCase

func NewCreateVoteUseCase(stream Stream, logger common.Logger) *CreateVote

func (*CreateVote) Execute

func (u *CreateVote) Execute(ctx context.Context, input CreateVoteInput) error

type CreateVoteInput

type CreateVoteInput struct {
	Id      int64            `validate:"gt=0"`
	Address string           `validate:"eth_addr"`
	Value   common.VoteValue `validate:"oneof=upvote downvote unvote"`
	Type    common.VoteType  `validate:"oneof=thread comment"`
}

type Database

type Database interface {
	Start(ctx context.Context)
	Shutdown(ctx context.Context)

	GetChallengeByAddress(ctx context.Context, address string) (entities.Challenge, error)
	SaveChallenge(ctx context.Context, challenge entities.Challenge) error

	GetUserByAddress(ctx context.Context, address string) (entities.User, error)
	GetThreads(ctx context.Context, limit int64) ([]entities.Thread, error)
	GetThreadById(ctx context.Context, threadId int64) (entities.Thread, error)
	GetComments(ctx context.Context, threadId int64, offset int64, limit int64) ([]entities.Comment, int64, error)
	GetCommentById(ctx context.Context, commentId int64) (entities.Comment, error)

	UpsertUser(ctx context.Context, address string) error
	UpdateUser(ctx context.Context, address string, name *string, avatar *entities.Image) error
	CreateComment(ctx context.Context, threadId int64, address string, repliedToCommentId *int64, content string, imageFileName string, imageUrl string, imageContentType string) (entities.Comment, error)
	CreateThread(ctx context.Context, address string, title string, content string, imageFileName string, imageUrl string, imageContentType string) (entities.Thread, error)
	CreateVote(ctx context.Context, vote entities.Vote) error
	DeleteThread(ctx context.Context, threadId int64) error
	DeleteComment(ctx context.Context, commentId int64) error
	AggregateVotes(ctx context.Context, id int64, voteType common.VoteType) error
}

type DeleteComment

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

func NewDeleteCommentUseCase

func NewDeleteCommentUseCase(database Database) *DeleteComment

func (*DeleteComment) Execute

func (u *DeleteComment) Execute(ctx context.Context, input DeleteCommentInput) error

type DeleteCommentInput

type DeleteCommentInput struct {
	Id             int64  `validate:"gt=0"`
	DeleterAddress string `validate:"eth_addr"`
}

type DeleteThread

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

func NewDeleteThreadUseCase

func NewDeleteThreadUseCase(database Database) *DeleteThread

func (*DeleteThread) Execute

func (u *DeleteThread) Execute(ctx context.Context, input DeleteThreadInput) error

type DeleteThreadInput

type DeleteThreadInput struct {
	ThreadId       int64  `validate:"gt=0"`
	DeleterAddress string `validate:"eth_addr"`
}

type GetChallenge

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

func NewGetChallengeUseCase

func NewGetChallengeUseCase(database Database) *GetChallenge

func (*GetChallenge) Execute

type GetChallengeInput

type GetChallengeInput struct {
	Address string `validate:"eth_addr"`
}

type GetComments

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

func NewGetCommentsUseCase

func NewGetCommentsUseCase(database Database) *GetComments

func (*GetComments) Execute

func (u *GetComments) Execute(ctx context.Context, input GetCommentsInput) ([]entities.Comment, int64, error)

type GetCommentsInput

type GetCommentsInput struct {
	ThreadId int64 `validate:"gt=0"`
	Offset   int64 `validate:"gte=0"`
	Limit    int64 `validate:"gt=0,lte=100"`
}

type GetThread

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

func NewGetThreadUseCase

func NewGetThreadUseCase(database Database) *GetThread

func (*GetThread) Execute

func (u *GetThread) Execute(ctx context.Context, input GetThreadInput) (entities.Thread, int64, error)

type GetThreadInput

type GetThreadInput struct {
	ThreadId      int64 `validate:"gt=0"`
	CommentOffset int64 `validate:"gte=0"`
	CommentLimit  int64 `validate:"gt=0,lte=100"`
}

type GetThreads

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

func NewGetThreadsUseCase

func NewGetThreadsUseCase(database Database, logger common.Logger) *GetThreads

func (*GetThreads) Execute

func (u *GetThreads) Execute(ctx context.Context, input GetThreadsInput) ([]entities.Thread, error)

Threads returned are random and thus the concept of pages/offset/count is not relevant

type GetThreadsInput

type GetThreadsInput struct {
	Limit int64 `validate:"gte=0,lte=100"`
}

type GetUser

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

func NewGetUserUseCase

func NewGetUserUseCase(logger common.Logger, database Database) *GetUser

func (*GetUser) Execute

func (g *GetUser) Execute(ctx context.Context, input GetUserInput) (entities.User, error)

type GetUserInput

type GetUserInput struct {
	Address string `validate:"eth_addr"`
}

type HydrateUsers

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

func NewHydrateUsersUseCase

func NewHydrateUsersUseCase(logger common.Logger, blockchain Blockchain, database Database, storage Storage, safeProxy SafeProxy) *HydrateUsers

func (*HydrateUsers) Execute

func (u *HydrateUsers) Execute(ctx context.Context, input HydrateUsersInput)

There be dragons below.

The general reasoning behind doing all this work async in the backend is that avatars are very dynamic, slow, unreliable and potentially very big. The goal is to have a fast, reliable and small profile pictures that can be rendered in a browser very quickly to not destroy page load times, SEO and user experience. The avatar image is thus resolved, uploaded and cached in our CDN and the url is stored in the database. But resolving the actual image url from an avatar text record is quite an involved process. See: https://docs.ens.domains/ens-improvement-proposals/ensip-12-avatar-text-records

Steps:

  1. Fetch the avatar text record from ENS using the name
  2. This record can point to any arbitrary server, so we proxy all the following http requests through a "safe" proxy to avoid leaking sensitive server information
  3. If nft uri detected, parse information and fetch the nft metadata uri from the contract then follow the metadata uri to get the image url.
  4. The resulting image url is hashed to derive a unique and idempotent file name
  5. If IPFS scheme detected on the url, resolve the https ipfs url
  6. Check if the file already exists in storage
  7. If not, download the image and upload it to our storage

TODO:

  • Supported Data URIs
  • Support other chains for NFT URIs

type HydrateUsersInput

type HydrateUsersInput struct {
	Addresses []string
}

type RateLimit

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

func NewVerifyRateLimitUseCase

func NewVerifyRateLimitUseCase(
	logger common.Logger,
	cache Cache,
) *RateLimit

func (*RateLimit) Execute

func (u *RateLimit) Execute(ctx context.Context, input *RateLimitInput) error

type RateLimitInput

type RateLimitInput struct {
	Namespace string        `validate:"min=1,max=100"`
	IpAddress string        `validate:"ip"`
	Rate      int           `validate:"gt=0"`
	Period    time.Duration `validate:"gt=0"`
}

type SafeProxy

type SafeProxy interface {
	Start(ctx context.Context)
	Shutdown(ctx context.Context)
	DownloadImage(ctx context.Context, uri string) (*[]byte, string, error)
	GetNFTImageURI(ctx context.Context, uri string) (string, error)
}

type Signin

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

func NewSigninUseCase

func NewSigninUseCase(logger common.Logger, settings settings.Settings, database Database, stream Stream) *Signin

func (*Signin) Execute

func (u *Signin) Execute(ctx context.Context, input SigninInput) (string, error)

type SigninInput

type SigninInput struct {
	Address   string `validate:"eth_addr"`
	Signature string `validate:"hexadecimal,min=1"`
}

type Storage

type Storage interface {
	Start(ctx context.Context)
	Shutdown(ctx context.Context)
	UploadImage(ctx context.Context, fileName string, contentType string, data *[]byte) (entities.Image, error)
	GetImageByFileName(ctx context.Context, fileName string) (*entities.Image, error)
}

type Stream

type Stream interface {
	Start(ctx context.Context)
	Shutdown(ctx context.Context)
	PublishSignin(ctx context.Context, address string) error
	PublishVote(ctx context.Context, vote entities.Vote) error
}

type UploadImage

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

func NewUploadImageUsecase

func NewUploadImageUsecase(logger common.Logger, storage Storage) *UploadImage

func (*UploadImage) Execute

func (u *UploadImage) Execute(ctx context.Context, input UploadImageInput) (entities.Image, error)

type UploadImageInput

type UploadImageInput struct {
	ContentType string  `validate:"oneof=image/jpeg image/png image/gif image/webp"`
	Bytes       *[]byte `validate:"required"`
}

Jump to

Keyboard shortcuts

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