github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/types/events.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"sort"
     8  	"strings"
     9  
    10  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    11  	tmkv "github.com/fibonacci-chain/fbc/libs/tendermint/libs/kv"
    12  )
    13  
    14  // ----------------------------------------------------------------------------
    15  // Event Manager
    16  // ----------------------------------------------------------------------------
    17  
    18  // EventManager implements a simple wrapper around a slice of Event objects that
    19  // can be emitted from.
    20  type EventManager struct {
    21  	events Events
    22  }
    23  
    24  func NewEventManager() *EventManager {
    25  	return &EventManager{EmptyEvents()}
    26  }
    27  
    28  func (em *EventManager) Events() Events { return em.events }
    29  
    30  // EmitEvent stores a single Event object.
    31  func (em *EventManager) EmitEvent(event Event) {
    32  	em.events = em.events.AppendEvent(event)
    33  }
    34  
    35  // EmitEvents stores a series of Event objects.
    36  func (em *EventManager) EmitEvents(events Events) {
    37  	em.events = em.events.AppendEvents(events)
    38  }
    39  
    40  // ABCIEvents returns all stored Event objects as abci.Event objects.
    41  func (em EventManager) ABCIEvents() []abci.Event {
    42  	return em.events.ToABCIEvents()
    43  }
    44  
    45  // ----------------------------------------------------------------------------
    46  // Events
    47  // ----------------------------------------------------------------------------
    48  
    49  type (
    50  	// Event is a type alias for an ABCI Event
    51  	Event abci.Event
    52  
    53  	// Attribute defines an attribute wrapper where the key and value are
    54  	// strings instead of raw bytes.
    55  	Attribute struct {
    56  		Key   string `json:"key"`
    57  		Value string `json:"value,omitempty"`
    58  	}
    59  
    60  	// Events defines a slice of Event objects
    61  	Events []Event
    62  )
    63  
    64  func (a Attribute) MarshalJsonToBuffer(buf *bytes.Buffer) error {
    65  	var err error
    66  
    67  	err = buf.WriteByte('{')
    68  	if err != nil {
    69  		return err
    70  	}
    71  
    72  	_, err = buf.WriteString(`"key":`)
    73  	if err != nil {
    74  		return err
    75  	}
    76  	blob, err := json.Marshal(a.Key)
    77  	if err != nil {
    78  		return err
    79  	}
    80  	_, err = buf.Write(blob)
    81  	if err != nil {
    82  		return err
    83  	}
    84  
    85  	if a.Value != "" {
    86  		err = buf.WriteByte(',')
    87  		if err != nil {
    88  			return err
    89  		}
    90  		buf.WriteString(`"value":`)
    91  		blob, err = json.Marshal(a.Value)
    92  		if err != nil {
    93  			return err
    94  		}
    95  		_, err = buf.Write(blob)
    96  		if err != nil {
    97  			return err
    98  		}
    99  	}
   100  
   101  	return buf.WriteByte('}')
   102  }
   103  
   104  // NewEvent creates a new Event object with a given type and slice of one or more
   105  // attributes.
   106  func NewEvent(ty string, attrs ...Attribute) Event {
   107  	e := Event{Type: ty}
   108  	if len(attrs) > 0 {
   109  		e.Attributes = make([]tmkv.Pair, len(attrs))
   110  	}
   111  
   112  	for i, attr := range attrs {
   113  		e.Attributes[i].Key = []byte(attr.Key)
   114  		e.Attributes[i].Value = []byte(attr.Value)
   115  	}
   116  
   117  	return e
   118  }
   119  
   120  // NewAttribute returns a new key/value Attribute object.
   121  func NewAttribute(k, v string) Attribute {
   122  	return Attribute{k, v}
   123  }
   124  
   125  // EmptyEvents returns an empty slice of events.
   126  func EmptyEvents() Events {
   127  	return make(Events, 0)
   128  }
   129  
   130  func (a Attribute) String() string {
   131  	return fmt.Sprintf("%s: %s", a.Key, a.Value)
   132  }
   133  
   134  // ToKVPair converts an Attribute object into a Tendermint key/value pair.
   135  func (a Attribute) ToKVPair() tmkv.Pair {
   136  	return tmkv.Pair{Key: []byte(a.Key), Value: []byte(a.Value)}
   137  }
   138  
   139  // AppendAttributes adds one or more attributes to an Event.
   140  func (e Event) AppendAttributes(attrs ...Attribute) Event {
   141  	for _, attr := range attrs {
   142  		e.Attributes = append(e.Attributes, attr.ToKVPair())
   143  	}
   144  	return e
   145  }
   146  
   147  // AppendEvent adds an Event to a slice of events.
   148  func (e Events) AppendEvent(event Event) Events {
   149  	return append(e, event)
   150  }
   151  
   152  // AppendEvents adds a slice of Event objects to an exist slice of Event objects.
   153  func (e Events) AppendEvents(events Events) Events {
   154  	return append(e, events...)
   155  }
   156  
   157  // ToABCIEvents converts a slice of Event objects to a slice of abci.Event
   158  // objects.
   159  func (e Events) ToABCIEvents() []abci.Event {
   160  	res := make([]abci.Event, len(e))
   161  	for i, ev := range e {
   162  		res[i] = abci.Event{Type: ev.Type, Attributes: ev.Attributes}
   163  	}
   164  
   165  	return res
   166  }
   167  
   168  func toBytes(i interface{}) []byte {
   169  	switch x := i.(type) {
   170  	case []uint8:
   171  		return x
   172  	case string:
   173  		return []byte(x)
   174  	default:
   175  		panic(i)
   176  	}
   177  }
   178  
   179  // Common event types and attribute keys
   180  var (
   181  	EventTypeMessage = "message"
   182  
   183  	AttributeKeyAction = "action"
   184  	AttributeKeyModule = "module"
   185  	AttributeKeySender = "sender"
   186  	AttributeKeyAmount = "amount"
   187  	AttributeKeyFee    = "fee"
   188  )
   189  
   190  type (
   191  	// StringAttribute defines en Event object wrapper where all the attributes
   192  	// contain key/value pairs that are strings instead of raw bytes.
   193  	StringEvent struct {
   194  		Type       string      `json:"type,omitempty"`
   195  		Attributes []Attribute `json:"attributes,omitempty"`
   196  	}
   197  
   198  	// StringAttributes defines a slice of StringEvents objects.
   199  	StringEvents []StringEvent
   200  )
   201  
   202  func (e StringEvent) MarshalJsonToBuffer(buf *bytes.Buffer) error {
   203  	var err error
   204  
   205  	err = buf.WriteByte('{')
   206  	if err != nil {
   207  		return err
   208  	}
   209  
   210  	var writeComma = false
   211  
   212  	if e.Type != "" {
   213  		_, err = buf.WriteString(`"type":`)
   214  		if err != nil {
   215  			return err
   216  		}
   217  		blob, err := json.Marshal(e.Type)
   218  		if err != nil {
   219  			return err
   220  		}
   221  		_, err = buf.Write(blob)
   222  		if err != nil {
   223  			return err
   224  		}
   225  		writeComma = true
   226  	}
   227  
   228  	if len(e.Attributes) != 0 {
   229  		if writeComma {
   230  			_, err = buf.WriteString(`,`)
   231  			if err != nil {
   232  				return err
   233  			}
   234  		}
   235  		_, err = buf.WriteString(`"attributes":[`)
   236  		if err != nil {
   237  			return err
   238  		}
   239  		for i, attr := range e.Attributes {
   240  			if i != 0 {
   241  				err = buf.WriteByte(',')
   242  				if err != nil {
   243  					return err
   244  				}
   245  			}
   246  			err = attr.MarshalJsonToBuffer(buf)
   247  			if err != nil {
   248  				return err
   249  			}
   250  		}
   251  		err = buf.WriteByte(']')
   252  		if err != nil {
   253  			return err
   254  		}
   255  	}
   256  
   257  	return buf.WriteByte('}')
   258  }
   259  
   260  func (se StringEvents) MarshalJsonToBuffer(buf *bytes.Buffer) error {
   261  	var err error
   262  	if se == nil {
   263  		_, err = buf.WriteString("null")
   264  		return err
   265  	}
   266  
   267  	err = buf.WriteByte('[')
   268  	if err != nil {
   269  		return err
   270  	}
   271  	for i, event := range se {
   272  		if i != 0 {
   273  			err = buf.WriteByte(',')
   274  			if err != nil {
   275  				return err
   276  			}
   277  		}
   278  		err = event.MarshalJsonToBuffer(buf)
   279  		if err != nil {
   280  			return err
   281  		}
   282  	}
   283  	return buf.WriteByte(']')
   284  }
   285  
   286  func (se StringEvents) String() string {
   287  	var sb strings.Builder
   288  
   289  	for _, e := range se {
   290  		sb.WriteString(fmt.Sprintf("\t\t- %s\n", e.Type))
   291  
   292  		for _, attr := range e.Attributes {
   293  			sb.WriteString(fmt.Sprintf("\t\t\t- %s\n", attr.String()))
   294  		}
   295  	}
   296  
   297  	return strings.TrimRight(sb.String(), "\n")
   298  }
   299  
   300  // Flatten returns a flattened version of StringEvents by grouping all attributes
   301  // per unique event type.
   302  func (se StringEvents) Flatten() StringEvents {
   303  	flatEvents := make(map[string][]Attribute)
   304  
   305  	for _, e := range se {
   306  		flatEvents[e.Type] = append(flatEvents[e.Type], e.Attributes...)
   307  	}
   308  	keys := make([]string, 0, len(flatEvents))
   309  	res := make(StringEvents, 0, len(flatEvents)) // appeneded to keys, same length of what is allocated to keys
   310  
   311  	for ty := range flatEvents {
   312  		keys = append(keys, ty)
   313  	}
   314  
   315  	sort.Strings(keys)
   316  	for _, ty := range keys {
   317  		res = append(res, StringEvent{Type: ty, Attributes: flatEvents[ty]})
   318  	}
   319  
   320  	return res
   321  }
   322  
   323  // StringifyEvent converts an Event object to a StringEvent object.
   324  func StringifyEvent(e Event) StringEvent {
   325  	res := StringEvent{Type: e.Type}
   326  
   327  	for _, attr := range e.Attributes {
   328  		res.Attributes = append(
   329  			res.Attributes,
   330  			Attribute{string(attr.Key), string(attr.Value)},
   331  		)
   332  	}
   333  
   334  	return res
   335  }
   336  
   337  // StringifyEvents converts a slice of Event objects into a slice of StringEvent
   338  // objects.
   339  func StringifyEvents(events []Event) StringEvents {
   340  	res := make(StringEvents, 0, len(events))
   341  
   342  	for _, e := range events {
   343  		res = append(res, StringifyEvent(e))
   344  	}
   345  
   346  	return res.Flatten()
   347  }