animusmagic

package
v0.0.0-...-c1401b0 Latest Latest
Warning

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

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

Documentation

Overview

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

Format of payloads: <target [from]: u8><target [to]: u8><cluster id from: u16><cluster id to: u16><op: 8 bits><command id: alphanumeric string>/<cbor payload>

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 / who the client is for
	From 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
}

func New

func New(channel string, from 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) 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) 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) RawRequest

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

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

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

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

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"`
	TogglePerModuleCache *struct {
		Module  string         `json:"module"`
		Toggle  string         `json:"toggle"`
		Options map[string]any `json:"options,omitempty"`
	} `json:"TogglePerModuleCache,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
}

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 // if unset, is set to AnimusTargetBot
	Op                    AnimusOp     // if unset is OpRequest
	IgnoreOpError         bool         // if true, will ignore OpError responses
}

RequestOptions stores the data 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