diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..061f367 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/utopialib-go +/utopialib-go.exe diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..eb93f27 --- /dev/null +++ b/.travis.yml @@ -0,0 +1 @@ +language: go \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..241b2cf --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Sagleft + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8ba389f --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ + +![logo](https://github.com/Sagleft/utopialib-go/raw/master/logo.png) + +Utopia Ecosystem API wrapper written in Golang + +Docs +----- + +[![GoDoc](https://godoc.org/github.com/sagleft/utopialib-go?status.svg)](https://godoc.org/gopkg.in/sagleft/utopialib-go.v1) +[![go-report](https://goreportcard.com/badge/github.com/Sagleft/utopialib-go)](https://goreportcard.com/report/github.com/Sagleft/utopialib-go) +[![Build Status](https://travis-ci.org/sagleft/utopialib-go.svg?branch=master)](https://travis-ci.org/sagleft/utopialib-go) + +Install +----- + +```bash +go get github.com/Sagleft/utopialib-go +``` + +then + +```go +import ( + utopiago "github.com/Sagleft/utopialib-go" +) +``` + +Usage +----- + +```go +client := utopiago.UtopiaClient{ + Protocol: "http", + Token: "C17BF2E95821A6B545DC9A193CBB750B", + Host: "127.0.0.1", + Port: 22791, +} + +fmt.Println(client.GetSystemInfo()) +``` + +How can this be used? +----- + +* creating a web service that processes client requests; +* creation of a payment service; +* development of a bot for the channel; +* utility for working with uNS; +* experiments to explore web3.0; diff --git a/doc.go b/doc.go new file mode 100644 index 0000000..4fb1a3a --- /dev/null +++ b/doc.go @@ -0,0 +1,4 @@ +/* +Package utopiago is Utopia Ecosystem API wrapper +*/ +package utopiago diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5114a41 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/Sagleft/utopialib-go + +go 1.16 + +require gopkg.in/grignaak/tribool.v1 v1.0.0-20150312065122-d6bb19d816df diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..6498b29 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +gopkg.in/grignaak/tribool.v1 v1.0.0-20150312065122-d6bb19d816df h1:SCh+kVSG+MN/pU/l0/3ehkc3i9T+G6AQS6jEoxM4ddY= +gopkg.in/grignaak/tribool.v1 v1.0.0-20150312065122-d6bb19d816df/go.mod h1:ikoZVciJt+u3It4kEk89OVqIKHPU9BjrgkHSr++TA2w= diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..9f7e001 Binary files /dev/null and b/logo.png differ diff --git a/utopia.go b/utopia.go new file mode 100644 index 0000000..fcc9132 --- /dev/null +++ b/utopia.go @@ -0,0 +1,273 @@ +package utopiago + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + "strconv" + + "gopkg.in/grignaak/tribool.v1" +) + +// Query is a filter for API requests +type Query struct { + Method string `json:"method"` + Token string `json:"token"` + Params map[string]interface{} `json:"params"` +} + +// UtopiaClient lets you connect to Utopia Client +type UtopiaClient struct { + Protocol, Host, Token string + Port int +} + +// UtopiaClientInterface contains an enumeration of methods +type UtopiaClientInterface interface { + apiQuery(methodName string) map[string]interface{} + // profile + GetProfileStatus() map[string]interface{} + GetSystemInfo() map[string]interface{} + GetOwnContact() map[string]interface{} + // crypton + GetBalance() (float64, error) + UseVoucher(voucherCode string) error + GetFinanceHistory() map[string]interface{} + CheckClientConnection() bool + CreateVoucher(amount float64) error + // channels + SendChannelMessage(channelID, message string) (string, error) + SendChannelPicture(channelID, base64Image, comment, filenameForImage string) (string, error) +} + +func (c *UtopiaClient) apiQuery(methodName string, params map[string]interface{}) (map[string]interface{}, error) { + var responseMap map[string]interface{} + url := c.Protocol + "://" + c.Host + ":" + strconv.Itoa(c.Port) + "/api/1.0/" + var query = Query{ + Method: methodName, + Token: c.Token, + } + if params != nil { + query.Params = params + } + + var jsonStr, err = json.Marshal(query) + if err != nil { + return responseMap, errors.New("failed to dedcode response json: " + err.Error()) + } + + req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr)) + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return responseMap, err + } + defer resp.Body.Close() + + body, _ := ioutil.ReadAll(resp.Body) + + if !json.Valid(body) { + return responseMap, errors.New("failed to validate json from client") + } + + json.Unmarshal(body, &responseMap) + return responseMap, nil +} + +// GetProfileStatus gets data about the status of the current account +func (c *UtopiaClient) GetProfileStatus() (map[string]interface{}, error) { + return c.apiQuery("getProfileStatus", nil) +} + +// GetSystemInfo retrieves client system information +func (c *UtopiaClient) GetSystemInfo() (map[string]interface{}, error) { + return c.apiQuery("getSystemInfo", nil) +} + +func (c *UtopiaClient) queryResultToInterface(methodName string, params map[string]interface{}) (interface{}, error) { + if !c.CheckClientConnection() { + return nil, errors.New("client disconected") + } + response, err := c.apiQuery(methodName, params) + if result, ok := response["result"]; ok { + return result, err + } + return nil, errors.New("result field doesn't exists in client response") +} + +func (c *UtopiaClient) queryResultToInterfaceArray(methodName string, params map[string]interface{}) ([]interface{}, error) { + if !c.CheckClientConnection() { + return nil, errors.New("client disconected") + } + response, err := c.apiQuery(methodName, params) + if result, ok := response["result"]; ok { + //check type assertion + IResult, isConvertable := result.([]interface{}) + if !isConvertable { + return nil, errors.New("failed to get result array") + } + return IResult, err + } + return nil, errors.New("accaptable result doesn't exists in client response") +} + +func (c *UtopiaClient) queryResultToString(methodName string, params map[string]interface{}) (string, error) { + if !c.CheckClientConnection() { + return "", errors.New("client disconected") + } + response, err := c.apiQuery(methodName, params) + if result, ok := response["result"]; ok { + resultstr := fmt.Sprintf("%v", result) + return resultstr, err + } + return "", errors.New("result field doesn't exists in client response") +} + +func (c *UtopiaClient) queryResultToBool(methodName string, params map[string]interface{}) (bool, error) { + resultstr, err := c.queryResultToString(methodName, params) + resultBool := tribool.FromString(resultstr).WithMaybeAsTrue() + return resultBool, err +} + +func (c *UtopiaClient) queryResultToFloat64(methodName string, params map[string]interface{}) (float64, error) { + resultstr, err := c.queryResultToString(methodName, params) + if err != nil { + return 0, err + } + resultFloat, err := strconv.ParseFloat(resultstr, 64) + return resultFloat, err +} + +func (c *UtopiaClient) queryResultToInt(methodName string, params map[string]interface{}) (int64, error) { + resultstr, err := c.queryResultToString(methodName, params) + if err != nil { + return 0, err + } + result, err := strconv.ParseInt(resultstr, 10, 64) + return result, err +} + +// SetProfileStatus updates data about the status of the current account +func (c *UtopiaClient) SetProfileStatus(status string, mood string) error { + queryMap := make(map[string]interface{}) + queryMap["status"] = status + queryMap["mood"] = mood + + result, err := c.queryResultToBool("setProfileStatus", queryMap) + if err != nil { + return err + } + if result == false { + return errors.New("failed to set profile status") + } + return nil +} + +// GetOwnContact asks for full details of the current account +func (c *UtopiaClient) GetOwnContact() (map[string]interface{}, error) { + return c.apiQuery("getOwnContact", nil) +} + +// CheckClientConnection - checks if there are any errors when contacting the client +func (c *UtopiaClient) CheckClientConnection() bool { + _, err := c.GetSystemInfo() + if err != nil { + return false + } + return true +} + +// UseVoucher - uses the voucher and returns an error on failure +func (c *UtopiaClient) UseVoucher(voucherID string) (string, error) { + params := map[string]interface{}{ + "voucherid": voucherID, + } + return c.queryResultToString("useVoucher", params) +} + +// GetFinanceHistory request the necessary financial statistics +func (c *UtopiaClient) GetFinanceHistory(filters string, referenceNumber string) ([]interface{}, error) { + params := map[string]interface{}{ + "filters": filters, + "referenceNumber": referenceNumber, + } + return c.queryResultToInterfaceArray("getFinanceSystemInformation", params) +} + +// GetBalance request account Crypton balance +func (c *UtopiaClient) GetBalance() (float64, error) { + result, err := c.queryResultToFloat64("getBalance", nil) + if err != nil { + return 0, err + } + return result, nil +} + +// CreateVoucher requests the creation of a new voucher. it returns referenceNumber +func (c *UtopiaClient) CreateVoucher(amount float64) (string, error) { + params := map[string]interface{}{ + "amount": amount, + } + result, err := c.queryResultToString("createVoucher", params) + if err != nil { + return "", err + } + if result == "" { + return "", errors.New("failed to create voucher, empty string in client response") + } + return result, nil +} + +// SetWebSocketState - set WSS Notification state +func (c *UtopiaClient) SetWebSocketState(enabled bool, port int) error { + var enabledStr string + if enabled { + enabledStr = "1" + } + params := map[string]interface{}{ + "enabled": enabledStr, + "port": port, + } + result, err := c.queryResultToString("setWebSocketState", params) + if err != nil { + return err + } + if result == "" { + return errors.New("failed to set websocker state") + } + return nil +} + +// GetWebSocketState - returns WSS Notifications state, 0 - disabled or active listening port number. +func (c *UtopiaClient) GetWebSocketState() (int64, error) { + result, err := c.queryResultToInt("getWebSocketState", nil) + if err != nil { + return 0, err + } + return result, nil +} + +// SendChannelMessage - send channel message & get message ID +func (c *UtopiaClient) SendChannelMessage(channelID, message string) (string, error) { + params := map[string]interface{}{ + "channelid": channelID, + "message": message, + } + return c.queryResultToString("sendChannelMessage", params) +} + +// SendChannelPicture - send channel picture & get message ID +func (c *UtopiaClient) SendChannelPicture(channelID, base64Image, comment, filenameForImage string) (string, error) { + params := map[string]interface{}{ + "channelid": channelID, + "base64_image": base64Image, + "comment": comment, + "filename_image": filenameForImage, + } + return c.queryResultToString("sendChannelPicture", params) +}