eventbus

package
v0.0.0-...-5baff64 Latest Latest
Warning

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

Go to latest
Published: Apr 4, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DefaultPublishBufferSize = 1000
	DefaultHistorySize       = 100
)

Default configuration values for LocalEventBus

View Source
const (
	ShutdownPriorityEventBus = 100 // High priority - shut down event bus first
	ShutdownPriorityKafka    = 90  // High priority - flush Kafka messages
	ShutdownPriorityRedis    = 80  // Medium-high priority
	ShutdownPriorityAPI      = 50  // Medium priority - stop accepting new requests
	ShutdownPriorityStorage  = 10  // Low priority - close storage last
	ShutdownPriorityCleanup  = 0   // Lowest priority - final cleanup
)

Common shutdown priorities

Variables

View Source
var (
	// ErrPublishFailed indicates that publishing an event failed
	ErrPublishFailed = errors.New("failed to publish event: channel full or bus stopped")

	// ErrNotConnected indicates the distributed event bus is not connected
	ErrNotConnected = errors.New("event bus is not connected")

	// ErrAlreadyConnected indicates the event bus is already connected
	ErrAlreadyConnected = errors.New("event bus is already connected")

	// ErrConnectionFailed indicates a connection failure to the distributed backend
	ErrConnectionFailed = errors.New("failed to connect to event bus backend")

	// ErrSerializationFailed indicates event serialization failure
	ErrSerializationFailed = errors.New("failed to serialize event")

	// ErrDeserializationFailed indicates event deserialization failure
	ErrDeserializationFailed = errors.New("failed to deserialize event")

	// ErrInvalidEventType indicates an unknown or invalid event type
	ErrInvalidEventType = errors.New("invalid event type")

	// ErrSubscriptionNotFound indicates the subscription was not found
	ErrSubscriptionNotFound = errors.New("subscription not found")

	// ErrInvalidConfiguration indicates invalid event bus configuration
	ErrInvalidConfiguration = errors.New("invalid event bus configuration")

	// ErrTimeout indicates an operation timed out
	ErrTimeout = errors.New("operation timed out")

	// ErrShutdown indicates the event bus is shutting down
	ErrShutdown = errors.New("event bus is shutting down")

	// ErrChannelClosed indicates the channel was closed unexpectedly
	ErrChannelClosed = errors.New("channel was closed")
)

Common errors for event bus operations

Functions

This section is empty.

Types

type DistributedEventBus

type DistributedEventBus interface {
	EventBus

	// Connect establishes connection to the distributed backend
	Connect(ctx context.Context) error

	// Disconnect closes the connection to the distributed backend
	Disconnect(ctx context.Context) error

	// IsConnected returns true if connected to the distributed backend
	IsConnected() bool

	// NodeID returns the unique identifier for this node
	NodeID() string
}

DistributedEventBus extends EventBus with distributed-specific functionality

type EventBus

type EventBus interface {
	Publisher
	Subscriber

	// Run starts the event bus main loop
	// This should be called in a goroutine
	Run()

	// Stop gracefully stops the event bus
	Stop()

	// SubscriberCount returns the current number of active subscribers
	SubscriberCount() int

	// Stats returns the current statistics
	// Returns (totalEvents, totalDeliveries, droppedEvents)
	Stats() (uint64, uint64, uint64)

	// SetMetrics enables Prometheus metrics for the EventBus
	SetMetrics(metrics *events.Metrics)

	// GetSubscriberInfo returns information about a specific subscriber
	GetSubscriberInfo(id events.SubscriptionID) *events.SubscriberInfo

	// GetAllSubscriberInfo returns information about all subscribers
	GetAllSubscriberInfo() []events.SubscriberInfo

	// Healthy returns true if the event bus is operational
	Healthy() bool

	// Type returns the type of event bus implementation
	Type() EventBusType
}

EventBus defines the complete interface for an event bus implementation

func NewEventBus

func NewEventBus(cfg *config.Config) (EventBus, error)

NewEventBus is a convenience function that creates an EventBus based on configuration

func NewEventBusWithContext

func NewEventBusWithContext(ctx context.Context, cfg *config.Config) (EventBus, error)

NewEventBusWithContext creates an EventBus with the given context

type EventBusStats

type EventBusStats struct {
	// TotalEventsPublished is the total number of events published
	TotalEventsPublished uint64 `json:"total_events_published"`

	// TotalEventsDelivered is the total number of events delivered to subscribers
	TotalEventsDelivered uint64 `json:"total_events_delivered"`

	// TotalEventsDropped is the number of events dropped due to full channels
	TotalEventsDropped uint64 `json:"total_events_dropped"`

	// ActiveSubscribers is the current number of active subscribers
	ActiveSubscribers int `json:"active_subscribers"`

	// PublishChannelUtilization is the current utilization of the publish channel (0-100%)
	PublishChannelUtilization float64 `json:"publish_channel_utilization"`

	// AverageDeliveryLatency is the average time to deliver an event
	AverageDeliveryLatency time.Duration `json:"average_delivery_latency"`

	// EventsByType tracks events published by type
	EventsByType map[events.EventType]uint64 `json:"events_by_type"`

	// LastEventTime is when the last event was published
	LastEventTime time.Time `json:"last_event_time"`

	// Uptime is how long the event bus has been running
	Uptime time.Duration `json:"uptime"`
}

EventBusStats provides detailed statistics about event bus operations

type EventBusType

type EventBusType string

EventBusType represents the type of event bus implementation

const (
	// EventBusTypeLocal represents an in-process local event bus
	EventBusTypeLocal EventBusType = "local"

	// EventBusTypeRedis represents a Redis Pub/Sub event bus
	EventBusTypeRedis EventBusType = "redis"

	// EventBusTypeKafka represents a Kafka event bus
	EventBusTypeKafka EventBusType = "kafka"

	// EventBusTypeHybrid represents a hybrid event bus (local + distributed)
	EventBusTypeHybrid EventBusType = "hybrid"
)

type EventSerializer

type EventSerializer interface {
	// Serialize converts an event to bytes
	Serialize(event events.Event) ([]byte, error)

	// Deserialize converts bytes back to an event
	Deserialize(data []byte) (events.Event, error)

	// ContentType returns the MIME type of the serialized format
	ContentType() string
}

EventSerializer defines the interface for serializing/deserializing events

type Factory

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

Factory creates EventBus instances based on configuration

func NewFactory

func NewFactory(cfg *config.Config) *Factory

NewFactory creates a new EventBus factory

func (*Factory) Create

func (f *Factory) Create() (EventBus, error)

Create creates an EventBus based on the configuration

func (*Factory) CreateWithContext

func (f *Factory) CreateWithContext(ctx context.Context) (EventBus, error)

CreateWithContext creates an EventBus with the given context

type HealthStatus

type HealthStatus struct {
	// Status is the overall status: "healthy", "degraded", "unhealthy"
	Status string `json:"status"`

	// Message provides additional context about the status
	Message string `json:"message,omitempty"`

	// LastCheck is when the health was last checked
	LastCheck time.Time `json:"last_check"`

	// Details contains component-specific health details
	Details map[string]interface{} `json:"details,omitempty"`
}

HealthStatus represents the health status of an event bus component

type JSONSerializer

type JSONSerializer struct{}

JSONSerializer implements EventSerializer using JSON encoding

func NewJSONSerializer

func NewJSONSerializer() *JSONSerializer

NewJSONSerializer creates a new JSON serializer

func (*JSONSerializer) ContentType

func (s *JSONSerializer) ContentType() string

ContentType returns the MIME type for JSON

func (*JSONSerializer) Deserialize

func (s *JSONSerializer) Deserialize(data []byte) (events.Event, error)

Deserialize converts JSON bytes back to an event

func (*JSONSerializer) Serialize

func (s *JSONSerializer) Serialize(event events.Event) ([]byte, error)

Serialize converts an event to JSON bytes

type KafkaEventBus

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

KafkaEventBus implements EventBus using Kafka for distributed event broadcasting. It follows the same adapter pattern as RedisEventBus: a local bus handles subscriptions and delivery, while Kafka provides cross-node event broadcasting.

func NewKafkaEventBus

func NewKafkaEventBus(cfg config.EventBusKafkaConfig, nodeID string, opts ...Option) (*KafkaEventBus, error)

NewKafkaEventBus creates a new Kafka EventBus

func (*KafkaEventBus) Connect

func (eb *KafkaEventBus) Connect(ctx context.Context) error

Connect establishes connection to Kafka (producer + consumer)

func (*KafkaEventBus) Disconnect

func (eb *KafkaEventBus) Disconnect(ctx context.Context) error

Disconnect closes the connection to Kafka

func (*KafkaEventBus) GetAllSubscriberInfo

func (eb *KafkaEventBus) GetAllSubscriberInfo() []events.SubscriberInfo

GetAllSubscriberInfo returns information about all subscribers

func (*KafkaEventBus) GetHealthStatus

func (eb *KafkaEventBus) GetHealthStatus() HealthStatus

GetHealthStatus returns detailed health status

func (*KafkaEventBus) GetSubscriberInfo

func (eb *KafkaEventBus) GetSubscriberInfo(id events.SubscriptionID) *events.SubscriberInfo

GetSubscriberInfo returns information about a specific subscriber

func (*KafkaEventBus) Healthy

func (eb *KafkaEventBus) Healthy() bool

Healthy returns true if the event bus is operational

func (*KafkaEventBus) IsConnected

func (eb *KafkaEventBus) IsConnected() bool

IsConnected returns true if connected to Kafka

func (*KafkaEventBus) NodeID

func (eb *KafkaEventBus) NodeID() string

NodeID returns the unique identifier for this node

func (*KafkaEventBus) Producer

func (eb *KafkaEventBus) Producer() *KafkaProducer

Producer returns the underlying KafkaProducer for health checks

func (*KafkaEventBus) Publish

func (eb *KafkaEventBus) Publish(event events.Event) bool

Publish publishes an event locally and to Kafka

func (*KafkaEventBus) PublishWithContext

func (eb *KafkaEventBus) PublishWithContext(ctx context.Context, event events.Event) error

PublishWithContext publishes an event with context

func (*KafkaEventBus) Run

func (eb *KafkaEventBus) Run()

Run starts the event bus main loop

func (*KafkaEventBus) SetMetrics

func (eb *KafkaEventBus) SetMetrics(metrics *events.Metrics)

SetMetrics enables Prometheus metrics for the EventBus

func (*KafkaEventBus) Stats

func (eb *KafkaEventBus) Stats() (uint64, uint64, uint64)

Stats returns the current statistics

func (*KafkaEventBus) Stop

func (eb *KafkaEventBus) Stop()

Stop gracefully stops the event bus

func (*KafkaEventBus) Subscribe

func (eb *KafkaEventBus) Subscribe(
	id events.SubscriptionID,
	eventTypes []events.EventType,
	filter *events.Filter,
	channelSize int,
) *events.Subscription

Subscribe creates a new subscription for the given event types

func (*KafkaEventBus) SubscribeWithOptions

func (eb *KafkaEventBus) SubscribeWithOptions(
	id events.SubscriptionID,
	eventTypes []events.EventType,
	filter *events.Filter,
	opts events.SubscribeOptions,
) *events.Subscription

SubscribeWithOptions creates a new subscription with configurable options

func (*KafkaEventBus) SubscriberCount

func (eb *KafkaEventBus) SubscriberCount() int

SubscriberCount returns the current number of active subscribers

func (*KafkaEventBus) Type

func (eb *KafkaEventBus) Type() EventBusType

Type returns the type of event bus implementation

func (*KafkaEventBus) Unsubscribe

func (eb *KafkaEventBus) Unsubscribe(id events.SubscriptionID)

Unsubscribe removes a subscription

type KafkaProducer

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

KafkaProducer handles event streaming to Kafka

func NewKafkaProducer

func NewKafkaProducer(cfg config.EventBusKafkaConfig, nodeID string) (*KafkaProducer, error)

NewKafkaProducer creates a new Kafka producer

func (*KafkaProducer) Connect

func (kp *KafkaProducer) Connect(ctx context.Context) error

Connect establishes connection to Kafka

func (*KafkaProducer) Disconnect

func (kp *KafkaProducer) Disconnect(ctx context.Context) error

Disconnect closes the connection to Kafka

func (*KafkaProducer) GetHealthStatus

func (kp *KafkaProducer) GetHealthStatus() HealthStatus

GetHealthStatus returns the health status of the producer

func (*KafkaProducer) IsConnected

func (kp *KafkaProducer) IsConnected() bool

IsConnected returns true if connected to Kafka

func (*KafkaProducer) Stats

func (kp *KafkaProducer) Stats() KafkaProducerStats

Stats returns producer statistics

func (*KafkaProducer) Stop

func (kp *KafkaProducer) Stop()

Stop gracefully stops the producer

func (*KafkaProducer) WriteEvent

func (kp *KafkaProducer) WriteEvent(ctx context.Context, event events.Event) error

WriteEvent writes an event to Kafka

func (*KafkaProducer) WriteEventAsync

func (kp *KafkaProducer) WriteEventAsync(event events.Event)

WriteEventAsync writes an event to Kafka asynchronously

type KafkaProducerStats

type KafkaProducerStats struct {
	MessagesWritten uint64        `json:"messages_written"`
	BytesWritten    uint64        `json:"bytes_written"`
	Errors          uint64        `json:"errors"`
	Connected       bool          `json:"connected"`
	Uptime          time.Duration `json:"uptime"`
}

KafkaProducerStats contains producer statistics

type LocalEventBus

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

LocalEventBus wraps the existing events.EventBus to implement the EventBus interface This provides backward compatibility while enabling future distributed implementations

func CreateDefaultLocalEventBus

func CreateDefaultLocalEventBus() *LocalEventBus

CreateDefaultLocalEventBus creates a local event bus with default settings

func CreateLocalEventBus

func CreateLocalEventBus(publishBufferSize, historySize int) *LocalEventBus

CreateLocalEventBus is a convenience function for creating a local event bus

func NewLocalEventBus

func NewLocalEventBus() *LocalEventBus

NewLocalEventBus creates a new local in-process event bus with default settings

func NewLocalEventBusWithConfig

func NewLocalEventBusWithConfig(publishBufferSize, historySize int) *LocalEventBus

NewLocalEventBusWithConfig creates a new local event bus with custom configuration

func NewLocalEventBusWithOptions

func NewLocalEventBusWithOptions(opts ...Option) *LocalEventBus

NewLocalEventBusWithOptions creates a new local event bus with functional options

func (*LocalEventBus) GetAllSubscriberInfo

func (eb *LocalEventBus) GetAllSubscriberInfo() []events.SubscriberInfo

GetAllSubscriberInfo returns information about all subscribers

func (*LocalEventBus) GetDetailedStats

func (eb *LocalEventBus) GetDetailedStats() EventBusStats

GetDetailedStats returns detailed statistics about the event bus

func (*LocalEventBus) GetHealthStatus

func (eb *LocalEventBus) GetHealthStatus() HealthStatus

GetHealthStatus returns the health status of the event bus

func (*LocalEventBus) GetSubscriberInfo

func (eb *LocalEventBus) GetSubscriberInfo(id events.SubscriptionID) *events.SubscriberInfo

GetSubscriberInfo returns information about a specific subscriber

func (*LocalEventBus) Healthy

func (eb *LocalEventBus) Healthy() bool

Healthy returns true if the event bus is operational

func (*LocalEventBus) Publish

func (eb *LocalEventBus) Publish(event events.Event) bool

Publish publishes an event to all interested subscribers

func (*LocalEventBus) PublishWithContext

func (eb *LocalEventBus) PublishWithContext(ctx context.Context, event events.Event) error

PublishWithContext publishes an event with context for cancellation

func (*LocalEventBus) Run

func (eb *LocalEventBus) Run()

Run starts the event bus main loop

func (*LocalEventBus) SetHistorySize

func (eb *LocalEventBus) SetHistorySize(_ int)

SetHistorySize is a no-op for local event bus (history size set at creation) This method exists to satisfy the Option pattern

func (*LocalEventBus) SetMetrics

func (eb *LocalEventBus) SetMetrics(metrics *events.Metrics)

SetMetrics enables Prometheus metrics for the EventBus

func (*LocalEventBus) SetPublishBufferSize

func (eb *LocalEventBus) SetPublishBufferSize(_ int)

SetPublishBufferSize is a no-op for local event bus (buffer size set at creation) This method exists to satisfy the Option pattern

func (*LocalEventBus) Stats

func (eb *LocalEventBus) Stats() (uint64, uint64, uint64)

Stats returns the current statistics

func (*LocalEventBus) Stop

func (eb *LocalEventBus) Stop()

Stop gracefully stops the event bus

func (*LocalEventBus) Subscribe

func (eb *LocalEventBus) Subscribe(
	id events.SubscriptionID,
	eventTypes []events.EventType,
	filter *events.Filter,
	channelSize int,
) *events.Subscription

Subscribe creates a new subscription for the given event types

func (*LocalEventBus) SubscribeWithOptions

func (eb *LocalEventBus) SubscribeWithOptions(
	id events.SubscriptionID,
	eventTypes []events.EventType,
	filter *events.Filter,
	opts events.SubscribeOptions,
) *events.Subscription

SubscribeWithOptions creates a new subscription with configurable options

func (*LocalEventBus) SubscriberCount

func (eb *LocalEventBus) SubscriberCount() int

SubscriberCount returns the current number of active subscribers

func (*LocalEventBus) Type

func (eb *LocalEventBus) Type() EventBusType

Type returns the type of event bus implementation

func (*LocalEventBus) UnderlyingBus

func (eb *LocalEventBus) UnderlyingBus() *events.EventBus

UnderlyingBus returns the underlying events.EventBus for backward compatibility This method should only be used during migration and will be deprecated

func (*LocalEventBus) Unsubscribe

func (eb *LocalEventBus) Unsubscribe(id events.SubscriptionID)

Unsubscribe removes a subscription

type MultiComponentShutdown

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

MultiComponentShutdown handles shutdown of multiple components with ordering

func NewMultiComponentShutdown

func NewMultiComponentShutdown(timeout time.Duration) *MultiComponentShutdown

NewMultiComponentShutdown creates a new multi-component shutdown handler

func (*MultiComponentShutdown) RegisterHook

func (mcs *MultiComponentShutdown) RegisterHook(name string, priority int, hook ShutdownHook)

RegisterHook adds a shutdown hook with a priority Higher priority hooks are executed first

func (*MultiComponentShutdown) Shutdown

func (mcs *MultiComponentShutdown) Shutdown(ctx context.Context) error

Shutdown executes all shutdown hooks in priority order

type Option

type Option func(interface{})

Option defines a functional option for configuring event bus implementations

func WithHistorySize

func WithHistorySize(size int) Option

WithHistorySize sets the event history size for replay

func WithMetrics

func WithMetrics(metrics *events.Metrics) Option

WithMetrics enables Prometheus metrics collection

func WithPublishBufferSize

func WithPublishBufferSize(size int) Option

WithPublishBufferSize sets the publish buffer size

type Publisher

type Publisher interface {
	// Publish publishes an event to all interested subscribers
	// Returns true if the event was successfully queued for publishing
	Publish(event events.Event) bool

	// PublishWithContext publishes an event with context for cancellation
	PublishWithContext(ctx context.Context, event events.Event) error
}

Publisher defines the interface for publishing events

type RedisEventBus

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

RedisEventBus implements EventBus using Redis Pub/Sub for distributed event broadcasting

func NewRedisEventBus

func NewRedisEventBus(cfg config.EventBusRedisConfig, nodeID string, opts ...Option) (*RedisEventBus, error)

NewRedisEventBus creates a new Redis EventBus

func (*RedisEventBus) Connect

func (eb *RedisEventBus) Connect(ctx context.Context) error

Connect establishes connection to Redis

func (*RedisEventBus) Disconnect

func (eb *RedisEventBus) Disconnect(ctx context.Context) error

Disconnect closes the connection to Redis

func (*RedisEventBus) GetAllSubscriberInfo

func (eb *RedisEventBus) GetAllSubscriberInfo() []events.SubscriberInfo

GetAllSubscriberInfo returns information about all subscribers

func (*RedisEventBus) GetHealthStatus

func (eb *RedisEventBus) GetHealthStatus() HealthStatus

GetHealthStatus returns detailed health status

func (*RedisEventBus) GetSubscriberInfo

func (eb *RedisEventBus) GetSubscriberInfo(id events.SubscriptionID) *events.SubscriberInfo

GetSubscriberInfo returns information about a specific subscriber

func (*RedisEventBus) Healthy

func (eb *RedisEventBus) Healthy() bool

Healthy returns true if the event bus is operational

func (*RedisEventBus) IsConnected

func (eb *RedisEventBus) IsConnected() bool

IsConnected returns true if connected to Redis

func (*RedisEventBus) NodeID

func (eb *RedisEventBus) NodeID() string

NodeID returns the unique identifier for this node

func (*RedisEventBus) Publish

func (eb *RedisEventBus) Publish(event events.Event) bool

Publish publishes an event locally and to Redis

func (*RedisEventBus) PublishWithContext

func (eb *RedisEventBus) PublishWithContext(ctx context.Context, event events.Event) error

PublishWithContext publishes an event with context

func (*RedisEventBus) Run

func (eb *RedisEventBus) Run()

Run starts the event bus main loop

func (*RedisEventBus) SetMetrics

func (eb *RedisEventBus) SetMetrics(metrics *events.Metrics)

SetMetrics enables Prometheus metrics for the EventBus

func (*RedisEventBus) Stats

func (eb *RedisEventBus) Stats() (uint64, uint64, uint64)

Stats returns the current statistics

func (*RedisEventBus) Stop

func (eb *RedisEventBus) Stop()

Stop gracefully stops the event bus

func (*RedisEventBus) Subscribe

func (eb *RedisEventBus) Subscribe(
	id events.SubscriptionID,
	eventTypes []events.EventType,
	filter *events.Filter,
	channelSize int,
) *events.Subscription

Subscribe creates a new subscription for the given event types

func (*RedisEventBus) SubscribeWithOptions

func (eb *RedisEventBus) SubscribeWithOptions(
	id events.SubscriptionID,
	eventTypes []events.EventType,
	filter *events.Filter,
	opts events.SubscribeOptions,
) *events.Subscription

SubscribeWithOptions creates a new subscription with configurable options

func (*RedisEventBus) SubscriberCount

func (eb *RedisEventBus) SubscriberCount() int

SubscriberCount returns the current number of active subscribers

func (*RedisEventBus) Type

func (eb *RedisEventBus) Type() EventBusType

Type returns the type of event bus implementation

func (*RedisEventBus) Unsubscribe

func (eb *RedisEventBus) Unsubscribe(id events.SubscriptionID)

Unsubscribe removes a subscription

type ShutdownHook

type ShutdownHook func(ctx context.Context) error

ShutdownHook represents a function to call during shutdown

type ShutdownManager

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

ShutdownManager handles graceful shutdown of distributed EventBus components

func NewShutdownManager

func NewShutdownManager(shutdownTimeout time.Duration) *ShutdownManager

NewShutdownManager creates a new shutdown manager

func (*ShutdownManager) RegisterEventBus

func (sm *ShutdownManager) RegisterEventBus(eb EventBus)

RegisterEventBus registers an EventBus for shutdown

func (*ShutdownManager) RegisterKafkaProducer

func (sm *ShutdownManager) RegisterKafkaProducer(kp *KafkaProducer)

RegisterKafkaProducer registers a Kafka producer for shutdown

func (*ShutdownManager) Shutdown

func (sm *ShutdownManager) Shutdown(ctx context.Context) error

Shutdown performs graceful shutdown of all registered components

type Subscriber

type Subscriber interface {
	// Subscribe creates a new subscription for the given event types
	// Returns a Subscription that can be used to receive events
	Subscribe(
		id events.SubscriptionID,
		eventTypes []events.EventType,
		filter *events.Filter,
		channelSize int,
	) *events.Subscription

	// SubscribeWithOptions creates a new subscription with configurable options
	SubscribeWithOptions(
		id events.SubscriptionID,
		eventTypes []events.EventType,
		filter *events.Filter,
		opts events.SubscribeOptions,
	) *events.Subscription

	// Unsubscribe removes a subscription
	Unsubscribe(id events.SubscriptionID)
}

Subscriber defines the interface for subscribing to events

Jump to

Keyboard shortcuts

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