Skip to content

Commit

Permalink
Merge pull request #61 from blinklabs-io/feat/filter-multiple-value
Browse files Browse the repository at this point in the history
feat: support for multiple filter values
  • Loading branch information
agaffney authored Aug 11, 2023
2 parents f5938d1 + 4d2fcef commit 1f309d0
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 73 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ plugins:
## Filtering
snek supports filtering events before they are output.
snek supports filtering events before they are output using multiple criteria. An event must match all configured filters to be emitted.
Each filter supports specifying multiple possible values separated by commas. When specifying multiple values for a filter, only one of
the values specified must match an event.
You can get a list of all available filter options by using the `-h`/`-help` flag.

Expand Down Expand Up @@ -172,6 +174,12 @@ Only output `chainsync.transaction` event types
$ snek -filter-type chainsync.transaction
```

Only output `chainsync.rollback` and `chainsync.block` event types

```bash
$ snek -filter-type chainsync.transaction,chainsync.block
```

#### Filtering on asset policy

Only output transactions involving an asset with a particular policy ID
Expand Down
113 changes: 67 additions & 46 deletions filter/chainsync/chainsync.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ import (
)

type ChainSync struct {
errorChan chan error
inputChan chan event.Event
outputChan chan event.Event
filterAddress string
filterPolicyId string
filterAssetFingerprint string
errorChan chan error
inputChan chan event.Event
outputChan chan event.Event
filterAddresses []string
filterPolicyIds []string
filterAssetFingerprints []string
}

// New returns a new ChainSync object with the specified options applied
Expand Down Expand Up @@ -57,74 +57,95 @@ func (c *ChainSync) Start() error {
switch v := evt.Payload.(type) {
case chainsync.TransactionEvent:
// Check address filter
if c.filterAddress != "" {
isStakeAddress := false
if strings.HasPrefix(c.filterAddress, "stake") {
isStakeAddress = true
}
foundMatch := false
for _, output := range v.Outputs {
if output.Address().String() == c.filterAddress {
foundMatch = true
break
}
if isStakeAddress {
stakeAddr := output.Address().StakeAddress()
if stakeAddr == nil {
continue
}
if stakeAddr.String() == c.filterAddress {
if len(c.filterAddresses) > 0 {
filterMatched := false
for _, filterAddress := range c.filterAddresses {
isStakeAddress := strings.HasPrefix(filterAddress, "stake")
foundMatch := false
for _, output := range v.Outputs {
if output.Address().String() == filterAddress {
foundMatch = true
break
}
if isStakeAddress {
stakeAddr := output.Address().StakeAddress()
if stakeAddr == nil {
continue
}
if stakeAddr.String() == filterAddress {
foundMatch = true
break
}
}
}
if foundMatch {
filterMatched = true
break
}
}
if !foundMatch {
// Skip the event if none of the filter values matched
if !filterMatched {
continue
}
}
// Check policy ID filter
if c.filterPolicyId != "" {
foundMatch := false
for _, output := range v.Outputs {
if output.Assets() != nil {
for _, policyId := range output.Assets().Policies() {
if policyId.String() == c.filterPolicyId {
foundMatch = true
break
if len(c.filterPolicyIds) > 0 {
filterMatched := false
for _, filterPolicyId := range c.filterPolicyIds {
foundMatch := false
for _, output := range v.Outputs {
if output.Assets() != nil {
for _, policyId := range output.Assets().Policies() {
if policyId.String() == filterPolicyId {
foundMatch = true
break
}
}
}
if foundMatch {
break
}
}
if foundMatch {
filterMatched = true
break
}
}
if !foundMatch {
// Skip the event if none of the filter values matched
if !filterMatched {
continue
}
}
// Check asset fingerprint filter
if c.filterAssetFingerprint != "" {
foundMatch := false
for _, output := range v.Outputs {
if output.Assets() != nil {
for _, policyId := range output.Assets().Policies() {
for _, assetName := range output.Assets().Assets(policyId) {
assetFp := ledger.NewAssetFingerprint(policyId.Bytes(), assetName)
if assetFp.String() == c.filterAssetFingerprint {
foundMatch = true
if len(c.filterAssetFingerprints) > 0 {
filterMatched := false
for _, filterAssetFingerprint := range c.filterAssetFingerprints {
foundMatch := false
for _, output := range v.Outputs {
if output.Assets() != nil {
for _, policyId := range output.Assets().Policies() {
for _, assetName := range output.Assets().Assets(policyId) {
assetFp := ledger.NewAssetFingerprint(policyId.Bytes(), assetName)
if assetFp.String() == filterAssetFingerprint {
foundMatch = true
}
}
if foundMatch {
break
}
}
if foundMatch {
break
}
}
if foundMatch {
break
}
}
if foundMatch {
filterMatched = true
break
}
}
if !foundMatch {
// Skip the event if none of the filter values matched
if !filterMatched {
continue
}
}
Expand Down
18 changes: 9 additions & 9 deletions filter/chainsync/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,23 @@ package chainsync

type ChainSyncOptionFunc func(*ChainSync)

// WithAddress specfies the address to filter on
func WithAddress(address string) ChainSyncOptionFunc {
// WithAddresses specfies the address to filter on
func WithAddresses(addresses []string) ChainSyncOptionFunc {
return func(c *ChainSync) {
c.filterAddress = address
c.filterAddresses = addresses[:]
}
}

// WithPolicy specfies the address to filter on
func WithPolicy(policyId string) ChainSyncOptionFunc {
// WithPolicies specfies the address to filter on
func WithPolicies(policyIds []string) ChainSyncOptionFunc {
return func(c *ChainSync) {
c.filterPolicyId = policyId
c.filterPolicyIds = policyIds[:]
}
}

//WithAssetFingerprint specifies the asset fingerprint (asset1xxx) to filter on
func WithAssetFingerprint(assetFingerprint string) ChainSyncOptionFunc {
//WithAssetFingerprints specifies the asset fingerprint (asset1xxx) to filter on
func WithAssetFingerprints(assetFingerprints []string) ChainSyncOptionFunc {
return func(c *ChainSync) {
c.filterAssetFingerprint = assetFingerprint
c.filterAssetFingerprints = assetFingerprints[:]
}
}
33 changes: 28 additions & 5 deletions filter/chainsync/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package chainsync

import (
"strings"

"github.com/blinklabs-io/snek/plugin"
)

Expand Down Expand Up @@ -62,10 +64,31 @@ func init() {
}

func NewFromCmdlineOptions() plugin.Plugin {
p := New(
WithAddress(cmdlineOptions.address),
WithPolicy(cmdlineOptions.policyId),
WithAssetFingerprint(cmdlineOptions.asset),
)
pluginOptions := []ChainSyncOptionFunc{}
if cmdlineOptions.address != "" {
pluginOptions = append(
pluginOptions,
WithAddresses(
strings.Split(cmdlineOptions.address, ","),
),
)
}
if cmdlineOptions.policyId != "" {
pluginOptions = append(
pluginOptions,
WithPolicies(
strings.Split(cmdlineOptions.policyId, ","),
),
)
}
if cmdlineOptions.asset != "" {
pluginOptions = append(
pluginOptions,
WithAssetFingerprints(
strings.Split(cmdlineOptions.asset, ","),
),
)
}
p := New(pluginOptions...)
return p
}
19 changes: 13 additions & 6 deletions filter/event/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import (
)

type Event struct {
errorChan chan error
inputChan chan event.Event
outputChan chan event.Event
filterType string
errorChan chan error
inputChan chan event.Event
outputChan chan event.Event
filterTypes []string
}

// New returns a new Event object with the specified options applied
Expand All @@ -49,8 +49,15 @@ func (e *Event) Start() error {
return
}
// Drop events if we have a type filter configured and the event doesn't match
if e.filterType != "" {
if evt.Type != e.filterType {
if len(e.filterTypes) > 0 {
matched := false
for _, filterType := range e.filterTypes {
if evt.Type == filterType {
matched = true
break
}
}
if !matched {
continue
}
}
Expand Down
6 changes: 3 additions & 3 deletions filter/event/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ package event

type EventOptionFunc func(*Event)

// WithType specfies the event type to filter on
func WithType(eventType string) EventOptionFunc {
// WithTypes specfies the event types to filter on
func WithTypes(eventTypes []string) EventOptionFunc {
return func(e *Event) {
e.filterType = eventType
e.filterTypes = eventTypes[:]
}
}
15 changes: 12 additions & 3 deletions filter/event/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package event

import (
"strings"

"github.com/blinklabs-io/snek/plugin"
)

Expand Down Expand Up @@ -44,8 +46,15 @@ func init() {
}

func NewFromCmdlineOptions() plugin.Plugin {
p := New(
WithType(cmdlineOptions.eventType),
)
pluginOptions := []EventOptionFunc{}
if cmdlineOptions.eventType != "" {
pluginOptions = append(
pluginOptions,
WithTypes(
strings.Split(cmdlineOptions.eventType, ","),
),
)
}
p := New(pluginOptions...)
return p
}

0 comments on commit 1f309d0

Please sign in to comment.