Skip to content

Commit 3b4ba1c

Browse files
committed
init: new go rules engine
1 parent f9974d0 commit 3b4ba1c

8 files changed

Lines changed: 351 additions & 0 deletions

File tree

listener/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
## ThirdEye listener
2+
3+
Standalone minimal listener to listen to important transactions.
4+
5+
### Simple mechanism
6+
7+
1. Listener listens to the transactions of a particular contract/wallet.
8+
2. Listener filters out the transactions based of the expression provided.
9+
3. Listener sends the filtered transaction to a webhook
10+
11+
### Important addons:
12+
- Using memcached to store quick needed data.

listener/go.mod

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module thirdeye
2+
3+
go 1.22.3
4+
5+
require (
6+
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874
7+
github.com/gofiber/fiber/v2 v2.52.5
8+
)
9+
10+
require (
11+
github.com/andybalholm/brotli v1.0.5 // indirect
12+
github.com/google/uuid v1.5.0 // indirect
13+
github.com/klauspost/compress v1.17.0 // indirect
14+
github.com/mattn/go-colorable v0.1.13 // indirect
15+
github.com/mattn/go-isatty v0.0.20 // indirect
16+
github.com/mattn/go-runewidth v0.0.15 // indirect
17+
github.com/rivo/uniseg v0.2.0 // indirect
18+
github.com/valyala/bytebufferpool v1.0.0 // indirect
19+
github.com/valyala/fasthttp v1.51.0 // indirect
20+
github.com/valyala/tcplisten v1.0.0 // indirect
21+
golang.org/x/sys v0.15.0 // indirect
22+
)

listener/go.sum

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
2+
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
3+
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous=
4+
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
5+
github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo=
6+
github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
7+
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
8+
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
9+
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
10+
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
11+
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
12+
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
13+
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
14+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
15+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
16+
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
17+
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
18+
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
19+
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
20+
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
21+
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
22+
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
23+
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
24+
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
25+
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
26+
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
27+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
28+
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
29+
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

listener/main.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"time"
6+
7+
"os"
8+
"fmt"
9+
10+
router "thirdeye/router"
11+
12+
fiber "github.com/gofiber/fiber/v2"
13+
cors "github.com/gofiber/fiber/v2/middleware/cors"
14+
"github.com/bradfitz/gomemcache/memcache"
15+
)
16+
17+
var memcachedClient *memcache.Client
18+
19+
func connectToMemcached() error {
20+
memcachedClient = memcache.New(os.Getenv("THIRDEYE_MEMCACHED_URL"))
21+
22+
return memcachedClient.Ping()
23+
}
24+
25+
func waitForMemcached(maxRetries int, retryInterval time.Duration) error {
26+
for i := 0; i < maxRetries; i++ {
27+
err := connectToMemcached()
28+
if err == nil {
29+
log.Println("[INFO] Successfully connected to Memcached")
30+
return nil
31+
}
32+
33+
log.Printf("[WARN] Failed to connect to Memcached (attempt %d/%d): %v\n",
34+
i+1, maxRetries, err)
35+
36+
if i < maxRetries-1 {
37+
log.Printf("[INFO] Retrying in %v...\n", retryInterval)
38+
time.Sleep(retryInterval)
39+
}
40+
}
41+
42+
return fmt.Errorf("failed to connect to Memcached after %d attempts", maxRetries)
43+
}
44+
45+
func CreateServer() *fiber.App {
46+
app := fiber.New()
47+
return app
48+
}
49+
50+
func main() {
51+
// Try to connect to Memcached with retries
52+
err := waitForMemcached(5, 5*time.Second)
53+
if err != nil {
54+
log.Fatal("[ERROR] Could not connect to Memcached: ", err)
55+
}
56+
57+
app := CreateServer()
58+
app.Use(cors.New())
59+
60+
// Add a test endpoint to verify Memcached connection
61+
app.Get("/memcached-test", func(c *fiber.Ctx) error {
62+
// Try to set and get a test value
63+
testKey := "test_key"
64+
testValue := "test_value"
65+
66+
err := memcachedClient.Set(&memcache.Item{
67+
Key: testKey,
68+
Value: []byte(testValue),
69+
Expiration: 30, // 30 seconds
70+
})
71+
72+
if err != nil {
73+
return c.Status(500).JSON(fiber.Map{
74+
"error": "Failed to set value in Memcached",
75+
"details": err.Error(),
76+
})
77+
}
78+
79+
item, err := memcachedClient.Get(testKey)
80+
if err != nil {
81+
return c.Status(500).JSON(fiber.Map{
82+
"error": "Failed to get value from Memcached",
83+
"details": err.Error(),
84+
})
85+
}
86+
87+
return c.JSON(fiber.Map{
88+
"status": "success",
89+
"value": string(item.Value),
90+
})
91+
})
92+
93+
router.SetupRoutes(app)
94+
95+
app.Use(func(c *fiber.Ctx) error {
96+
return c.SendStatus(404)
97+
})
98+
99+
log.Println("[INFO] Server started on :5002")
100+
log.Fatal(app.Listen(":5002"))
101+
}

listener/router/addresses.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package router
2+
3+
import (
4+
utils "thirdeye/utils"
5+
6+
"log"
7+
fiber "github.com/gofiber/fiber/v2"
8+
)
9+
10+
func SetupAddressesRoutes() {
11+
ADDRESSES.Get("/get", HandleGetAddresses)
12+
ADDRESSES.Post("/create", HandleCreateAddress)
13+
ADDRESSES.Delete("/delete", HandleDeleteAddresses)
14+
}
15+
16+
func HandleGetAddresses(c *fiber.Ctx) error {
17+
addresses, err := utils.GetThirdeyeAddresses()
18+
if err != nil {
19+
log.Printf("[ERROR] Failed to get addresses: %v", err)
20+
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
21+
"error": err.Error(),
22+
})
23+
}
24+
25+
return c.JSON(fiber.Map{
26+
"addresses": addresses,
27+
})
28+
}
29+
30+
func HandleCreateAddress(c *fiber.Ctx) error {
31+
var newAddress utils.ThirdeyeAddress
32+
33+
if err := c.BodyParser(&newAddress); err != nil {
34+
log.Printf("[ERROR] Invalid request body: %v", err)
35+
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
36+
"error": err.Error(),
37+
})
38+
}
39+
40+
if newAddress.Network == "" || newAddress.Chain == "" || newAddress.Address == "" {
41+
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
42+
"error": "Network, Chain, and Address are required fields",
43+
})
44+
}
45+
46+
if err := utils.AppendThirdeyeAddress(newAddress); err != nil {
47+
log.Printf("[ERROR] Failed to add address: %v", err)
48+
if err.Error() == "address already exists" {
49+
return c.Status(fiber.StatusConflict).JSON(fiber.Map{
50+
"error": err.Error(),
51+
})
52+
}
53+
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
54+
"error": err.Error(),
55+
})
56+
}
57+
58+
return c.Status(fiber.StatusCreated).JSON(fiber.Map{
59+
"message": "Address added successfully",
60+
"address": newAddress,
61+
})
62+
}
63+
64+
func HandleDeleteAddresses(c *fiber.Ctx) error {
65+
if err := utils.DeleteThirdeyeAddresses(); err != nil {
66+
log.Printf("[ERROR] Failed to delete addresses: %v", err)
67+
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
68+
"error": err.Error(),
69+
})
70+
}
71+
72+
return c.JSON(fiber.Map{
73+
"message": "All addresses deleted successfully",
74+
})
75+
}

listener/router/setup.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package router
2+
3+
import (
4+
fiber "github.com/gofiber/fiber/v2"
5+
cors "github.com/gofiber/fiber/v2/middleware/cors"
6+
logger "github.com/gofiber/fiber/v2/middleware/logger"
7+
)
8+
9+
var ADDRESSES fiber.Router
10+
11+
func SetupRoutes(app *fiber.App) {
12+
app.Use(logger.New())
13+
14+
app.Use(cors.New(cors.Config{
15+
AllowOrigins: "*",
16+
AllowMethods: "GET,POST,PUT,DELETE",
17+
AllowHeaders: "Content-Type, Authorization",
18+
// AllowCredentials: true,
19+
}))
20+
21+
api := app.Group("/api")
22+
ADDRESSES = api.Group("/addresses")
23+
24+
SetupAddressesRoutes()
25+
}

listener/utils/db-connector.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package utils
2+
3+
import (
4+
"os"
5+
"encoding/json"
6+
"log"
7+
"github.com/bradfitz/gomemcache/memcache"
8+
)
9+
10+
var mc *memcache.Client
11+
12+
func init() {
13+
mc = memcache.New(os.Getenv("THIRDEYE_MEMCACHED_URL"))
14+
}
15+
16+
func GetThirdeyeAddresses() ([]ThirdeyeAddress, error) {
17+
item, err := mc.Get("thirdeye_addresses")
18+
if err == memcache.ErrCacheMiss {
19+
return []ThirdeyeAddress{}, nil
20+
}
21+
if err != nil {
22+
log.Printf("[ERROR] Failed to get thirdeye addresses: %v", err)
23+
return nil, err
24+
}
25+
26+
var addresses []ThirdeyeAddress
27+
if err := json.Unmarshal(item.Value, &addresses); err != nil {
28+
log.Printf("[ERROR] Failed to unmarshal thirdeye addresses: %v", err)
29+
return nil, err
30+
}
31+
32+
return addresses, nil
33+
}
34+
35+
func AppendThirdeyeAddress(newAddress ThirdeyeAddress) error {
36+
addresses, err := GetThirdeyeAddresses()
37+
if err != nil {
38+
log.Printf("[ERROR] Failed to get existing addresses: %v", err)
39+
return err
40+
}
41+
42+
for _, addr := range addresses {
43+
if addr.Network == newAddress.Network &&
44+
addr.Chain == newAddress.Chain &&
45+
addr.Address == newAddress.Address {
46+
return err
47+
}
48+
}
49+
50+
addresses = append(addresses, newAddress)
51+
52+
jsonData, err := json.Marshal(addresses)
53+
if err != nil {
54+
log.Printf("[ERROR] Failed to marshal addresses: %v", err)
55+
return err
56+
}
57+
58+
err = mc.Set(&memcache.Item{
59+
Key: "thirdeye_addresses",
60+
Value: jsonData,
61+
})
62+
if err != nil {
63+
log.Printf("[ERROR] Failed to store updated addresses: %v", err)
64+
return err
65+
}
66+
67+
return nil
68+
}
69+
70+
func DeleteThirdeyeAddresses() error {
71+
err := mc.Delete("thirdeye_addresses")
72+
if err == memcache.ErrCacheMiss {
73+
return nil
74+
}
75+
if err != nil {
76+
log.Printf("[ERROR] Failed to delete thirdeye addresses: %v", err)
77+
return err
78+
}
79+
return nil
80+
}

listener/utils/structs.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package utils
2+
3+
type ThirdeyeAddress struct {
4+
Network string `json:"network"`
5+
Chain string `json:"chain"`
6+
Address string `json:"address"`
7+
}

0 commit comments

Comments
 (0)