Skip to content
Snippets Groups Projects
Unverified Commit 3f7ac60e authored by Luca Moser's avatar Luca Moser Committed by GitHub
Browse files

Adds a client lib as a wrapper for the HTTP API (#118)

* :art: moves all webapi into one

* :art: adds public key log

* :art: changes txRequest to getTrytes

* :art: rename packages

* :pencil: adds comments

* :art: changes status to error

* :recycle: removes duration from API - getTrytes converts trits to trytes - set default spammer TPS to 1

Fix: Allow starting a node with gossip disabled (#97)

* fix: remove selection flag and use gossip plugin

* Upgrade hive.go

feat: improve logging

feat: improve analysis status

chore: remove unused packages (#99)

Fix: Use docker specific config (#100)

* Use docker specific config

* Format JSON

:heavy_minus_sign: removes status

:art: adds omitempty

:lipstick: updates style import

:sparkles: adds getNeighbors API

:sparkles: adds getTransaction

:heavy_minus_sign: removes addEndpoint

* ports glumb plugin from Hornet to GoShimmer

* :construction:

 WIP

* implements HTTP API wrapper client lib

* removes empty lines

* clean line in autopeering

* normalize client lib imports

Co-authored-by: default avatarAngelo Capossele <angelocapossele@gmail.com>
parent c0fc4fc0
No related branches found
No related tags found
No related merge requests found
// Implements a very simple wrapper for GoShimmer's HTTP API .
package shimmer
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"github.com/iotaledger/goshimmer/packages/errors"
webapi_broadcastData "github.com/iotaledger/goshimmer/plugins/webapi/broadcastData"
webapi_findTransactions "github.com/iotaledger/goshimmer/plugins/webapi/findTransactions"
webapi_getNeighbors "github.com/iotaledger/goshimmer/plugins/webapi/getNeighbors"
webapi_getTransactions "github.com/iotaledger/goshimmer/plugins/webapi/getTransactions"
webapi_getTrytes "github.com/iotaledger/goshimmer/plugins/webapi/getTrytes"
webapi_gtta "github.com/iotaledger/goshimmer/plugins/webapi/gtta"
webapi_spammer "github.com/iotaledger/goshimmer/plugins/webapi/spammer"
"github.com/iotaledger/iota.go/consts"
"github.com/iotaledger/iota.go/guards"
"github.com/iotaledger/iota.go/trinary"
)
var (
ErrBadRequest = errors.New("bad request")
ErrInternalServerError = errors.New("internal server error")
ErrNotFound = errors.New("not found")
ErrUnknownError = errors.New("unknown error")
)
const (
routeBroadcastData = "broadcastData"
routeGetTrytes = "getTrytes"
routeGetTransactions = "getTransactions"
routeFindTransactions = "findTransactions"
routeGetNeighbors = "getNeighbors"
routeGetTransactionsToApprove = "getTransactionsToApprove"
routeSpammer = "spammer"
contentTypeJSON = "application/json"
)
func NewShimmerAPI(node string) *ShimmerAPI {
return &ShimmerAPI{node: node}
}
type ShimmerAPI struct {
http.Client
node string
}
type errorresponse struct {
Error string `json:"error"`
}
func interpretBody(res *http.Response, decodeTo interface{}) error {
resBody, err := ioutil.ReadAll(res.Body)
if err != nil {
return errors.Wrap(err, "unable to read response body")
}
defer res.Body.Close()
if res.StatusCode == http.StatusOK {
return json.Unmarshal(resBody, decodeTo)
}
errRes := &errorresponse{}
if err := json.Unmarshal(resBody, errRes); err != nil {
return errors.Wrap(err, "unable to read error from response body")
}
switch res.StatusCode {
case http.StatusInternalServerError:
return errors.Wrap(ErrInternalServerError, errRes.Error)
case http.StatusNotFound:
return errors.Wrap(ErrNotFound, errRes.Error)
case http.StatusBadRequest:
return errors.Wrap(ErrBadRequest, errRes.Error)
}
return errors.Wrap(ErrUnknownError, errRes.Error)
}
func (api *ShimmerAPI) BroadcastData(targetAddress trinary.Trytes, data trinary.Trytes) (trinary.Hash, error) {
if !guards.IsHash(targetAddress) {
return "", errors.Wrapf(consts.ErrInvalidHash, "invalid address: %s", targetAddress)
}
if !guards.IsTrytes(data) {
return "", errors.Wrapf(consts.ErrInvalidTrytes, "invalid trytes: %s", data)
}
reqBytes, err := json.Marshal(&webapi_broadcastData.Request{Address: targetAddress, Data: data})
if err != nil {
return "", err
}
res, err := api.Post(fmt.Sprintf("%s/%s", api.node, routeBroadcastData), contentTypeJSON, bytes.NewReader(reqBytes))
if err != nil {
return "", err
}
resObj := &webapi_broadcastData.Response{}
if err := interpretBody(res, resObj); err != nil {
return "", err
}
return resObj.Hash, nil
}
func (api *ShimmerAPI) GetTrytes(txHashes trinary.Hashes) ([]trinary.Trytes, error) {
for _, hash := range txHashes {
if !guards.IsTrytes(hash) {
return nil, errors.Wrapf(consts.ErrInvalidHash, "invalid hash: %s", hash)
}
}
reqBytes, err := json.Marshal(&webapi_getTrytes.Request{Hashes: txHashes})
if err != nil {
return nil, err
}
res, err := api.Post(fmt.Sprintf("%s/%s", api.node, routeGetTrytes), contentTypeJSON, bytes.NewReader(reqBytes))
if err != nil {
return nil, err
}
resObj := &webapi_getTrytes.Response{}
if err := interpretBody(res, resObj); err != nil {
return nil, err
}
return resObj.Trytes, nil
}
func (api *ShimmerAPI) GetTransactions(txHashes trinary.Hashes) ([]webapi_getTransactions.Transaction, error) {
for _, hash := range txHashes {
if !guards.IsTrytes(hash) {
return nil, errors.Wrapf(consts.ErrInvalidHash, "invalid hash: %s", hash)
}
}
reqBytes, err := json.Marshal(&webapi_getTransactions.Request{Hashes: txHashes})
if err != nil {
return nil, err
}
res, err := api.Post(fmt.Sprintf("%s/%s", api.node, routeGetTransactions), contentTypeJSON, bytes.NewReader(reqBytes))
if err != nil {
return nil, err
}
resObj := &webapi_getTransactions.Response{}
if err := interpretBody(res, resObj); err != nil {
return nil, err
}
return resObj.Transactions, nil
}
func (api *ShimmerAPI) FindTransactions(query *webapi_findTransactions.Request) ([]trinary.Hashes, error) {
for _, hash := range query.Addresses {
if !guards.IsTrytes(hash) {
return nil, errors.Wrapf(consts.ErrInvalidHash, "invalid hash: %s", hash)
}
}
reqBytes, err := json.Marshal(&query)
if err != nil {
return nil, err
}
res, err := api.Post(fmt.Sprintf("%s/%s", api.node, routeFindTransactions), contentTypeJSON, bytes.NewReader(reqBytes))
if err != nil {
return nil, err
}
resObj := &webapi_findTransactions.Response{}
if err := interpretBody(res, resObj); err != nil {
return nil, err
}
return resObj.Transactions, nil
}
func (api *ShimmerAPI) GetNeighbors() (*webapi_getNeighbors.Response, error) {
res, err := api.Get(fmt.Sprintf("%s/%s", api.node, routeGetNeighbors))
if err != nil {
return nil, err
}
resObj := &webapi_getNeighbors.Response{}
if err := interpretBody(res, resObj); err != nil {
return nil, err
}
return resObj, nil
}
func (api *ShimmerAPI) GetTips() (*webapi_gtta.Response, error) {
res, err := api.Get(fmt.Sprintf("%s/%s", api.node, routeGetTransactionsToApprove))
if err != nil {
return nil, err
}
resObj := &webapi_gtta.Response{}
if err := interpretBody(res, resObj); err != nil {
return nil, err
}
return resObj, nil
}
func (api *ShimmerAPI) ToggleSpammer(enable bool) (*webapi_spammer.Response, error) {
res, err := api.Get(fmt.Sprintf("%s/%s?cmd=%s", api.node, routeSpammer, func() string {
if enable {
return "start"
}
return "stop"
}()))
if err != nil {
return nil, err
}
resObj := &webapi_spammer.Response{}
if err := interpretBody(res, resObj); err != nil {
return nil, err
}
return resObj, nil
}
......@@ -61,6 +61,7 @@ func main() {
webapi_getTransactions.PLUGIN,
webapi_findTransactions.PLUGIN,
webapi_getNeighbors.PLUGIN,
webapi_spammer.PLUGIN,
ui.PLUGIN,
webauth.PLUGIN,
......
# How to install this plugin
- Run the following commands in this folder (or set `graph.socketioPath` and `graph.webrootPath` in your config if you want to use another path)
```bash
git clone https://github.com/glumb/IOTAtangle.git
cd IOTAtangle && git reset --hard 07bba77a296a2d06277cdae56aa963abeeb5f66e
cd ../
git clone https://github.com/socketio/socket.io-client.git
```
\ No newline at end of file
......@@ -30,12 +30,14 @@ func configure(plugin *node.Plugin) {
// broadcasts it to the node's neighbors. It returns the transaction hash if successful.
func broadcastData(c echo.Context) error {
var request webRequest
var request Request
if err := c.Bind(&request); err != nil {
log.Info(err.Error())
return requestFailed(c, err.Error())
}
log.Debug("Received - address:", request.Address, " data:", request.Data)
tx := value_transaction.New()
tx.SetHead(true)
tx.SetTail(true)
......@@ -76,23 +78,23 @@ func broadcastData(c echo.Context) error {
}
func requestSuccessful(c echo.Context, txHash string) error {
return c.JSON(http.StatusCreated, webResponse{
return c.JSON(http.StatusCreated, Response{
Hash: txHash,
})
}
func requestFailed(c echo.Context, message string) error {
return c.JSON(http.StatusBadRequest, webResponse{
return c.JSON(http.StatusBadRequest, Response{
Error: message,
})
}
type webResponse struct {
type Response struct {
Hash string `json:"hash,omitempty"`
Error string `json:"error,omitempty"`
}
type webRequest struct {
type Request struct {
Address string `json:"address"`
Data string `json:"data"`
}
......@@ -25,7 +25,7 @@ func configure(plugin *node.Plugin) {
// the value at the index of that address is empty.
func findTransactions(c echo.Context) error {
var request webRequest
var request Request
if err := c.Bind(&request); err != nil {
log.Info(err.Error())
......@@ -46,22 +46,22 @@ func findTransactions(c echo.Context) error {
}
func requestSuccessful(c echo.Context, txHashes [][]trinary.Trytes) error {
return c.JSON(http.StatusOK, webResponse{
return c.JSON(http.StatusOK, Response{
Transactions: txHashes,
})
}
func requestFailed(c echo.Context, message string) error {
return c.JSON(http.StatusNotFound, webResponse{
return c.JSON(http.StatusNotFound, Response{
Error: message,
})
}
type webResponse struct {
type Response struct {
Transactions [][]trinary.Trytes `json:"transactions,omitempty"` //string
Error string `json:"error,omitempty"`
}
type webRequest struct {
type Request struct {
Addresses []string `json:"addresses"`
}
......@@ -24,8 +24,8 @@ func configure(plugin *node.Plugin) {
// getNeighbors returns the chosen and accepted neighbors of the node
func getNeighbors(c echo.Context) error {
chosen := []neighbor{}
accepted := []neighbor{}
chosen := []Neighbor{}
accepted := []Neighbor{}
if autopeering.Selection == nil {
return requestFailed(c, "Neighbor Selection is not enabled")
......@@ -33,7 +33,7 @@ func getNeighbors(c echo.Context) error {
for _, peer := range autopeering.Selection.GetOutgoingNeighbors() {
n := neighbor{
n := Neighbor{
ID: peer.ID().String(),
PublicKey: base64.StdEncoding.EncodeToString(peer.PublicKey()),
}
......@@ -41,7 +41,7 @@ func getNeighbors(c echo.Context) error {
chosen = append(chosen, n)
}
for _, peer := range autopeering.Selection.GetIncomingNeighbors() {
n := neighbor{
n := Neighbor{
ID: peer.ID().String(),
PublicKey: base64.StdEncoding.EncodeToString(peer.PublicKey()),
}
......@@ -52,26 +52,26 @@ func getNeighbors(c echo.Context) error {
}
func requestSuccessful(c echo.Context, chosen, accepted []neighbor) error {
return c.JSON(http.StatusOK, webResponse{
func requestSuccessful(c echo.Context, chosen, accepted []Neighbor) error {
return c.JSON(http.StatusOK, Response{
Chosen: chosen,
Accepted: accepted,
})
}
func requestFailed(c echo.Context, message string) error {
return c.JSON(http.StatusNotFound, webResponse{
return c.JSON(http.StatusNotFound, Response{
Error: message,
})
}
type webResponse struct {
Chosen []neighbor `json:"chosen"`
Accepted []neighbor `json:"accepted"`
type Response struct {
Chosen []Neighbor `json:"chosen"`
Accepted []Neighbor `json:"accepted"`
Error string `json:"error,omitempty"`
}
type neighbor struct {
type Neighbor struct {
ID string `json:"id"` // comparable node identifier
PublicKey string `json:"publicKey"` // public key used to verify signatures
Services []peerService
......
......@@ -25,13 +25,14 @@ func configure(plugin *node.Plugin) {
// the value at the index of that transaction hash is empty.
func getTransactions(c echo.Context) error {
var request webRequest
result := []transaction{}
var request Request
result := []Transaction{}
if err := c.Bind(&request); err != nil {
log.Info(err.Error())
return requestFailed(c, err.Error())
}
log.Debug("Received:", request.Hashes)
for _, hash := range request.Hashes {
......@@ -40,7 +41,7 @@ func getTransactions(c echo.Context) error {
return requestFailed(c, err.Error())
}
if tx != nil {
t := transaction{
t := Transaction{
Hash: tx.GetHash(),
WeightMagnitude: tx.GetWeightMagnitude(),
TrunkTransactionHash: tx.GetTrunkTransactionHash(),
......@@ -56,7 +57,7 @@ func getTransactions(c echo.Context) error {
result = append(result, t)
} else {
//tx not found
result = append(result, transaction{})
result = append(result, Transaction{})
}
}
......@@ -64,28 +65,28 @@ func getTransactions(c echo.Context) error {
return requestSuccessful(c, result)
}
func requestSuccessful(c echo.Context, txs []transaction) error {
return c.JSON(http.StatusOK, webResponse{
func requestSuccessful(c echo.Context, txs []Transaction) error {
return c.JSON(http.StatusOK, Response{
Transactions: txs,
})
}
func requestFailed(c echo.Context, message string) error {
return c.JSON(http.StatusNotFound, webResponse{
return c.JSON(http.StatusNotFound, Response{
Error: message,
})
}
type webResponse struct {
Transactions []transaction `json:"transaction,omitempty"`
type Response struct {
Transactions []Transaction `json:"transaction,omitempty"`
Error string `json:"error,omitempty"`
}
type webRequest struct {
type Request struct {
Hashes []string `json:"hashes"`
}
type transaction struct {
type Transaction struct {
Hash trinary.Trytes `json:"hash,omitempty"`
WeightMagnitude int `json:"weightMagnitude,omitempty"`
TrunkTransactionHash trinary.Trytes `json:"trunkTransactionHash,omitempty"`
......
......@@ -25,7 +25,7 @@ func configure(plugin *node.Plugin) {
// the value at the index of that transaction hash is empty.
func getTrytes(c echo.Context) error {
var request webRequest
var request Request
result := []trinary.Trytes{}
if err := c.Bind(&request); err != nil {
log.Info(err.Error())
......@@ -56,22 +56,22 @@ func getTrytes(c echo.Context) error {
}
func requestSuccessful(c echo.Context, txTrytes []trinary.Trytes) error {
return c.JSON(http.StatusOK, webResponse{
return c.JSON(http.StatusOK, Response{
Trytes: txTrytes,
})
}
func requestFailed(c echo.Context, message string) error {
return c.JSON(http.StatusNotFound, webResponse{
return c.JSON(http.StatusNotFound, Response{
Error: message,
})
}
type webResponse struct {
type Response struct {
Trytes []trinary.Trytes `json:"trytes,omitempty"` //string
Error string `json:"error,omitempty"`
}
type webRequest struct {
type Request struct {
Hashes []string `json:"hashes"`
}
......@@ -19,13 +19,13 @@ func Handler(c echo.Context) error {
branchTransactionHash := tipselection.GetRandomTip()
trunkTransactionHash := tipselection.GetRandomTip()
return c.JSON(http.StatusOK, webResponse{
return c.JSON(http.StatusOK, Response{
BranchTransaction: branchTransactionHash,
TrunkTransaction: trunkTransactionHash,
})
}
type webResponse struct {
type Response struct {
BranchTransaction trinary.Trytes `json:"branchTransaction"`
TrunkTransaction trinary.Trytes `json:"trunkTransaction"`
}
......@@ -17,7 +17,7 @@ func configure(plugin *node.Plugin) {
func WebApiHandler(c echo.Context) error {
var request webRequest
var request Request
if err := c.Bind(&request); err != nil {
return requestFailed(c, err.Error())
}
......@@ -44,22 +44,22 @@ func WebApiHandler(c echo.Context) error {
}
func requestSuccessful(c echo.Context, message string) error {
return c.JSON(http.StatusOK, webResponse{
return c.JSON(http.StatusOK, Response{
Message: message,
})
}
func requestFailed(c echo.Context, message string) error {
return c.JSON(http.StatusNotFound, webResponse{
return c.JSON(http.StatusNotFound, Response{
Message: message,
})
}
type webResponse struct {
type Response struct {
Message string `json:"message"`
}
type webRequest struct {
type Request struct {
Cmd string `json:"cmd"`
Tps uint `json:"tps"`
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment