mirror of
https://github.com/eosswedenorg/thalos
synced 2026-06-16 04:24:56 +02:00
Formatting fix.
This commit is contained in:
parent
953113b456
commit
1e2dda54c8
9 changed files with 440 additions and 448 deletions
75
abi.go
75
abi.go
|
|
@ -1,57 +1,56 @@
|
|||
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
"errors"
|
||||
"fmt"
|
||||
"encoding/json"
|
||||
eos "github.com/eoscanada/eos-go"
|
||||
redis_cache "github.com/go-redis/cache/v8"
|
||||
"eosio-ship-trace-reader/abi_cache"
|
||||
"eosio-ship-trace-reader/redis"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"eosio-ship-trace-reader/abi_cache"
|
||||
"eosio-ship-trace-reader/redis"
|
||||
|
||||
eos "github.com/eoscanada/eos-go"
|
||||
redis_cache "github.com/go-redis/cache/v8"
|
||||
)
|
||||
|
||||
var abiCache *abi_cache.Cache
|
||||
|
||||
func InitAbiCache(id string) {
|
||||
// Init abi cache
|
||||
abiCache = abi_cache.New("ship.cache." + id + ".abi", &redis_cache.Options{
|
||||
Redis: redis.Client(),
|
||||
// Cache 10k keys for 10 minutes.
|
||||
LocalCache: redis_cache.NewTinyLFU(10000, 10 * time.Minute),
|
||||
})
|
||||
// Init abi cache
|
||||
abiCache = abi_cache.New("ship.cache."+id+".abi", &redis_cache.Options{
|
||||
Redis: redis.Client(),
|
||||
// Cache 10k keys for 10 minutes.
|
||||
LocalCache: redis_cache.NewTinyLFU(10000, 10*time.Minute),
|
||||
})
|
||||
}
|
||||
|
||||
func GetAbi(account eos.AccountName) (*eos.ABI, error) {
|
||||
key := string(account)
|
||||
|
||||
key := string(account)
|
||||
abi, err := abiCache.Get(key)
|
||||
if err != nil {
|
||||
resp, err := eosClient.GetABI(eosClientCtx, account)
|
||||
if err != nil {
|
||||
return nil, errors.New(fmt.Sprintf("api: %s", err))
|
||||
}
|
||||
abi = &resp.ABI
|
||||
|
||||
abi, err := abiCache.Get(key)
|
||||
if err != nil {
|
||||
resp, err := eosClient.GetABI(eosClientCtx, account)
|
||||
if err != nil {
|
||||
return nil, errors.New(fmt.Sprintf("api: %s", err))
|
||||
}
|
||||
abi = &resp.ABI
|
||||
|
||||
err = abiCache.Set(key, abi, time.Hour)
|
||||
if err != nil {
|
||||
return nil, errors.New(fmt.Sprintf("cache: %s", err))
|
||||
}
|
||||
}
|
||||
return abi, nil
|
||||
err = abiCache.Set(key, abi, time.Hour)
|
||||
if err != nil {
|
||||
return nil, errors.New(fmt.Sprintf("cache: %s", err))
|
||||
}
|
||||
}
|
||||
return abi, nil
|
||||
}
|
||||
|
||||
func DecodeAction(abi *eos.ABI, data []byte, actionName eos.ActionName) (interface{}, error) {
|
||||
var v interface{}
|
||||
|
||||
var v interface{}
|
||||
bytes, err := abi.DecodeAction(data, actionName)
|
||||
if err != nil {
|
||||
return v, err
|
||||
}
|
||||
|
||||
bytes, err := abi.DecodeAction(data, actionName)
|
||||
if err != nil {
|
||||
return v, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(bytes, &v)
|
||||
return v, err
|
||||
err = json.Unmarshal(bytes, &v)
|
||||
return v, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,42 @@
|
|||
|
||||
package abi_cache
|
||||
|
||||
import (
|
||||
"time"
|
||||
"context"
|
||||
redis_cache "github.com/go-redis/cache/v8"
|
||||
eos "github.com/eoscanada/eos-go"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
eos "github.com/eoscanada/eos-go"
|
||||
redis_cache "github.com/go-redis/cache/v8"
|
||||
)
|
||||
|
||||
type Cache struct {
|
||||
c *redis_cache.Cache
|
||||
ctx context.Context
|
||||
prefix string
|
||||
c *redis_cache.Cache
|
||||
ctx context.Context
|
||||
prefix string
|
||||
}
|
||||
|
||||
func New(prefix string, options *redis_cache.Options) (*Cache) {
|
||||
return &Cache{
|
||||
c: redis_cache.New(options),
|
||||
ctx: context.Background(),
|
||||
prefix: prefix,
|
||||
}
|
||||
func New(prefix string, options *redis_cache.Options) *Cache {
|
||||
return &Cache{
|
||||
c: redis_cache.New(options),
|
||||
ctx: context.Background(),
|
||||
prefix: prefix,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Cache) Get(account string) (*eos.ABI, error) {
|
||||
var v eos.ABI
|
||||
err := this.c.Get(this.ctx, this.key(account), &v);
|
||||
return &v, err
|
||||
var v eos.ABI
|
||||
err := this.c.Get(this.ctx, this.key(account), &v)
|
||||
return &v, err
|
||||
}
|
||||
|
||||
func (this *Cache) Set(account string, abi *eos.ABI, ttl time.Duration) error {
|
||||
return this.c.Set(&redis_cache.Item{
|
||||
Ctx: this.ctx,
|
||||
Key: this.key(account),
|
||||
Value: *abi,
|
||||
TTL: ttl,
|
||||
})
|
||||
return this.c.Set(&redis_cache.Item{
|
||||
Ctx: this.ctx,
|
||||
Key: this.key(account),
|
||||
Value: *abi,
|
||||
TTL: ttl,
|
||||
})
|
||||
}
|
||||
|
||||
func (this *Cache) key(account string) (string) {
|
||||
return this.prefix + "." + account
|
||||
func (this *Cache) key(account string) string {
|
||||
return this.prefix + "." + account
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
|
||||
package abi_cache
|
||||
|
||||
import (
|
||||
"time"
|
||||
"strings"
|
||||
"github.com/go-redis/redis/v8"
|
||||
redis_cache "github.com/go-redis/cache/v8"
|
||||
eos "github.com/eoscanada/eos-go"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"testing"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
eos "github.com/eoscanada/eos-go"
|
||||
redis_cache "github.com/go-redis/cache/v8"
|
||||
"github.com/go-redis/redis/v8"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var abiString = `
|
||||
|
|
@ -74,86 +74,84 @@ var abiString = `
|
|||
`
|
||||
|
||||
func TestGetSet(t *testing.T) {
|
||||
c := New("abi.cache.test", &redis_cache.Options{
|
||||
Redis: redis.NewClient(&redis.Options{}),
|
||||
// Cache 10k keys for 1 minute.
|
||||
LocalCache: redis_cache.NewTinyLFU(10000, time.Minute),
|
||||
})
|
||||
|
||||
c := New("abi.cache.test", &redis_cache.Options{
|
||||
Redis: redis.NewClient(&redis.Options{}),
|
||||
// Cache 10k keys for 1 minute.
|
||||
LocalCache: redis_cache.NewTinyLFU(10000, time.Minute),
|
||||
})
|
||||
abi, err := eos.NewABI(strings.NewReader(abiString))
|
||||
if err != nil {
|
||||
t.Error("Failed to build ABI", err)
|
||||
}
|
||||
|
||||
abi, err := eos.NewABI(strings.NewReader(abiString))
|
||||
if err != nil {
|
||||
t.Error("Failed to build ABI", err)
|
||||
}
|
||||
err = c.Set("testaccount", abi, time.Minute)
|
||||
if err != nil {
|
||||
t.Error("Failed to set cache item", err)
|
||||
}
|
||||
|
||||
err = c.Set("testaccount", abi, time.Minute)
|
||||
if err != nil {
|
||||
t.Error("Failed to set cache item", err)
|
||||
}
|
||||
c_abi, err := c.Get("testaccount")
|
||||
if err != nil {
|
||||
t.Error("Failed to get cache item", err)
|
||||
}
|
||||
|
||||
c_abi, err := c.Get("testaccount")
|
||||
if err != nil {
|
||||
t.Error("Failed to get cache item", err)
|
||||
}
|
||||
assert.Equal(t, c_abi.Version, "eosio::abi/1.0")
|
||||
|
||||
assert.Equal(t, c_abi.Version, "eosio::abi/1.0")
|
||||
// Types
|
||||
assert.Equal(t, c_abi.Types[0].NewTypeName, "new_type_name_1")
|
||||
assert.Equal(t, c_abi.Types[0].Type, "name")
|
||||
|
||||
// Types
|
||||
assert.Equal(t, c_abi.Types[0].NewTypeName, "new_type_name_1")
|
||||
assert.Equal(t, c_abi.Types[0].Type, "name")
|
||||
// Structs
|
||||
assert.Equal(t, c_abi.Structs[0].Name, "struct_name_1")
|
||||
assert.Equal(t, c_abi.Structs[0].Base, "struct_name_2")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[0].Name, "struct_1_field_1")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[0].Type, "new_type_name_1")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[1].Name, "struct_1_field_2")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[1].Type, "struct_name_3")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[2].Name, "struct_1_field_3")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[2].Type, "string?")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[3].Name, "struct_1_field_4")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[3].Type, "string?")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[4].Name, "struct_1_field_5")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[4].Type, "struct_name_4[]")
|
||||
|
||||
// Structs
|
||||
assert.Equal(t, c_abi.Structs[0].Name, "struct_name_1")
|
||||
assert.Equal(t, c_abi.Structs[0].Base, "struct_name_2")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[0].Name, "struct_1_field_1")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[0].Type, "new_type_name_1")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[1].Name, "struct_1_field_2")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[1].Type, "struct_name_3")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[2].Name, "struct_1_field_3")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[2].Type, "string?")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[3].Name, "struct_1_field_4")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[3].Type, "string?")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[4].Name, "struct_1_field_5")
|
||||
assert.Equal(t, c_abi.Structs[0].Fields[4].Type, "struct_name_4[]")
|
||||
assert.Equal(t, c_abi.Structs[1].Name, "struct_name_2")
|
||||
assert.Equal(t, c_abi.Structs[1].Base, "")
|
||||
assert.Equal(t, c_abi.Structs[1].Fields[0].Name, "struct_2_field_1")
|
||||
assert.Equal(t, c_abi.Structs[1].Fields[0].Type, "string")
|
||||
|
||||
assert.Equal(t, c_abi.Structs[1].Name, "struct_name_2")
|
||||
assert.Equal(t, c_abi.Structs[1].Base, "")
|
||||
assert.Equal(t, c_abi.Structs[1].Fields[0].Name, "struct_2_field_1")
|
||||
assert.Equal(t, c_abi.Structs[1].Fields[0].Type, "string")
|
||||
assert.Equal(t, c_abi.Structs[2].Name, "struct_name_3")
|
||||
assert.Equal(t, c_abi.Structs[2].Base, "")
|
||||
assert.Equal(t, c_abi.Structs[2].Fields[0].Name, "struct_3_field_1")
|
||||
assert.Equal(t, c_abi.Structs[2].Fields[0].Type, "string")
|
||||
|
||||
assert.Equal(t, c_abi.Structs[2].Name, "struct_name_3")
|
||||
assert.Equal(t, c_abi.Structs[2].Base, "")
|
||||
assert.Equal(t, c_abi.Structs[2].Fields[0].Name, "struct_3_field_1")
|
||||
assert.Equal(t, c_abi.Structs[2].Fields[0].Type, "string")
|
||||
assert.Equal(t, c_abi.Structs[3].Name, "struct_name_4")
|
||||
assert.Equal(t, c_abi.Structs[3].Base, "")
|
||||
assert.Equal(t, c_abi.Structs[3].Fields[0].Name, "struct_4_field_1")
|
||||
assert.Equal(t, c_abi.Structs[3].Fields[0].Type, "string")
|
||||
|
||||
assert.Equal(t, c_abi.Structs[3].Name, "struct_name_4")
|
||||
assert.Equal(t, c_abi.Structs[3].Base, "")
|
||||
assert.Equal(t, c_abi.Structs[3].Fields[0].Name, "struct_4_field_1")
|
||||
assert.Equal(t, c_abi.Structs[3].Fields[0].Type, "string")
|
||||
// Actions
|
||||
assert.Equal(t, c_abi.Actions[0].Name, eos.ActN("action_name_1"))
|
||||
assert.Equal(t, c_abi.Actions[0].Type, "struct_name_1")
|
||||
assert.Equal(t, c_abi.Actions[0].RicardianContract, "")
|
||||
|
||||
// Actions
|
||||
assert.Equal(t, c_abi.Actions[0].Name, eos.ActN("action_name_1"))
|
||||
assert.Equal(t, c_abi.Actions[0].Type, "struct_name_1")
|
||||
assert.Equal(t, c_abi.Actions[0].RicardianContract, "")
|
||||
|
||||
// Tables
|
||||
assert.Equal(t, c_abi.Tables[0].Name, eos.TableName("table_name_1"))
|
||||
assert.Equal(t, c_abi.Tables[0].Type, "struct_name_1")
|
||||
assert.Equal(t, c_abi.Tables[0].IndexType, "i64")
|
||||
assert.Equal(t, c_abi.Tables[0].KeyNames[0], "key_name_1")
|
||||
assert.Equal(t, c_abi.Tables[0].KeyNames[1], "key_name_2")
|
||||
assert.Equal(t, c_abi.Tables[0].KeyTypes[0], "string")
|
||||
assert.Equal(t, c_abi.Tables[0].KeyTypes[1], "int")
|
||||
// Tables
|
||||
assert.Equal(t, c_abi.Tables[0].Name, eos.TableName("table_name_1"))
|
||||
assert.Equal(t, c_abi.Tables[0].Type, "struct_name_1")
|
||||
assert.Equal(t, c_abi.Tables[0].IndexType, "i64")
|
||||
assert.Equal(t, c_abi.Tables[0].KeyNames[0], "key_name_1")
|
||||
assert.Equal(t, c_abi.Tables[0].KeyNames[1], "key_name_2")
|
||||
assert.Equal(t, c_abi.Tables[0].KeyTypes[0], "string")
|
||||
assert.Equal(t, c_abi.Tables[0].KeyTypes[1], "int")
|
||||
}
|
||||
|
||||
func TestCacheMiss(t *testing.T) {
|
||||
c := New("abi.cache.test", &redis_cache.Options{
|
||||
Redis: redis.NewClient(&redis.Options{}),
|
||||
// Cache 10k keys for 1 minute.
|
||||
LocalCache: redis_cache.NewTinyLFU(10000, time.Minute),
|
||||
})
|
||||
|
||||
c := New("abi.cache.test", &redis_cache.Options{
|
||||
Redis: redis.NewClient(&redis.Options{}),
|
||||
// Cache 10k keys for 1 minute.
|
||||
LocalCache: redis_cache.NewTinyLFU(10000, time.Minute),
|
||||
})
|
||||
|
||||
_, err := c.Get("nonexist")
|
||||
require.Error(t, err)
|
||||
_, err := c.Get("nonexist")
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,63 +1,61 @@
|
|||
|
||||
package config
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"encoding/json"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
const NULL_BLOCK_NUMBER uint32 = 0xffffffff
|
||||
|
||||
type RedisConfig struct {
|
||||
Addr string `json:"addr"`
|
||||
Password string `json:"password"`
|
||||
DB int `json:db`
|
||||
CacheID string `json:"cache_id"`
|
||||
Addr string `json:"addr"`
|
||||
Password string `json:"password"`
|
||||
DB int `json:db`
|
||||
CacheID string `json:"cache_id"`
|
||||
}
|
||||
|
||||
type TelegramConfig struct {
|
||||
Id string `json:"id"`
|
||||
Channel int64 `json:"channel"`
|
||||
Id string `json:"id"`
|
||||
Channel int64 `json:"channel"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Name string `json:"name"`
|
||||
ShipApi string `json:"ship_api"`
|
||||
Api string `json:"api"`
|
||||
Name string `json:"name"`
|
||||
ShipApi string `json:"ship_api"`
|
||||
Api string `json:"api"`
|
||||
|
||||
Redis RedisConfig `json:"redis"`
|
||||
Redis RedisConfig `json:"redis"`
|
||||
|
||||
Telegram TelegramConfig `json:"telegram"`
|
||||
Telegram TelegramConfig `json:"telegram"`
|
||||
|
||||
IrreversibleOnly bool `json:"irreversible_only"`
|
||||
MaxMessagesInFlight uint32 `json:"max_messages_in_flight"`
|
||||
StartBlockNum uint32 `json:"start_block_num"`
|
||||
EndBlockNum uint32 `json:"end_block_num"`
|
||||
IrreversibleOnly bool `json:"irreversible_only"`
|
||||
MaxMessagesInFlight uint32 `json:"max_messages_in_flight"`
|
||||
StartBlockNum uint32 `json:"start_block_num"`
|
||||
EndBlockNum uint32 `json:"end_block_num"`
|
||||
}
|
||||
|
||||
func Load(filename string) (Config, error) {
|
||||
cfg := Config{
|
||||
StartBlockNum: NULL_BLOCK_NUMBER,
|
||||
EndBlockNum: NULL_BLOCK_NUMBER,
|
||||
MaxMessagesInFlight: 10,
|
||||
IrreversibleOnly: false,
|
||||
Redis: RedisConfig{
|
||||
Addr: "localhost:6379",
|
||||
Password: "",
|
||||
DB: 0,
|
||||
},
|
||||
}
|
||||
|
||||
cfg := Config{
|
||||
StartBlockNum: NULL_BLOCK_NUMBER,
|
||||
EndBlockNum: NULL_BLOCK_NUMBER,
|
||||
MaxMessagesInFlight: 10,
|
||||
IrreversibleOnly: false,
|
||||
Redis: RedisConfig{
|
||||
Addr: "localhost:6379",
|
||||
Password: "",
|
||||
DB: 0,
|
||||
},
|
||||
}
|
||||
bytes, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
bytes, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
err = json.Unmarshal(bytes, &cfg)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(bytes, &cfg)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
return cfg, nil
|
||||
}
|
||||
|
|
|
|||
322
main.go
322
main.go
|
|
@ -1,20 +1,21 @@
|
|||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"context"
|
||||
"log"
|
||||
"time"
|
||||
"github.com/pborman/getopt/v2"
|
||||
"github.com/eosswedenorg-go/pid"
|
||||
"eosio-ship-trace-reader/config"
|
||||
"eosio-ship-trace-reader/redis"
|
||||
"eosio-ship-trace-reader/telegram"
|
||||
eos "github.com/eoscanada/eos-go"
|
||||
shipclient "github.com/eosswedenorg-go/eos-ship-client"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"eosio-ship-trace-reader/config"
|
||||
"eosio-ship-trace-reader/redis"
|
||||
"eosio-ship-trace-reader/telegram"
|
||||
|
||||
eos "github.com/eoscanada/eos-go"
|
||||
shipclient "github.com/eosswedenorg-go/eos-ship-client"
|
||||
"github.com/eosswedenorg-go/pid"
|
||||
"github.com/pborman/getopt/v2"
|
||||
)
|
||||
|
||||
// ---------------------------
|
||||
|
|
@ -27,191 +28,190 @@ var chainInfo *eos.InfoResp
|
|||
|
||||
var shClient *shipclient.ShipClient
|
||||
|
||||
var eosClient *eos.API
|
||||
var eosClientCtx = context.Background()
|
||||
|
||||
var (
|
||||
eosClient *eos.API
|
||||
eosClientCtx = context.Background()
|
||||
)
|
||||
|
||||
// Reader states
|
||||
const RS_CONNECT = 1
|
||||
const RS_READ = 2
|
||||
|
||||
func readerLoop() {
|
||||
state := RS_CONNECT
|
||||
var recon_cnt uint = 0
|
||||
|
||||
state := RS_CONNECT
|
||||
var recon_cnt uint = 0
|
||||
for {
|
||||
switch state {
|
||||
case RS_CONNECT:
|
||||
recon_cnt++
|
||||
log.Printf("Connecting to ship at: %s (Try %d)", conf.ShipApi, recon_cnt)
|
||||
err := shClient.Connect(conf.ShipApi)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
||||
for {
|
||||
switch state {
|
||||
case RS_CONNECT :
|
||||
recon_cnt++
|
||||
log.Printf("Connecting to ship at: %s (Try %d)", conf.ShipApi, recon_cnt)
|
||||
err := shClient.Connect(conf.ShipApi)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
if recon_cnt >= 3 {
|
||||
msg := fmt.Sprintf("Failed to connect to ship at '%s'", conf.ShipApi)
|
||||
if err = telegram.Send(msg); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
recon_cnt = 0
|
||||
}
|
||||
|
||||
if recon_cnt >= 3 {
|
||||
msg := fmt.Sprintf("Failed to connect to ship at '%s'", conf.ShipApi)
|
||||
if err = telegram.Send(msg); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
recon_cnt = 0
|
||||
}
|
||||
log.Printf("Trying again in 5 seconds ....")
|
||||
time.Sleep(5 * time.Second)
|
||||
break
|
||||
}
|
||||
|
||||
log.Printf("Trying again in 5 seconds ....")
|
||||
time.Sleep(5 * time.Second)
|
||||
break;
|
||||
}
|
||||
err = shClient.SendBlocksRequest()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
break
|
||||
}
|
||||
|
||||
err = shClient.SendBlocksRequest()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
break
|
||||
}
|
||||
// Connected
|
||||
log.Printf("Connected, Start: %d, End: %d", shClient.StartBlock, shClient.EndBlock)
|
||||
state = RS_READ
|
||||
recon_cnt = 0
|
||||
case RS_READ:
|
||||
err := shClient.Read()
|
||||
if err != nil {
|
||||
log.Print(err.Error())
|
||||
|
||||
// Connected
|
||||
log.Printf("Connected, Start: %d, End: %d", shClient.StartBlock, shClient.EndBlock)
|
||||
state = RS_READ
|
||||
recon_cnt = 0
|
||||
case RS_READ :
|
||||
err := shClient.Read()
|
||||
if err != nil {
|
||||
log.Print(err.Error())
|
||||
// Reconnect
|
||||
if err.Type == shipclient.ErrSockRead {
|
||||
state = RS_CONNECT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reconnect
|
||||
if err.Type == shipclient.ErrSockRead {
|
||||
state = RS_CONNECT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shClient.Close()
|
||||
shClient.Close()
|
||||
}
|
||||
|
||||
func run() {
|
||||
// Create done and interrupt channels.
|
||||
done := make(chan bool)
|
||||
interrupt := make(chan os.Signal, 1)
|
||||
|
||||
// Create done and interrupt channels.
|
||||
done := make(chan bool)
|
||||
interrupt := make(chan os.Signal, 1)
|
||||
// Register interrupt channel to receive interrupt messages
|
||||
signal.Notify(interrupt, os.Interrupt)
|
||||
|
||||
// Register interrupt channel to receive interrupt messages
|
||||
signal.Notify(interrupt, os.Interrupt)
|
||||
// Spawn message read loop in another thread.
|
||||
go func() {
|
||||
readerLoop()
|
||||
|
||||
// Spawn message read loop in another thread.
|
||||
go func() {
|
||||
readerLoop()
|
||||
// Reader exited. signal that we are done.
|
||||
done <- true
|
||||
}()
|
||||
|
||||
// Reader exited. signal that we are done.
|
||||
done <- true
|
||||
}()
|
||||
// Enter event loop in main thread
|
||||
for {
|
||||
select {
|
||||
case <-interrupt:
|
||||
log.Println("Interrupt, closing")
|
||||
|
||||
// Enter event loop in main thread
|
||||
for {
|
||||
select {
|
||||
case <-interrupt:
|
||||
log.Println("Interrupt, closing")
|
||||
if shClient.IsOpen() == false {
|
||||
log.Println("ship client not connected, exiting...")
|
||||
return
|
||||
}
|
||||
|
||||
if shClient.IsOpen() == false {
|
||||
log.Println("ship client not connected, exiting...")
|
||||
return
|
||||
}
|
||||
// Cleanly close the connection by sending a close message and then
|
||||
// waiting (with timeout) for the server to close the connection.
|
||||
shClient.SendCloseMessage()
|
||||
|
||||
// Cleanly close the connection by sending a close message and then
|
||||
// waiting (with timeout) for the server to close the connection.
|
||||
shClient.SendCloseMessage()
|
||||
|
||||
select {
|
||||
case <-done: log.Println("Closed")
|
||||
case <-time.After(time.Second * 10): log.Println("Timeout");
|
||||
}
|
||||
return
|
||||
case <-done:
|
||||
log.Println("Closed")
|
||||
return
|
||||
}
|
||||
}
|
||||
select {
|
||||
case <-done:
|
||||
log.Println("Closed")
|
||||
case <-time.After(time.Second * 10):
|
||||
log.Println("Timeout")
|
||||
}
|
||||
return
|
||||
case <-done:
|
||||
log.Println("Closed")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
|
||||
var err error
|
||||
showHelp := getopt.BoolLong("help", 'h', "display this help text")
|
||||
showVersion := getopt.BoolLong("version", 'v', "display this help text")
|
||||
configFile := getopt.StringLong("config", 'c', "./config.json", "Config file to read", "file")
|
||||
pidFile := getopt.StringLong("pid", 'p', "", "Where to write process id", "file")
|
||||
|
||||
showHelp := getopt.BoolLong("help", 'h', "display this help text")
|
||||
showVersion := getopt.BoolLong("version", 'v', "display this help text")
|
||||
configFile := getopt.StringLong("config", 'c', "./config.json", "Config file to read", "file")
|
||||
pidFile := getopt.StringLong("pid", 'p', "", "Where to write process id", "file")
|
||||
getopt.Parse()
|
||||
|
||||
getopt.Parse()
|
||||
if *showHelp {
|
||||
getopt.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
if *showHelp {
|
||||
getopt.Usage()
|
||||
return
|
||||
}
|
||||
if *showVersion {
|
||||
fmt.Println("v0.0.0")
|
||||
return
|
||||
}
|
||||
|
||||
if *showVersion {
|
||||
fmt.Println("v0.0.0")
|
||||
return
|
||||
}
|
||||
// Write PID file
|
||||
if len(*pidFile) > 0 {
|
||||
log.Printf("Writing pid to: %s", *pidFile)
|
||||
err = pid.Save(*pidFile)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Write PID file
|
||||
if len(*pidFile) > 0 {
|
||||
log.Printf("Writing pid to: %s", *pidFile)
|
||||
err = pid.Save(*pidFile)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
// Parse config
|
||||
conf, err = config.Load(*configFile)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Parse config
|
||||
conf, err = config.Load(*configFile)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
// Init telegram
|
||||
err = telegram.Init(conf.Name, conf.Telegram.Id, conf.Telegram.Channel)
|
||||
if err != nil {
|
||||
log.Println("Failed to initialize telegram", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Init telegram
|
||||
err = telegram.Init(conf.Name, conf.Telegram.Id, conf.Telegram.Channel)
|
||||
if err != nil {
|
||||
log.Println("Failed to initialize telegram", err)
|
||||
return
|
||||
}
|
||||
// Connect to redis
|
||||
err = redis.Connect(conf.Redis.Addr, conf.Redis.Password, conf.Redis.DB)
|
||||
if err != nil {
|
||||
log.Println("Failed to connect to redis:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Connect to redis
|
||||
err = redis.Connect(conf.Redis.Addr, conf.Redis.Password, conf.Redis.DB)
|
||||
if err != nil {
|
||||
log.Println("Failed to connect to redis:", err)
|
||||
return
|
||||
}
|
||||
// Init Abi cache
|
||||
InitAbiCache(conf.Redis.CacheID)
|
||||
|
||||
// Init Abi cache
|
||||
InitAbiCache(conf.Redis.CacheID)
|
||||
// Connect client and get chain info.
|
||||
log.Printf("Get chain info from api at: %s", conf.Api)
|
||||
eosClient = eos.New(conf.Api)
|
||||
chainInfo, err = eosClient.GetInfo(eosClientCtx)
|
||||
if err != nil {
|
||||
log.Println("Failed to get info:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Connect client and get chain info.
|
||||
log.Printf("Get chain info from api at: %s", conf.Api)
|
||||
eosClient = eos.New(conf.Api)
|
||||
chainInfo, err = eosClient.GetInfo(eosClientCtx)
|
||||
if err != nil {
|
||||
log.Println("Failed to get info:", err)
|
||||
return
|
||||
}
|
||||
redis.Prefix += chainInfo.ChainID.String() + "."
|
||||
|
||||
redis.Prefix += chainInfo.ChainID.String() + "."
|
||||
if conf.StartBlockNum == config.NULL_BLOCK_NUMBER {
|
||||
if conf.IrreversibleOnly {
|
||||
conf.StartBlockNum = uint32(chainInfo.LastIrreversibleBlockNum)
|
||||
} else {
|
||||
conf.StartBlockNum = uint32(chainInfo.HeadBlockNum)
|
||||
}
|
||||
}
|
||||
|
||||
if conf.StartBlockNum == config.NULL_BLOCK_NUMBER {
|
||||
// Construct ship client
|
||||
shClient = shipclient.NewClient(conf.StartBlockNum, conf.EndBlockNum, conf.IrreversibleOnly)
|
||||
shClient.BlockHandler = processBlock
|
||||
shClient.TraceHandler = processTraces
|
||||
|
||||
if conf.IrreversibleOnly {
|
||||
conf.StartBlockNum = uint32(chainInfo.LastIrreversibleBlockNum)
|
||||
} else {
|
||||
conf.StartBlockNum = uint32(chainInfo.HeadBlockNum)
|
||||
}
|
||||
}
|
||||
|
||||
// Construct ship client
|
||||
shClient = shipclient.NewClient(conf.StartBlockNum, conf.EndBlockNum, conf.IrreversibleOnly)
|
||||
shClient.BlockHandler = processBlock
|
||||
shClient.TraceHandler = processTraces
|
||||
|
||||
// Run the application
|
||||
run()
|
||||
// Run the application
|
||||
run()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
|
||||
package redis
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"context"
|
||||
"time"
|
||||
_redis "github.com/go-redis/redis/v8"
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_redis "github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
var rdb *_redis.Client
|
||||
|
|
@ -17,41 +17,41 @@ var redisCtx = context.Background()
|
|||
var Prefix = "ship."
|
||||
|
||||
func Connect(addr string, password string, db int) error {
|
||||
rdb = _redis.NewClient(&_redis.Options{
|
||||
Addr: addr,
|
||||
Password: password,
|
||||
DB: db,
|
||||
})
|
||||
rdb = _redis.NewClient(&_redis.Options{
|
||||
Addr: addr,
|
||||
Password: password,
|
||||
DB: db,
|
||||
})
|
||||
|
||||
redis_pipe = rdb.Pipeline()
|
||||
redis_pipe = rdb.Pipeline()
|
||||
|
||||
return rdb.Ping(redisCtx).Err()
|
||||
return rdb.Ping(redisCtx).Err()
|
||||
}
|
||||
|
||||
func Client() *_redis.Client {
|
||||
return rdb
|
||||
return rdb
|
||||
}
|
||||
|
||||
func Key(components ...string) (string) {
|
||||
return Prefix + strings.Join(components, ".")
|
||||
func Key(components ...string) string {
|
||||
return Prefix + strings.Join(components, ".")
|
||||
}
|
||||
|
||||
func Get(key string) (*_redis.StringCmd) {
|
||||
return rdb.Get(redisCtx, key)
|
||||
func Get(key string) *_redis.StringCmd {
|
||||
return rdb.Get(redisCtx, key)
|
||||
}
|
||||
|
||||
func Set(key string, value interface{}, expiration time.Duration) (*_redis.StatusCmd) {
|
||||
return rdb.Set(redisCtx, key, value, expiration)
|
||||
func Set(key string, value interface{}, expiration time.Duration) *_redis.StatusCmd {
|
||||
return rdb.Set(redisCtx, key, value, expiration)
|
||||
}
|
||||
|
||||
func Publish(channel string, message interface{}) (*_redis.IntCmd) {
|
||||
return rdb.Publish(redisCtx, channel, message)
|
||||
func Publish(channel string, message interface{}) *_redis.IntCmd {
|
||||
return rdb.Publish(redisCtx, channel, message)
|
||||
}
|
||||
|
||||
func RegisterPublish(channel string, message interface{}) (*_redis.IntCmd) {
|
||||
return redis_pipe.Publish(redisCtx, channel, message)
|
||||
func RegisterPublish(channel string, message interface{}) *_redis.IntCmd {
|
||||
return redis_pipe.Publish(redisCtx, channel, message)
|
||||
}
|
||||
|
||||
func Send() ([]_redis.Cmder, error) {
|
||||
return redis_pipe.Exec(redisCtx)
|
||||
return redis_pipe.Exec(redisCtx)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,78 +1,75 @@
|
|||
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"encoding/json"
|
||||
"github.com/eoscanada/eos-go/ship"
|
||||
"eosio-ship-trace-reader/redis"
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"eosio-ship-trace-reader/redis"
|
||||
"github.com/eoscanada/eos-go/ship"
|
||||
)
|
||||
|
||||
func processBlock(block *ship.GetBlocksResultV0) {
|
||||
|
||||
if block.ThisBlock.BlockNum % 100 == 0 {
|
||||
log.Printf("Current: %d, Head: %d\n", block.ThisBlock.BlockNum, block.Head.BlockNum)
|
||||
}
|
||||
if block.ThisBlock.BlockNum%100 == 0 {
|
||||
log.Printf("Current: %d, Head: %d\n", block.ThisBlock.BlockNum, block.Head.BlockNum)
|
||||
}
|
||||
}
|
||||
|
||||
func processTraces(traces []*ship.TransactionTraceV0) {
|
||||
for _, trace := range traces {
|
||||
|
||||
for _, trace := range traces {
|
||||
payload, err := json.Marshal(trace)
|
||||
if err == nil {
|
||||
channel := redis.Key("transactions")
|
||||
if err := redis.Publish(channel, payload).Err(); err != nil {
|
||||
log.Printf("Failed to post to channel '%s': %s", channel, err)
|
||||
}
|
||||
} else {
|
||||
log.Println("Failed to encode transaction:", err)
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(trace)
|
||||
if err == nil {
|
||||
channel := redis.Key("transactions")
|
||||
if err := redis.Publish(channel, payload).Err(); err != nil {
|
||||
log.Printf("Failed to post to channel '%s': %s", channel, err)
|
||||
}
|
||||
} else {
|
||||
log.Println("Failed to encode transaction:", err)
|
||||
}
|
||||
// Actions
|
||||
for _, actionTraceVar := range trace.ActionTraces {
|
||||
trace := actionTraceVar.Impl.(*ship.ActionTraceV0)
|
||||
|
||||
// Actions
|
||||
for _, actionTraceVar := range trace.ActionTraces {
|
||||
trace := actionTraceVar.Impl.(*ship.ActionTraceV0)
|
||||
act := ActionTrace{
|
||||
Receiver: trace.Receiver,
|
||||
Contract: trace.Act.Account,
|
||||
Action: trace.Act.Name,
|
||||
}
|
||||
|
||||
act := ActionTrace{
|
||||
Receiver: trace.Receiver,
|
||||
Contract: trace.Act.Account,
|
||||
Action: trace.Act.Name,
|
||||
}
|
||||
abi, err := GetAbi(trace.Act.Account)
|
||||
if err == nil {
|
||||
v, err := DecodeAction(abi, trace.Act.Data, trace.Act.Name)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
act.Data = v
|
||||
} else {
|
||||
log.Printf("Failed to get abi for contract %s: %s\n", trace.Act.Account, err)
|
||||
}
|
||||
|
||||
abi, err := GetAbi(trace.Act.Account)
|
||||
if err == nil {
|
||||
v, err := DecodeAction(abi, trace.Act.Data, trace.Act.Name)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
act.Data = v
|
||||
} else {
|
||||
log.Printf("Failed to get abi for contract %s: %s\n", trace.Act.Account, err)
|
||||
}
|
||||
payload, err := json.Marshal(act)
|
||||
if err != nil {
|
||||
log.Println("Failed to encode action:", err)
|
||||
continue
|
||||
}
|
||||
|
||||
channels := []string{
|
||||
redis.Key("actions"),
|
||||
redis.Key(string(act.Contract), "actions"),
|
||||
redis.Key(string(act.Contract), "actions", string(act.Action)),
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(act)
|
||||
if err != nil {
|
||||
log.Println("Failed to encode action:", err)
|
||||
continue
|
||||
}
|
||||
for _, channel := range channels {
|
||||
if err := redis.RegisterPublish(channel, payload).Err(); err != nil {
|
||||
log.Printf("Failed to post to channel '%s': %s", channel, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
channels := []string{
|
||||
redis.Key("actions"),
|
||||
redis.Key(string(act.Contract), "actions"),
|
||||
redis.Key(string(act.Contract), "actions", string(act.Action)),
|
||||
}
|
||||
|
||||
for _, channel := range channels {
|
||||
if err := redis.RegisterPublish(channel, payload).Err(); err != nil {
|
||||
log.Printf("Failed to post to channel '%s': %s", channel, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err := redis.Send()
|
||||
if err != nil {
|
||||
log.Println("Failed to send redis. command:", err)
|
||||
}
|
||||
_, err := redis.Send()
|
||||
if err != nil {
|
||||
log.Println("Failed to send redis. command:", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,30 @@
|
|||
|
||||
package telegram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
_api "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
"fmt"
|
||||
|
||||
_api "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
var _bot *_api.BotAPI
|
||||
var _channel int64
|
||||
var _prefix string
|
||||
var (
|
||||
_bot *_api.BotAPI
|
||||
_channel int64
|
||||
_prefix string
|
||||
)
|
||||
|
||||
func Init(prefix string, id string, channel int64) (error) {
|
||||
func Init(prefix string, id string, channel int64) error {
|
||||
var err error
|
||||
|
||||
var err error
|
||||
|
||||
_bot, err = _api.NewBotAPI(id)
|
||||
if err == nil {
|
||||
_prefix = prefix
|
||||
_channel = channel
|
||||
}
|
||||
return err
|
||||
_bot, err = _api.NewBotAPI(id)
|
||||
if err == nil {
|
||||
_prefix = prefix
|
||||
_channel = channel
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func Send(message string) (error) {
|
||||
msg := _api.NewMessage(_channel, fmt.Sprintf("%s: %s", _prefix, message))
|
||||
_, err := _bot.Send(msg);
|
||||
return err
|
||||
func Send(message string) error {
|
||||
msg := _api.NewMessage(_channel, fmt.Sprintf("%s: %s", _prefix, message))
|
||||
_, err := _bot.Send(msg)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
11
types.go
11
types.go
|
|
@ -1,13 +1,12 @@
|
|||
|
||||
package main
|
||||
|
||||
import (
|
||||
eos "github.com/eoscanada/eos-go"
|
||||
eos "github.com/eoscanada/eos-go"
|
||||
)
|
||||
|
||||
type ActionTrace struct {
|
||||
Receiver eos.Name `json:"receiver"`
|
||||
Contract eos.AccountName `json:"contract"`
|
||||
Action eos.ActionName `json:"action"`
|
||||
Data interface{} `json:"data"`
|
||||
Receiver eos.Name `json:"receiver"`
|
||||
Contract eos.AccountName `json:"contract"`
|
||||
Action eos.ActionName `json:"action"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue