commit f87acbf98eda27a5f55ffc419f5e093ffc908ccc Author: Mohammed Sohail Date: Thu Dec 19 17:23:36 2024 +0300 feat: add data encode decode fns diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..9770634 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.grassecon.net/urdt/ussd-data-connect + +go 1.23.3 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/pkg/data/decode.go b/pkg/data/decode.go new file mode 100644 index 0000000..d98bf5b --- /dev/null +++ b/pkg/data/decode.go @@ -0,0 +1,22 @@ +package data + +import ( + "encoding/binary" +) + +const () + +// DecodeKey specifically only decodes user data keys stored as bytes into its respective session ID and data type +// TODO: Replace return data type with imported data types from the common package once lib-gdbm dependency is removed. +func DecodeKey(key []byte) (uint16, string) { + if key[0] != keyPrefix { + return 0, "" + } + + return binary.BigEndian.Uint16(key[len(key)-2:]), string(key[1 : len(key)-2]) +} + +// DecodeValue returns the utf-8 string representation of the value stored in the storage backend +func DecodeValue(v []byte) string { + return string(v) +} diff --git a/pkg/data/decode_test.go b/pkg/data/decode_test.go new file mode 100644 index 0000000..539c2f4 --- /dev/null +++ b/pkg/data/decode_test.go @@ -0,0 +1,43 @@ +package data + +import ( + "encoding/hex" + "testing" +) + +func TestDecodeKey(t *testing.T) { + type want struct { + sessionID string + dataType uint16 + } + type args struct { + keyBytesHex string + } + tests := []struct { + name string + args args + want want + }{ + { + "blockchain_address", + args{ + keyBytesHex: "202b3235343731313030303132330001", + }, + want{ + sessionID: "+254711000123", + dataType: ACCOUNT_BLOCKCHAIN_ADDRESS, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + keyBytes, err := hex.DecodeString(tt.args.keyBytesHex) + if err != nil { + t.Fatalf("failed to decode hex string: %v", err) + } + + dataType, sessionID := DecodeKey(keyBytes) + t.Logf("%s data_type: %d, session_id: %s", tt.name, dataType, sessionID) + }) + } +} diff --git a/pkg/data/encode.go b/pkg/data/encode.go new file mode 100644 index 0000000..046c111 --- /dev/null +++ b/pkg/data/encode.go @@ -0,0 +1,23 @@ +package data + +import ( + "encoding/binary" +) + +// EncodeKey returns the byte representation of a urdt/ussd user data key. +// This key can be used to lookup the value on any storage backend implementation. +// Warning: This is a shortcut specifically for user data, it is not expected to work for all go-vise keys. +// TODO: Replace with imported data types from the common package once lib-gdbm dependency is removed. +func EncodeKey(sessionID string, dataType uint16) []byte { + keyBytes := []byte(sessionID) + keyBytes = append(keyBytes, uint16ToBytes(dataType)...) + keyBytes = append([]uint8{keyPrefix}, keyBytes...) + + return keyBytes +} + +func uint16ToBytes(v uint16) []byte { + bytes := make([]byte, 2) + binary.BigEndian.PutUint16(bytes, v) + return bytes +} diff --git a/pkg/data/encode_test.go b/pkg/data/encode_test.go new file mode 100644 index 0000000..e7248b3 --- /dev/null +++ b/pkg/data/encode_test.go @@ -0,0 +1,31 @@ +package data + +import ( + "testing" +) + +// TODO: Import from urdt/ussd +func TestEncodeKey(t *testing.T) { + type args struct { + sessionID string + dataType uint16 + } + tests := []struct { + name string + args args + }{ + { + "blockchain_address", + args{ + sessionID: "+254711000123", + dataType: ACCOUNT_BLOCKCHAIN_ADDRESS, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := EncodeKey(tt.args.sessionID, tt.args.dataType) + t.Logf("%s key: %x", tt.name, got) + }) + } +} diff --git a/pkg/data/type.go b/pkg/data/type.go new file mode 100644 index 0000000..49dd78e --- /dev/null +++ b/pkg/data/type.go @@ -0,0 +1,16 @@ +package data + +// Subset of urdt/ussd/common specifically for syncing to the central data store i.e Graph. +// TODO: Replace with imported data types from the common package once lib-gdbm dependency is removed. +const ( + keyPrefix = 32 + + ACCOUNT_BLOCKCHAIN_ADDRESS = 1 + ACCOUNT_FIRST_NAME = 3 + ACCOUNT_LAST_NAME = 4 + ACCOUNT_YOB = 5 + ACCOUNT_LOCATION = 6 + ACCOUNT_GENDER = 7 + ACCOUNT_COMMODITIES = 8 + ACCOUNT_ACTIVE_VOUCHER = 17 +)