commit
483175ace2
@ -1,158 +0,0 @@ |
||||
package explorer_test |
||||
|
||||
// http://www.golangprograms.com/golang-restful-api-using-grom-and-gorilla-mux.html
|
||||
// https://dev.to/codehakase/building-a-restful-api-with-go
|
||||
// https://thenewstack.io/make-a-restful-json-api-go/
|
||||
// https://medium.com/@kelvin_sp/building-and-testing-a-rest-api-in-golang-using-gorilla-mux-and-mysql-1f0518818ff6
|
||||
// var a App
|
||||
|
||||
// func TestMain(m *testing.M) {
|
||||
// a = App{}
|
||||
// a.Initialize("root", "", "rest_api_example")
|
||||
|
||||
// ensureTableExists()
|
||||
|
||||
// code := m.Run()
|
||||
|
||||
// clearTable()
|
||||
|
||||
// os.Exit(code)
|
||||
// }
|
||||
|
||||
// func ensureTableExists() {
|
||||
// if _, err := a.DB.Exec(tableCreationQuery); err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// func clearTable() {
|
||||
// a.DB.Exec("DELETE FROM users")
|
||||
// a.DB.Exec("ALTER TABLE users AUTO_INCREMENT = 1")
|
||||
// }
|
||||
|
||||
// func executeRequest(req *http.Request) *httptest.ResponseRecorder {
|
||||
// rr := httptest.NewRecorder()
|
||||
// a.Router.ServeHTTP(rr, req)
|
||||
|
||||
// return rr
|
||||
// }
|
||||
|
||||
// func checkResponseCode(t *testing.T, expected, actual int) {
|
||||
// if expected != actual {
|
||||
// t.Errorf("Expected response code %d. Got %d\n", expected, actual)
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestGetNonExistentUser(t *testing.T) {
|
||||
// clearTable()
|
||||
|
||||
// req, _ := http.NewRequest("GET", "/user/45", nil)
|
||||
// response := executeRequest(req)
|
||||
|
||||
// checkResponseCode(t, http.StatusNotFound, response.Code)
|
||||
|
||||
// var m map[string]string
|
||||
// json.Unmarshal(response.Body.Bytes(), &m)
|
||||
// if m["error"] != "User not found" {
|
||||
// t.Errorf("Expected the 'error' key of the response to be set to 'User not found'. Got '%s'", m["error"])
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestCreateUser(t *testing.T) {
|
||||
// clearTable()
|
||||
|
||||
// payload := []byte(`{"name":"test user","age":30}`)
|
||||
|
||||
// req, _ := http.NewRequest("POST", "/user", bytes.NewBuffer(payload))
|
||||
// response := executeRequest(req)
|
||||
|
||||
// checkResponseCode(t, http.StatusCreated, response.Code)
|
||||
|
||||
// var m map[string]interface{}
|
||||
// json.Unmarshal(response.Body.Bytes(), &m)
|
||||
|
||||
// if m["name"] != "test user" {
|
||||
// t.Errorf("Expected user name to be 'test user'. Got '%v'", m["name"])
|
||||
// }
|
||||
|
||||
// if m["age"] != 30.0 {
|
||||
// t.Errorf("Expected user age to be '30'. Got '%v'", m["age"])
|
||||
// }
|
||||
|
||||
// // the id is compared to 1.0 because JSON unmarshaling converts numbers to
|
||||
// // floats, when the target is a map[string]interface{}
|
||||
// if m["id"] != 1.0 {
|
||||
// t.Errorf("Expected product ID to be '1'. Got '%v'", m["id"])
|
||||
// }
|
||||
// }
|
||||
|
||||
// func addUsers(count int) {
|
||||
// if count < 1 {
|
||||
// count = 1
|
||||
// }
|
||||
|
||||
// for i := 0; i < count; i++ {
|
||||
// statement := fmt.Sprintf("INSERT INTO users(name, age) VALUES('%s', %d)", ("User " + strconv.Itoa(i+1)), ((i + 1) * 10))
|
||||
// a.DB.Exec(statement)
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestGetUser(t *testing.T) {
|
||||
// clearTable()
|
||||
// addUsers(1)
|
||||
|
||||
// req, _ := http.NewRequest("GET", "/user/1", nil)
|
||||
// response := executeRequest(req)
|
||||
|
||||
// checkResponseCode(t, http.StatusOK, response.Code)
|
||||
// }
|
||||
|
||||
// func TestUpdateUser(t *testing.T) {
|
||||
// clearTable()
|
||||
// addUsers(1)
|
||||
|
||||
// req, _ := http.NewRequest("GET", "/user/1", nil)
|
||||
// response := executeRequest(req)
|
||||
// var originalUser map[string]interface{}
|
||||
// json.Unmarshal(response.Body.Bytes(), &originalUser)
|
||||
|
||||
// payload := []byte(`{"name":"test user - updated name","age":21}`)
|
||||
|
||||
// req, _ = http.NewRequest("PUT", "/user/1", bytes.NewBuffer(payload))
|
||||
// response = executeRequest(req)
|
||||
|
||||
// checkResponseCode(t, http.StatusOK, response.Code)
|
||||
|
||||
// var m map[string]interface{}
|
||||
// json.Unmarshal(response.Body.Bytes(), &m)
|
||||
|
||||
// if m["id"] != originalUser["id"] {
|
||||
// t.Errorf("Expected the id to remain the same (%v). Got %v", originalUser["id"], m["id"])
|
||||
// }
|
||||
|
||||
// if m["name"] == originalUser["name"] {
|
||||
// t.Errorf("Expected the name to change from '%v' to '%v'. Got '%v'", originalUser["name"], m["name"], m["name"])
|
||||
// }
|
||||
|
||||
// if m["age"] == originalUser["age"] {
|
||||
// t.Errorf("Expected the age to change from '%v' to '%v'. Got '%v'", originalUser["age"], m["age"], m["age"])
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestDeleteUser(t *testing.T) {
|
||||
// clearTable()
|
||||
// addUsers(1)
|
||||
|
||||
// req, _ := http.NewRequest("GET", "/user/1", nil)
|
||||
// response := executeRequest(req)
|
||||
// checkResponseCode(t, http.StatusOK, response.Code)
|
||||
|
||||
// req, _ = http.NewRequest("DELETE", "/user/1", nil)
|
||||
// response = executeRequest(req)
|
||||
|
||||
// checkResponseCode(t, http.StatusOK, response.Code)
|
||||
|
||||
// req, _ = http.NewRequest("GET", "/user/1", nil)
|
||||
// response = executeRequest(req)
|
||||
// checkResponseCode(t, http.StatusNotFound, response.Code)
|
||||
// }
|
@ -0,0 +1,118 @@ |
||||
package explorer |
||||
|
||||
import ( |
||||
"fmt" |
||||
"os" |
||||
"strconv" |
||||
"sync" |
||||
|
||||
"github.com/ethereum/go-ethereum/rlp" |
||||
"github.com/harmony-one/harmony/core/types" |
||||
"github.com/harmony-one/harmony/db" |
||||
) |
||||
|
||||
// Constants for storage.
|
||||
const ( |
||||
BlockHeightKey = "bh" |
||||
BlockInfoPrefix = "bi" |
||||
BlockPrefix = "b" |
||||
TXPrefix = "tx" |
||||
) |
||||
|
||||
// GetBlockInfoKey ...
|
||||
func GetBlockInfoKey(id int) string { |
||||
return fmt.Sprintf("%s_%d", BlockInfoPrefix, id) |
||||
} |
||||
|
||||
// GetBlockKey ...
|
||||
func GetBlockKey(id int) string { |
||||
return fmt.Sprintf("%s_%d", BlockPrefix, id) |
||||
} |
||||
|
||||
// GetTXKey ...
|
||||
func GetTXKey(hash string) string { |
||||
return fmt.Sprintf("%s_%s", TXPrefix, hash) |
||||
} |
||||
|
||||
var storage *Storage |
||||
var once sync.Once |
||||
|
||||
// Storage dump the block info into leveldb.
|
||||
type Storage struct { |
||||
db *db.LDBDatabase |
||||
} |
||||
|
||||
// GetStorageInstance returns attack model by using singleton pattern.
|
||||
func GetStorageInstance(ip, port string, remove bool) *Storage { |
||||
once.Do(func() { |
||||
storage = &Storage{} |
||||
storage.Init(ip, port, remove) |
||||
}) |
||||
return storage |
||||
} |
||||
|
||||
// Init initializes the block update.
|
||||
func (storage *Storage) Init(ip, port string, remove bool) { |
||||
dbFileName := "/tmp/explorer_storage_" + ip + "_" + port |
||||
var err error |
||||
if remove { |
||||
var err = os.RemoveAll(dbFileName) |
||||
if err != nil { |
||||
fmt.Println(err.Error()) |
||||
} |
||||
} |
||||
if storage.db, err = db.NewLDBDatabase(dbFileName, 0, 0); err != nil { |
||||
fmt.Println(err.Error()) |
||||
os.Exit(1) |
||||
} |
||||
} |
||||
|
||||
// GetDB returns the LDBDatabase of the storage.
|
||||
func (storage *Storage) GetDB() *db.LDBDatabase { |
||||
return storage.db |
||||
} |
||||
|
||||
// Dump extracts information from block and index them into lvdb for explorer.
|
||||
func (storage *Storage) Dump(accountBlock []byte, height uint32) { |
||||
fmt.Println("Dumping block ", height) |
||||
if accountBlock == nil { |
||||
return |
||||
} |
||||
// Update block height.
|
||||
storage.db.Put([]byte(BlockHeightKey), []byte(strconv.Itoa(int(height)))) |
||||
|
||||
// Store block.
|
||||
block := new(types.Block) |
||||
rlp.DecodeBytes(accountBlock, block) |
||||
storage.db.Put([]byte(GetBlockKey(int(height))), accountBlock) |
||||
|
||||
// Store block info.
|
||||
blockInfo := BlockInfo{ |
||||
ID: block.Hash().Hex(), |
||||
Height: string(height), |
||||
Timestamp: string(block.Time().Int64()), |
||||
TXCount: string(block.Transactions().Len()), |
||||
Size: block.Size().String(), |
||||
} |
||||
|
||||
if data, err := rlp.EncodeToBytes(blockInfo); err == nil { |
||||
key := GetBlockInfoKey(int(height)) |
||||
fmt.Println("store blockinfo with key ", key) |
||||
fmt.Println("data to store ", data) |
||||
storage.db.Put([]byte(key), data) |
||||
} else { |
||||
fmt.Println("EncodeRLP blockInfo error") |
||||
os.Exit(1) |
||||
} |
||||
|
||||
// Store txs
|
||||
for _, tx := range block.Transactions() { |
||||
if data, err := rlp.EncodeToBytes(tx); err == nil { |
||||
key := GetTXKey(tx.Hash().Hex()) |
||||
storage.db.Put([]byte(key), data) |
||||
} else { |
||||
fmt.Println("EncodeRLP transaction error") |
||||
os.Exit(1) |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue