server

package
v0.0.0-...-a657b10 Latest Latest
Warning

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

Go to latest
Published: Nov 29, 2021 License: MIT Imports: 38 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrEmpty = fmt.Errorf("must provide an event payload")

ErrEmpty is returned if an Event's payload is nil.

Functions

func BoardStateKey

func BoardStateKey(gameID, userID string) string

BoardStateKey formats a board state key for boardstate to user mapping.

func GameKey

func GameKey(gameID string) string

GameKey formats the keys for Games in our Directory

func NewExecutableSchema

func NewExecutableSchema(cfg Config) graphql.ExecutableSchema

NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.

func NewGraphQLServer

func NewGraphQLServer(
	kv persistence.KV,
	db *sql.DB,
	cfg Conf,
) (*graphQLServer, error)

NewGraphQLServer creates a new server to attach the database, game engine, and graphql connections together

Types

type BoardObserver

type BoardObserver struct {
	// The UserID of the user subscribing to BoardUpdates
	UserID string
	// the channel that BoardUpdates are passed down
	Channel chan *BoardState
}

BoardObserver wraps a UserID to a BoardState channel emiter.

type BoardState

type BoardState struct {
	User       *User      `json:"User"`
	Life       int        `json:"Life"`
	GameID     string     `json:"GameID"`
	Commander  []*Card    `json:"Commander"`
	Library    []*Card    `json:"Library"`
	Graveyard  []*Card    `json:"Graveyard"`
	Exiled     []*Card    `json:"Exiled"`
	Field      []*Card    `json:"Field"`
	Hand       []*Card    `json:"Hand"`
	Revealed   []*Card    `json:"Revealed"`
	Controlled []*Card    `json:"Controlled"`
	Counters   []*Counter `json:"Counters"`
}

type Card

type Card struct {
	FaceName              *string    `json:"FaceName"`
	Name                  string     `json:"Name"`
	ID                    string     `json:"ID"`
	Quantity              *int       `json:"Quantity"`
	Tapped                *bool      `json:"Tapped"`
	Flipped               *bool      `json:"Flipped"`
	Counters              []*Counter `json:"Counters"`
	Colors                *string    `json:"Colors"`
	ColorIdentity         *string    `json:"ColorIdentity"`
	FaceManaValue         *string    `json:"FaceManaValue"`
	FaceConvertedManaCost *string    `json:"FaceConvertedManaCost"`
	Cmc                   *string    `json:"CMC"`
	ManaCost              *string    `json:"ManaCost"`
	UUID                  *string    `json:"UUID"`
	Power                 *string    `json:"Power"`
	Toughness             *string    `json:"Toughness"`
	Types                 *string    `json:"Types"`
	Subtypes              *string    `json:"Subtypes"`
	Supertypes            *string    `json:"Supertypes"`
	Text                  *string    `json:"Text"`
	Tcgid                 *string    `json:"TCGID"`
	ScryfallID            *string    `json:"ScryfallID"`
}

func Shuffle

func Shuffle(deck []*Card) ([]*Card, error)

Shuffle will apply a Knuth shuffle to the decklist.

type ComplexityRoot

type ComplexityRoot struct {
	BoardState struct {
		Commander  func(childComplexity int) int
		Controlled func(childComplexity int) int
		Counters   func(childComplexity int) int
		Exiled     func(childComplexity int) int
		Field      func(childComplexity int) int
		GameID     func(childComplexity int) int
		Graveyard  func(childComplexity int) int
		Hand       func(childComplexity int) int
		Library    func(childComplexity int) int
		Life       func(childComplexity int) int
		Revealed   func(childComplexity int) int
		User       func(childComplexity int) int
	}

	Card struct {
		Cmc                   func(childComplexity int) int
		ColorIdentity         func(childComplexity int) int
		Colors                func(childComplexity int) int
		Counters              func(childComplexity int) int
		FaceConvertedManaCost func(childComplexity int) int
		FaceManaValue         func(childComplexity int) int
		FaceName              func(childComplexity int) int
		Flipped               func(childComplexity int) int
		ID                    func(childComplexity int) int
		ManaCost              func(childComplexity int) int
		Name                  func(childComplexity int) int
		Power                 func(childComplexity int) int
		Quantity              func(childComplexity int) int
		ScryfallID            func(childComplexity int) int
		Subtypes              func(childComplexity int) int
		Supertypes            func(childComplexity int) int
		Tapped                func(childComplexity int) int
		Tcgid                 func(childComplexity int) int
		Text                  func(childComplexity int) int
		Toughness             func(childComplexity int) int
		Types                 func(childComplexity int) int
		UUID                  func(childComplexity int) int
	}

	Counter struct {
		Name  func(childComplexity int) int
		Value func(childComplexity int) int
	}

	Emblem struct {
		Name   func(childComplexity int) int
		Player func(childComplexity int) int
		Value  func(childComplexity int) int
	}

	Game struct {
		CreatedAt func(childComplexity int) int
		ID        func(childComplexity int) int
		PlayerIDs func(childComplexity int) int
		Rules     func(childComplexity int) int
		Turn      func(childComplexity int) int
	}

	Message struct {
		Channel   func(childComplexity int) int
		CreatedAt func(childComplexity int) int
		GameID    func(childComplexity int) int
		ID        func(childComplexity int) int
		Text      func(childComplexity int) int
		User      func(childComplexity int) int
	}

	Mutation struct {
		CreateGame       func(childComplexity int, input InputCreateGame) int
		JoinGame         func(childComplexity int, input *InputJoinGame) int
		Login            func(childComplexity int, username string, password string) int
		PostMessage      func(childComplexity int, user string, text string) int
		Signup           func(childComplexity int, username string, password string) int
		UpdateBoardState func(childComplexity int, input InputBoardState) int
		UpdateGame       func(childComplexity int, input InputGame) int
	}

	Query struct {
		Boardstates func(childComplexity int, gameID string, userID *string) int
		Card        func(childComplexity int, name string, id *string) int
		Cards       func(childComplexity int, list []string) int
		Games       func(childComplexity int, gameID *string) int
		Messages    func(childComplexity int) int
		Search      func(childComplexity int, name *string, colors []*string, colorIdentity []*string, keywords []*string) int
		Users       func(childComplexity int, userID *string) int
	}

	Rule struct {
		Name  func(childComplexity int) int
		Value func(childComplexity int) int
	}

	Subscription struct {
		BoardstateUpdated func(childComplexity int, observerID string, userID string) int
		GameUpdated       func(childComplexity int, gameID string, userID string) int
	}

	Turn struct {
		Number func(childComplexity int) int
		Phase  func(childComplexity int) int
		Player func(childComplexity int) int
	}

	User struct {
		ID       func(childComplexity int) int
		Password func(childComplexity int) int
		Token    func(childComplexity int) int
		Username func(childComplexity int) int
	}
}

type Conf

type Conf struct {
	RedisURL    string `envconfig:"REDIS_URL" default:"redis://localhost:6379"`
	PostgresURL string `envconfig:"DATABASE_URL" default:"postgres://edhgo:edhgodev@localhost:5432/edhgo?sslmode=disable"`
	DefaultPort int    `envconfig:"PORT" default:"8080"`
}

Conf takes configuration values and loads them from the environment into our struct.

type Config

type Config struct {
	Resolvers  ResolverRoot
	Directives DirectiveRoot
	Complexity ComplexityRoot
}

type Counter

type Counter struct {
	Name  string `json:"Name"`
	Value string `json:"Value"`
}

type DirectiveRoot

type DirectiveRoot struct {
	Deprecated func(ctx context.Context, obj interface{}, next graphql.Resolver, reason *string) (res interface{}, err error)
	Include    func(ctx context.Context, obj interface{}, next graphql.Resolver, ifArg bool) (res interface{}, err error)
	Skip       func(ctx context.Context, obj interface{}, next graphql.Resolver, ifArg bool) (res interface{}, err error)
}

type Emblem

type Emblem struct {
	Name   string `json:"Name"`
	Value  string `json:"Value"`
	Player *User  `json:"Player"`
}

type Event

type Event struct {
	Payload map[string]interface{}
}

Event represents a change to boardstate

func (*Event) Scan

func (e *Event) Scan(value interface{}) error

Scan fulfills the sql.Scanner interface. This method decodes a JSON encoded value into the struct fields.

func (Event) Value

func (e Event) Value() (driver.Value, error)

Make the Event struct implement the driver.Valuer interface. This method simply returns the JSON-encoded representation of the struct.

type EventLog

type EventLog interface {
	Add(ctx context.Context, event Event) error
}

EventLog declares an interface for an append-only Event log.

type FullBoardstate

type FullBoardstate struct {
	sync.Mutex
	// Game ID of the Boardstate in play
	GameID string
	// User ID of the Boardstate being observed
	UserID string
	// Observers keeps a map of UserID to BoardObservers
	Observers map[string]*BoardObserver
}

FullBoardstate binds a set of observers to a game ID and user ID

type FullGame

type FullGame struct {
	sync.Mutex

	GameID    string
	Observers map[string]*GameObserver
}

FullGame wraps a Game with Observers and Players so that we can access players boardstates with only a game and a player ID

type Game

type Game struct {
	ID        string    `json:"ID"`
	CreatedAt time.Time `json:"CreatedAt"`
	Rules     []*Rule   `json:"Rules"`
	Turn      *Turn     `json:"Turn"`
	PlayerIDs []*User   `json:"PlayerIDs"`
}

type GameObserver

type GameObserver struct {
	UserID  string
	Channel chan *Game
}

GameObserver binds a UserID to a Channel.

type GameState

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

func New

func New() *GameState

New returns an FSM with the default phase transitions assigned. * It does not currently have any concept of a Player or turn passing. That logic must be added later. It only loops through one player's turn phases as an exercise in FSM construction

func (*GameState) LockIn

func (gs *GameState) LockIn() error

func (*GameState) PassPriority

func (gs *GameState) PassPriority() error

type InputBoardState

type InputBoardState struct {
	User       *InputUser      `json:"User"`
	GameID     string          `json:"GameID"`
	Life       int             `json:"Life"`
	Decklist   *string         `json:"Decklist"`
	Commander  []*InputCard    `json:"Commander"`
	Library    []*InputCard    `json:"Library"`
	Graveyard  []*InputCard    `json:"Graveyard"`
	Exiled     []*InputCard    `json:"Exiled"`
	Field      []*InputCard    `json:"Field"`
	Hand       []*InputCard    `json:"Hand"`
	Revealed   []*InputCard    `json:"Revealed"`
	Controlled []*InputCard    `json:"Controlled"`
	Counters   []*InputCounter `json:"Counters"`
	Emblems    []*InputEmblem  `json:"Emblems"`
}

type InputCard

type InputCard struct {
	ID            *string         `json:"ID"`
	Name          string          `json:"Name"`
	Counters      []*InputCounter `json:"Counters"`
	Labels        []*InputLabel   `json:"Labels"`
	Tapped        *bool           `json:"Tapped"`
	Flipped       *bool           `json:"Flipped"`
	Quantity      *int            `json:"Quantity"`
	Colors        *string         `json:"Colors"`
	ColorIdentity *string         `json:"ColorIdentity"`
	Cmc           *string         `json:"CMC"`
	ManaCost      *string         `json:"ManaCost"`
	UUID          *string         `json:"UUID"`
	Power         *string         `json:"Power"`
	Toughness     *string         `json:"Toughness"`
	Types         *string         `json:"Types"`
	Subtypes      *string         `json:"Subtypes"`
	Supertypes    *string         `json:"Supertypes"`
	IsTextless    *string         `json:"IsTextless"`
	Text          *string         `json:"Text"`
	Tcgid         *string         `json:"TCGID"`
	ScryfallID    *string         `json:"ScryfallID"`
}

type InputCounter

type InputCounter struct {
	Card  *InputCard `json:"Card"`
	Name  string     `json:"Name"`
	Value string     `json:"Value"`
}

type InputCreateGame

type InputCreateGame struct {
	ID      string             `json:"ID"`
	Turn    *InputTurn         `json:"Turn"`
	Handle  *string            `json:"Handle"`
	Players []*InputBoardState `json:"Players"`
}

type InputDeck

type InputDeck struct {
	Name      *string  `json:"Name"`
	Commander []string `json:"Commander"`
	Cards     []string `json:"Cards"`
}

type InputEmblem

type InputEmblem struct {
	Name   string     `json:"Name"`
	Value  string     `json:"Value"`
	Player *InputUser `json:"Player"`
}

type InputGame

type InputGame struct {
	ID        string       `json:"ID"`
	Turn      *InputTurn   `json:"Turn"`
	CreatedAt *time.Time   `json:"CreatedAt"`
	Handle    *string      `json:"Handle"`
	PlayerIDs []*InputUser `json:"PlayerIDs"`
	Rules     []*InputRule `json:"Rules"`
}

type InputJoinGame

type InputJoinGame struct {
	ID         string           `json:"ID"`
	User       *InputUser       `json:"User"`
	Handle     *string          `json:"Handle"`
	Decklist   *string          `json:"Decklist"`
	BoardState *InputBoardState `json:"BoardState"`
}

type InputLabel

type InputLabel struct {
	Name       string `json:"Name"`
	Value      string `json:"Value"`
	AssignedBy string `json:"AssignedBy"`
}

type InputRule

type InputRule struct {
	Name  string `json:"Name"`
	Value string `json:"Value"`
}

type InputSignup

type InputSignup struct {
	Username string `json:"Username"`
	Email    string `json:"Email"`
	Password string `json:"Password"`
}

type InputTurn

type InputTurn struct {
	Player string `json:"Player"`
	Phase  string `json:"Phase"`
	Number int    `json:"Number"`
}

type InputUser

type InputUser struct {
	Username string  `json:"Username"`
	ID       *string `json:"ID"`
}

type KeyValue

type KeyValue interface {
	Set(key string, value interface{}) error
	Get(key string, dest interface{}) error
}

Persistence defines the persistence interface for the server. This interface stores Game and BoardStates for realtime interaction.

type Message

type Message struct {
	ID        string    `json:"ID"`
	User      string    `json:"User"`
	CreatedAt time.Time `json:"CreatedAt"`
	Text      string    `json:"Text"`
	GameID    string    `json:"GameID"`
	Channel   *string   `json:"Channel"`
}

type MutationResolver

type MutationResolver interface {
	Signup(ctx context.Context, username string, password string) (*User, error)
	Login(ctx context.Context, username string, password string) (*User, error)
	PostMessage(ctx context.Context, user string, text string) (*Message, error)
	CreateGame(ctx context.Context, input InputCreateGame) (*Game, error)
	JoinGame(ctx context.Context, input *InputJoinGame) (*Game, error)
	UpdateGame(ctx context.Context, input InputGame) (*Game, error)
	UpdateBoardState(ctx context.Context, input InputBoardState) (*BoardState, error)
}

type PGCard

type PGCard struct {
	Id                     string
	Artist                 string
	Asciiname              string
	Availability           string
	Bordercolor            string
	CardKingdomId          string
	ColorIdentity          string
	Colors                 string
	ConvertedManaCost      string
	FaceConvertedManaCost  string
	FaceManaValue          string
	FlavorName             string
	FlavorText             string
	Keywords               string
	MtgJsonv4Id            string
	Name                   string
	Number                 string
	OriginalText           string
	OriginalType           string
	Power                  string
	ScryfallID             string
	ScryfallIllustrationId string
	ScryfallOracleId       string
	SetCode                string
	Side                   string
	Subtypes               string
	Supertypes             string
	TcgplayerProductId     string
	Text                   string
	Toughness              string
	Type                   string
	Types                  string
	Uuid                   string
}

PGCard is a model used to reflect our internal Postgres model of a card. We must serialize it to a *Card type provided by our GraphQL model before returning it.

type QueryResolver

type QueryResolver interface {
	Messages(ctx context.Context) ([]*Message, error)
	Users(ctx context.Context, userID *string) ([]string, error)
	Games(ctx context.Context, gameID *string) ([]*Game, error)
	Boardstates(ctx context.Context, gameID string, userID *string) ([]*BoardState, error)
	Card(ctx context.Context, name string, id *string) (*Card, error)
	Cards(ctx context.Context, list []string) ([]*Card, error)
	Search(ctx context.Context, name *string, colors []*string, colorIdentity []*string, keywords []*string) ([]*Card, error)
}

type ResolverRoot

type ResolverRoot interface {
	Mutation() MutationResolver
	Query() QueryResolver
	Subscription() SubscriptionResolver
}

type Rule

type Rule struct {
	Name  string `json:"Name"`
	Value string `json:"Value"`
}

type Shuffler

type Shuffler func(deck []*Card) ([]*Card, error)

Shuffler type defines the interface for a given Shuffle function to fulfill.

type SubscriptionResolver

type SubscriptionResolver interface {
	GameUpdated(ctx context.Context, gameID string, userID string) (<-chan *Game, error)
	BoardstateUpdated(ctx context.Context, observerID string, userID string) (<-chan *BoardState, error)
}

type Turn

type Turn struct {
	Player string `json:"Player"`
	Phase  string `json:"Phase"`
	Number int    `json:"Number"`
}

type User

type User struct {
	ID       string  `json:"ID"`
	Username string  `json:"Username"`
	Password *string `json:"Password"`
	Token    *string `json:"Token"`
}

Jump to

Keyboard shortcuts

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