animusmagic

package
v0.0.0-...-231e43a Latest Latest
Warning

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

Go to latest
Published: May 15, 2024 License: AGPL-3.0 Imports: 16 Imported by: 0

Documentation

Overview

Animus Magic is the internal redis IPC system for internal communications between the bot and the server

This package defines all possible responses to an action

Index

Constants

View Source
const (
	WildcardClusterID = 0xFFFF // top means wildcard/all clusters
)

Variables

View Source
var ErrInvalidPayload = errors.New("request validation error: invalid payload")
View Source
var ErrInvalidTarget = errors.New("request validation error: message target and payload.To mismatch")
View Source
var ErrNilClusterID = errors.New("request validation error: nil cluster id")
View Source
var ErrNilExpectedResponseCount = errors.New("request validation error: nil expected response count")
View Source
var ErrNilMessage = errors.New("request validation error: nil message")
View Source
var ErrNilRequestData = errors.New("request validation error: nil request data")
View Source
var ErrOpError = errors.New("request validation error: op is OpError")

Functions

func DeserializeData

func DeserializeData[T any](data []byte, d *T) error

Helper function to deserialize data from the correct/current format

func NewCommandId

func NewCommandId() string

Helper function to create a new command id

func ParseClientRequest

func ParseClientRequest[T AnimusMessage](c *ClientRequest) (*T, error)

func SerializeData

func SerializeData[T any](data T) ([]byte, error)

Helper function to serialize data to the correct/current format

Types

type AnimusErrorResponse

type AnimusErrorResponse struct {
	Message string `json:"message"`
	Context string `json:"context"`

	// Client internal
	ClientDebugInfo map[string]any `json:"client_debug_info,omitempty"`
}

type AnimusMagicClient

type AnimusMagicClient struct {
	// Target / the identity the client is for
	Identify AnimusTarget

	// The cluster id
	ClusterID uint16

	// On request function, if set, will be called upon recieving op of type OpRequest
	OnRequest func(*ClientRequest) (AnimusResponse, error)

	// On response function, if set, will be called upon recieving op of type OpResponse
	OnResponse func(*ClientResponse) error

	// Middleware function, will be called regardless of the op
	//
	// If bool is false, the message will be ignored/dropped for further processing
	OnMiddleware func(*AnimusMessageMetadata, []byte) (bool, error)

	// Allow all requests
	AllowAll bool

	// Set of notifiers
	Notify syncmap.Map[string, *NotifyWrapper]

	// The redis channel to use
	Channel string
	// contains filtered or unexported fields
}

func New

func New(channel string, identity AnimusTarget, clusterId uint16) *AnimusMagicClient

New returns a new AnimusMagicClient

func (*AnimusMagicClient) CloseNotifier

func (c *AnimusMagicClient) CloseNotifier(commandId string)

CloseNotifier closes the notifier for the given command id

func (*AnimusMagicClient) CreateNotifier

func (c *AnimusMagicClient) CreateNotifier(commandId string, expectedResponseCount uint32) chan *ClientResponse

CreateNotifier adds a notifier to the map and returns the channel

This channel will receive the response for the given command id

func (*AnimusMagicClient) CreatePayload

func (c *AnimusMagicClient) CreatePayload(
	from, to AnimusTarget,
	clusterIdFrom uint16,
	clusterIdTo uint16,
	op AnimusOp,
	commandId string,
	data any,
) ([]byte, error)

CreatePayload creates a payload for the given command id and message

func (*AnimusMagicClient) Filter

func (c *AnimusMagicClient) Filter(meta *AnimusMessageMetadata) bool

Filter filters a message

func (*AnimusMagicClient) GatherResponses

func (c *AnimusMagicClient) GatherResponses(
	ctx context.Context,
	opts *RequestOptions,
	notify chan *ClientResponse,
) (r []*ClientResponse, err error)

GatherResponses gathers responses from the given notifier

This waits for the expected number of responses or until the context is done

func (*AnimusMagicClient) GetPayloadMeta

func (c *AnimusMagicClient) GetPayloadMeta(payload []byte) (*AnimusMessageMetadata, error)

GetPayloadMeta parses the payload metadata from a message

func (*AnimusMagicClient) Handle

func (c *AnimusMagicClient) Handle(ctx context.Context, redis rueidis.Client, l *zap.Logger, meta *AnimusMessageMetadata, payload []byte)

Handle handles a message

func (*AnimusMagicClient) Listen

func (c *AnimusMagicClient) Listen(ctx context.Context, redis rueidis.Client, l *zap.Logger) error

Listen starts listening for messages from redis and restarts the listener if it dies

func (*AnimusMagicClient) ListenOnce

func (c *AnimusMagicClient) ListenOnce(ctx context.Context, r rueidis.Client, l *zap.Logger) error

ListenOnce starts listening for messages from redis

This is *blocking* and should be run in a goroutine

func (*AnimusMagicClient) Publish

func (c *AnimusMagicClient) Publish(ctx context.Context, redis rueidis.Client, payload []byte) error

func (*AnimusMagicClient) Request

func (c *AnimusMagicClient) Request(
	ctx context.Context,
	redis rueidis.Client,
	msg AnimusMessage,
	data *RequestOptions,
) ([]*ClientResponse, error)

Request sends a request to the given cluster id and waits for a response

type AnimusMessage

type AnimusMessage interface {
	Message()             // Marker method
	Target() AnimusTarget // Who the message is for
}

type AnimusMessageMetadata

type AnimusMessageMetadata struct {
	From          AnimusTarget
	To            AnimusTarget
	ClusterIDFrom uint16
	ClusterIDTo   uint16
	Op            AnimusOp
	CommandID     string
	PayloadOffset uint
}

type AnimusOp

type AnimusOp byte
const (
	OpRequest  AnimusOp = 0x0
	OpResponse AnimusOp = 0x1
	OpError    AnimusOp = 0x2
	OpProbe    AnimusOp = 0x3
)

func ByteToAnimusOp

func ByteToAnimusOp(b uint8) (AnimusOp, bool)

func StringToAnimusOp

func StringToAnimusOp(s string) (AnimusOp, bool)

func (AnimusOp) String

func (a AnimusOp) String() string

func (*AnimusOp) UnmarshalJSON

func (a *AnimusOp) UnmarshalJSON(b []byte) error

UnmarshalJSON implements the json.Unmarshaler interface for an AnimusOp

func (*AnimusOp) UnmarshalYAML

func (a *AnimusOp) UnmarshalYAML(value *yaml.Node) error

YAML is same as JSON

type AnimusResponse

type AnimusResponse interface {
	Response()            // Marker method
	Target() AnimusTarget // Who can create a response should be from
}

type AnimusTarget

type AnimusTarget byte
const (
	AnimusTargetBot       AnimusTarget = 0x0
	AnimusTargetJobserver AnimusTarget = 0x1
	AnimusTargetWebserver AnimusTarget = 0x2
	AnimusTargetInfra     AnimusTarget = 0x3
	AnimusTargetWildcard  AnimusTarget = 0xFF
)

func ByteToAnimusTarget

func ByteToAnimusTarget(b uint8) (AnimusTarget, bool)

func StringToAnimusTarget

func StringToAnimusTarget(s string) (AnimusTarget, bool)

func (AnimusTarget) String

func (a AnimusTarget) String() string

func (*AnimusTarget) UnmarshalJSON

func (a *AnimusTarget) UnmarshalJSON(b []byte) error

UnmarshalJSON implements the json.Unmarshaler interface for an AnimusTarget

func (*AnimusTarget) UnmarshalYAML

func (a *AnimusTarget) UnmarshalYAML(value *yaml.Node) error

YAML is same as JSON

type BotAnimusMessage

type BotAnimusMessage struct {
	Modules     *struct{} `json:"Modules,omitempty"`
	GuildsExist *struct {
		Guilds []string `json:"guilds"`
	} `json:"GuildsExist,omitempty"`
	BaseGuildUserInfo *struct {
		GuildID string `json:"guild_id"`
		UserID  string `json:"user_id"`
	} `json:"BaseGuildUserInfo,omitempty"`
	CheckCommandPermission *struct {
		GuildID             string                         `json:"guild_id"`
		UserID              string                         `json:"user_id"`
		Command             string                         `json:"command"`
		CheckCommandOptions silverpelt.CheckCommandOptions `json:"opts"`
	} `json:"CheckCommandPermission,omitempty"`
	ExecutePerModuleFunction *struct {
		Module  string         `json:"module"`
		Toggle  string         `json:"toggle"`
		Options map[string]any `json:"options,omitempty"`
	} `json:"ExecutePerModuleFunction,omitempty"`
	GetSerenityPermissionList *struct{} `json:"GetSerenityPermissionList,omitempty"`
}

func (BotAnimusMessage) Message

func (b BotAnimusMessage) Message()

func (BotAnimusMessage) Target

func (b BotAnimusMessage) Target() AnimusTarget

type BotAnimusResponse

type BotAnimusResponse struct {
	OK *struct {
		Message string `json:"message"`
	} `json:"OK,omitempty"`
	Modules *struct {
		Modules ClusterModules `json:"modules"`
	} `json:"Modules,omitempty"`

	GuildsExist *struct {
		GuildsExist []uint8 `json:"guilds_exist"`
	}

	BaseGuildUserInfo *types.UserGuildBaseData

	/// Returns the response of a command permission check
	CheckCommandPermission *struct {
		PermRes silverpelt.PermissionResult `json:"perm_res"`
		IsOk    bool                        `json:"is_ok"`
	}
	GetSerenityPermissionList *struct {
		Permissions map[string]uint64 `json:"perms"`
	} `json:"GetSerenityPermissionList,omitempty"`
}

func (BotAnimusResponse) Response

func (b BotAnimusResponse) Response()

func (BotAnimusResponse) Target

func (b BotAnimusResponse) Target() AnimusTarget

type ClientRequest

type ClientRequest struct {
	Meta *AnimusMessageMetadata

	// The raw payload
	RawPayload []byte
}

A ClientResponse contains the request from animus magic

type ClientResponse

type ClientResponse struct {
	Meta *AnimusMessageMetadata

	// The raw payload
	RawPayload []byte
}

A ClientResponse contains the response from animus magic

type ClusterModules

type ClusterModules = []silverpelt.CanonicalModule

type JobserverMessage

type JobserverMessage struct {
	// spawns a task and executes it if the execute argument is set.
	// If you already have both a task and a task create response, consider execute_task
	SpawnTask *struct {
		Name    string                 `json:"name"`
		Data    map[string]interface{} `json:"data"`
		Create  bool                   `json:"create"`
		Execute bool                   `json:"execute"`

		// If create is false, then task id must be set
		TaskID string `json:"task_id"`

		// The User ID who initiated the action
		UserID string `json:"user_id"`
	} `json:"SpawnTask,omitempty"`
}

func (JobserverMessage) Message

func (b JobserverMessage) Message()

func (JobserverMessage) Target

func (b JobserverMessage) Target() AnimusTarget

type JobserverResponse

type JobserverResponse struct {
	SpawnTask *struct {
		TaskID string `json:"task_id"`
	} `json:"SpawnTask,omitempty"`
}

func (JobserverResponse) Response

func (b JobserverResponse) Response()

func (JobserverResponse) Target

func (b JobserverResponse) Target() AnimusTarget

type NotifyWrapper

type NotifyWrapper struct {
	Chan          chan *ClientResponse
	ExpectedCount uint32
	ResponseCount atomic.Uint32
}

type ParsedClientResponse

type ParsedClientResponse[T AnimusResponse] struct {
	Err        *AnimusErrorResponse
	Resp       *T
	ClientResp *ClientResponse
}

Parsed client response, contains the response and the error if any

func ParseClientResponse

func ParseClientResponse[T AnimusResponse](
	cr *ClientResponse,
) (*ParsedClientResponse[T], error)

func ParseClientResponses

func ParseClientResponses[T AnimusResponse](
	cr []*ClientResponse,
) ([]*ParsedClientResponse[T], error)

type RequestOptions

type RequestOptions struct {
	ClusterID             *uint16      // the cluster id to send to, must be set, also ExpectedResponseCount must be set if wildcard
	ExpectedResponseCount uint32       // must be set if wildcard. this is the number of responses expected
	CommandID             string       // if unset, will be randomly generated
	To                    AnimusTarget // must be set
	Op                    AnimusOp     // must be set
	IgnoreOpError         bool         // if true, will ignore OpError responses
}

RequestOptions stores the options for a request

func (*RequestOptions) Parse

func (o *RequestOptions) Parse() error

Parse parses a RequestOptions

Jump to

Keyboard shortcuts

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