-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
183 lines (161 loc) · 5.71 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package main
import (
log "github.com/sirupsen/logrus"
"os"
"polymorphs-rarity-v1/config"
"polymorphs-rarity-v1/dlt"
"polymorphs-rarity-v1/handlers"
"polymorphs-rarity-v1/services"
"polymorphs-rarity-v1/store"
"polymorphs-rarity-v1/structs"
"strings"
"time"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/gofiber/fiber"
"github.com/joho/godotenv"
)
func connectToEthereum() (*dlt.EthereumClient, error) {
log.SetFormatter(&log.TextFormatter{
FullTimestamp: true,
TimestampFormat: "2006-01-02 15:04:05",
})
nodeURL := os.Getenv("NODE_URL_ETHEREUM")
client, err := dlt.NewEthereumClient(nodeURL)
if err != nil {
return nil, err
}
log.Infof("Successfully connected to ethereum client")
return client, nil
}
// initResources is a wrapper function which tries to initialize all .env variables, contract abi, new contract instance.
//
// It connects to the ethereum client and returns all information which will be needed at some point from the application
func initResources() (*dlt.EthereumClient, abi.ABI, *store.Store, string, *structs.ConfigService, structs.DBInfo) {
// Load env variables
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file: " + err.Error())
}
log.SetFormatter(&log.TextFormatter{
FullTimestamp: true,
TimestampFormat: "2006-01-02 15:04:05",
})
// Inital step: Recover to be up to date
ethClient, err := connectToEthereum()
if err != nil {
log.Error("Error connecting to Ethereum node")
}
polymorphDBName := os.Getenv("POLYMORPH_DB")
rarityCollectionName := os.Getenv("RARITY_COLLECTION")
blocksCollectionName := os.Getenv("BLOCKS_COLLECTION")
contractAddress := os.Getenv("CONTRACT_ADDRESS")
transactionsCollectionName := os.Getenv("TRANSACTIONS_COLLECTION")
historyCollectionName := os.Getenv("HISTORY_COLLECTION")
morphCostCollectionName := os.Getenv("MORPH_COST_COLLECTION")
if contractAddress == "" {
log.Fatal("Missing contract address in .env")
}
if polymorphDBName == "" {
log.Fatal("Missing polymorph db name in .env")
}
if rarityCollectionName == "" {
log.Fatal("Missing rarity collection name in .env")
}
if blocksCollectionName == "" {
log.Fatal("Missing block collection name in .env")
}
if transactionsCollectionName == "" {
log.Fatal("Missing transactions collection name in .env")
}
if historyCollectionName == "" {
log.Fatal("Missing morph history collection name in .env")
}
if morphCostCollectionName == "" {
log.Fatal("Missing morph cost collection name in .env")
}
contractAbi, err := abi.JSON(strings.NewReader(string(store.PolymorphRootMetaData.ABI)))
if err != nil {
log.Fatal(err)
}
instance, err := store.NewStore(common.HexToAddress(contractAddress), ethClient.Client)
if err != nil {
log.Fatalln(err)
}
configService := config.NewConfigService("./config.json")
dbInfo := structs.DBInfo{
PolymorphDBName: polymorphDBName,
RarityCollectionName: rarityCollectionName,
TransactionsCollectionName: transactionsCollectionName,
BlocksCollectionName: blocksCollectionName,
HistoryCollectionName: historyCollectionName,
MorphCostCollectionName: morphCostCollectionName,
}
return ethClient, contractAbi, instance, contractAddress, configService, dbInfo
}
// main is the entry point of the application.
// It fetches all configurations and starts 2 concurrent processes:
//
// 1. API which handles GET requests
//
// 2. Polling process which processes mint and morph events and stores their metadata in the database
func main() {
ethClient,
contractAbi,
instance,
contractAddress,
configService,
dbInfo := initResources()
recoverAndPoll(
ethClient,
contractAbi,
instance,
contractAddress,
configService,
dbInfo)
//startAPI()
}
// startAPI registers the endpoints for API and listens for requests
// API has moved to a cloud function due to bad response times
func startAPI() {
// Routine two: API -> Should start after deploy?
app := fiber.New()
// app.Get("/morphs/", handlers.GetPolymorphs)
// app.Get("/morphs/:id", handlers.GetPolymorphById)
// app.Get("/morphs/history/:id", handlers.GetPolymorphHistory)
apiPORT := os.Getenv("API_PORT")
log.Fatal(app.Listen(apiPORT))
}
// recoverAndPoll loads transactions and morph cost state in memory from the database and initiates polling mechanism.
//
// Recovery function and polling function is the same.
// Currently the polling timer doesn't wait for the previous one to finish before starting the new countdown
func recoverAndPoll(ethClient *dlt.EthereumClient, contractAbi abi.ABI, store *store.Store, contractAddress string, configService *structs.ConfigService, dbInfo structs.DBInfo) {
// Build transactions scramble transaction mapping from db
txMap, err := handlers.GetTransactionsMapping(dbInfo.PolymorphDBName, dbInfo.TransactionsCollectionName)
if err != nil {
log.Infoln("Error getting transactions mapping initially.")
}
// Build polymorph cost mapping from db
morphCostMap, err := handlers.GetMorphPriceMapping(dbInfo.PolymorphDBName, dbInfo.HistoryCollectionName)
if err != nil {
log.Infoln("Error getting morph prices mapping initially.")
}
// Recover immediately
// services.RecoverProcess(ethClient, contractAbi, store, contractAddress, configService, dbInfo, txMap, morphCostMap)
// Routine one: Start polling after recovery
log.SetFormatter(&log.TextFormatter{
FullTimestamp: true,
TimestampFormat: "2006-01-02 15:04:05",
})
for {
err = services.RecoverProcess(ethClient, contractAbi, store, contractAddress, configService, dbInfo, txMap, morphCostMap)
if err != nil {
log.WithFields(log.Fields{"error: ": err}).Error("Recovering from error...")
time.Sleep(15 * time.Second)
continue
} else {
time.Sleep(15 * time.Second)
}
}
}