From a6f24042f5edf1c5b3876f51aa72ea4e6bdf8682 Mon Sep 17 00:00:00 2001 From: Mohammed Sohail Date: Fri, 29 Apr 2022 17:04:01 +0300 Subject: [PATCH] add: cic-meta client --- pkg/meta/meta.go | 113 +++++++++++++++++++++++++++++++++++++++++++++++ pkg/meta/util.go | 50 +++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 pkg/meta/meta.go create mode 100644 pkg/meta/util.go diff --git a/pkg/meta/meta.go b/pkg/meta/meta.go new file mode 100644 index 0000000..a549297 --- /dev/null +++ b/pkg/meta/meta.go @@ -0,0 +1,113 @@ +package meta + +import ( + "github.com/ethereum/go-ethereum/common" + "net/http" + "strings" + "time" +) + +const ( + personPointer = ":cic.person" + phonePointer = ":cic.phone" + preferencesPointer = ":cic.preferences" + customPointer = ":cic.custom" +) + +type CicMeta struct { + httpClient *http.Client + baseUrl string +} + +type CustomResponse struct { + Tags []string `json:"tags"` +} + +type PreferencesResponse struct { + PreferredLanguage string `json:"preferred_language"` +} + +type PersonResponse struct { + DateRegistered int `json:"date_registered"` + VCard string `json:"vcard"` + Gender string `json:"gender"` + Location Location `json:"location"` + Products []string `json:"products"` + DateOfBirth DateOfBirth `json:"date_of_birth"` +} + +type Location struct { + AreaName string `json:"area_name"` +} + +type DateOfBirth struct { + Year int `json:"year"` +} + +func NewCicMeta(metaEndpoint string) *CicMeta { + return &CicMeta{ + httpClient: &http.Client{ + Timeout: time.Second * 3, + }, + baseUrl: metaEndpoint, + } +} + +func (c *CicMeta) GetPhonePointer(phone string) (string, error) { + hashedKey := mergeSha256Key([]byte(phone), []byte(phonePointer)) + + r, err := requestHandler(c, hashedKey) + if err != nil { + return "", err + } + + return strings.Trim(string(r), "\""), nil +} + +func (c *CicMeta) GetPersonMetadata(address string) (PersonResponse, error) { + hashedKey := mergeSha256Key(common.HexToAddress(address).Bytes(), []byte(personPointer)) + + respData, err := requestHandler(c, hashedKey) + if err != nil { + return PersonResponse{}, err + } + + metadata, err := jsonUnmarshaler(respData, PersonResponse{}) + if err != nil { + return PersonResponse{}, err + } + + return metadata, nil +} + +func (c *CicMeta) GetPreferencesMetadata(address string) (PreferencesResponse, error) { + hashedKey := mergeSha256Key(common.HexToAddress(address).Bytes(), []byte(preferencesPointer)) + + respData, err := requestHandler(c, hashedKey) + if err != nil { + return PreferencesResponse{}, err + } + + metadata, err := jsonUnmarshaler(respData, PreferencesResponse{}) + if err != nil { + return PreferencesResponse{}, err + } + + return metadata, nil +} + +func (c *CicMeta) GetCustomMetadata(address string) (CustomResponse, error) { + hashedKey := mergeSha256Key(common.HexToAddress(address).Bytes(), []byte(customPointer)) + + respData, err := requestHandler(c, hashedKey) + if err != nil { + return CustomResponse{}, err + } + + metadata, err := jsonUnmarshaler(respData, CustomResponse{}) + if err != nil { + return CustomResponse{}, err + } + + return metadata, nil +} diff --git a/pkg/meta/util.go b/pkg/meta/util.go new file mode 100644 index 0000000..b521fc1 --- /dev/null +++ b/pkg/meta/util.go @@ -0,0 +1,50 @@ +package meta + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" +) + +func generateMetaUrl(metaBaseUrl string, key string) string { + return fmt.Sprintf("%s/%s", metaBaseUrl, key) +} + +func mergeSha256Key(x []byte, y []byte) string { + h := sha256.New() + + h.Write(x) + h.Write(y) + + return hex.EncodeToString(h.Sum(nil)) +} + +func requestHandler(cicMeta *CicMeta, metadataKey string) ([]byte, error) { + resp, err := cicMeta.httpClient.Get(generateMetaUrl(cicMeta.baseUrl, metadataKey)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("error fetching metadata for key %s: %s", metadataKey, resp.Status) + } + + respData, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return respData, nil +} + +func jsonUnmarshaler[T PersonResponse | PreferencesResponse | CustomResponse](respBody []byte, binding T) (T, error) { + if err := json.Unmarshal(respBody, &binding); err != nil { + return binding, err + } + + return binding, nil +}