aboutsummaryrefslogtreecommitdiff
path: root/dynamicid
diff options
context:
space:
mode:
Diffstat (limited to 'dynamicid')
-rw-r--r--dynamicid/encoding.go115
-rw-r--r--dynamicid/handling.go74
2 files changed, 189 insertions, 0 deletions
diff --git a/dynamicid/encoding.go b/dynamicid/encoding.go
new file mode 100644
index 0000000..23d00db
--- /dev/null
+++ b/dynamicid/encoding.go
@@ -0,0 +1,115 @@
+package dynamicid
+
+import (
+ "encoding/csv"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+var (
+ stringReflectType = reflect.TypeOf(string(""))
+ intReflectType = reflect.TypeOf(int(0))
+ uintReflectType = reflect.TypeOf(uint(0))
+ boolReflectType = reflect.TypeOf(bool(false))
+)
+
+// UnmarshallCSV record into a struct in-place
+func UnmarshallCSV(data string, v any) error {
+ r := csv.NewReader(strings.NewReader(data))
+ record, err := r.Read()
+ if err != nil {
+ return err
+ }
+ s := reflect.ValueOf(v).Elem()
+ t := s.Type()
+ if s.NumField() != len(record) {
+ return &ErrFieldMismatch{s.NumField(), len(record)}
+ }
+ for i := 0; i < s.NumField(); i++ {
+ f := s.Field(i)
+ if t.Field(i).Tag.Get("cid") != "-" {
+ switch f.Type() {
+ case stringReflectType:
+ f.SetString(record[i])
+ case intReflectType:
+ v, err := strconv.ParseInt(record[i], 10, 0)
+ if err != nil {
+ return err
+ }
+ f.SetInt(v)
+ case uintReflectType:
+ v, err := strconv.ParseUint(record[i], 10, 0)
+ if err != nil {
+ return err
+ }
+ f.SetUint(v)
+ case boolReflectType:
+ switch record[i] {
+ case "0":
+ f.SetBool(false)
+ case "1":
+ f.SetBool(true)
+ default:
+ return &ErrUnreadable{"boolean", record[i]}
+ }
+ default:
+ return &ErrUnsupportedType{Type: f.Type().String()}
+ }
+ }
+ }
+ return nil
+}
+
+// MarshallCSV from a struct
+func MarshallCSV(v any) string {
+ s := reflect.ValueOf(v)
+ r := make([]string, 0)
+ for i := 0; i < s.NumField(); i++ {
+ f := s.Field(i)
+ switch f.Type() {
+ case stringReflectType:
+ r = append(r, f.String())
+ case intReflectType:
+ r = append(r, strconv.FormatInt(f.Int(), 10))
+ case uintReflectType:
+ r = append(r, strconv.FormatUint(f.Uint(), 10))
+ case boolReflectType:
+ if f.Bool() {
+ r = append(r, "1")
+ } else {
+ r = append(r, "0")
+ }
+ }
+ }
+ b := new(strings.Builder)
+ w := csv.NewWriter(b)
+ w.Write(r)
+ w.Flush()
+ return b.String()
+}
+
+type ErrFieldMismatch struct {
+ Expected, Found int
+}
+
+func (e *ErrFieldMismatch) Error() string {
+ return fmt.Sprintf("CSV line fields mismatch. Expected %d found %d", e.Expected, e.Found)
+}
+
+type ErrUnreadable struct {
+ Format, Found string
+}
+
+func (e *ErrUnreadable) Error() string {
+ return fmt.Sprintf("Unreadable value as %s. Found %s", e.Format, e.Found)
+}
+
+type ErrUnsupportedType struct {
+ Type string
+}
+
+func (e *ErrUnsupportedType) Error() string {
+ return "Unsupported type: " + e.Type
+}
diff --git a/dynamicid/handling.go b/dynamicid/handling.go
new file mode 100644
index 0000000..8369e27
--- /dev/null
+++ b/dynamicid/handling.go
@@ -0,0 +1,74 @@
+package dynamicid
+
+import (
+ "strings"
+
+ "github.com/anhgelus/gokord"
+ "github.com/anhgelus/gokord/cmd"
+ "github.com/nyttikord/gokord/bot"
+ "github.com/nyttikord/gokord/discord/types"
+ "github.com/nyttikord/gokord/event"
+ "github.com/nyttikord/gokord/interaction"
+)
+
+func HandleDynamicMessageComponent[DynamicData any](
+ b *gokord.Bot,
+ handler func(
+ bot.Session,
+ *event.InteractionCreate,
+ *interaction.MessageComponentData,
+ *DynamicData, *cmd.ResponseBuilder,
+ ),
+ base string,
+) {
+ b.AddHandler(func(s bot.Session, i *event.InteractionCreate) {
+ if i.Type != types.InteractionMessageComponent {
+ return
+ }
+ data := i.MessageComponentData()
+ if !strings.HasPrefix(data.CustomID, base+";") {
+ return
+ }
+ dynamicID := data.CustomID[len(base)+1:]
+ dynamicData := new(DynamicData)
+ err := UnmarshallCSV(dynamicID, dynamicData)
+ if err != nil {
+ s.Logger().Error("Unable to parse CustomID", "error", err, "CustomID", data.CustomID, "base", base)
+ return
+ }
+ handler(s, i, data, dynamicData, cmd.NewResponseBuilder(s, i))
+ })
+}
+
+func HandleDynamicModalComponent[DynamicData any](
+ b *gokord.Bot,
+ handler func(
+ bot.Session,
+ *event.InteractionCreate,
+ *interaction.ModalSubmitData,
+ *DynamicData,
+ *cmd.ResponseBuilder,
+ ),
+ base string,
+) {
+ b.AddHandler(func(s bot.Session, i *event.InteractionCreate) {
+ if i.Type != types.InteractionModalSubmit {
+ return
+ }
+ data := i.ModalSubmitData()
+ if strings.HasPrefix(data.CustomID, base+";") {
+ dynamicID := data.CustomID[len(base)+1:]
+ dynamicData := new(DynamicData)
+ err := UnmarshallCSV(dynamicID, dynamicData)
+ if err != nil {
+ s.Logger().Error("Unable to parse CustomID", "error", err, "CustomID", data.CustomID, "base", base)
+ return
+ }
+ handler(s, i, data, dynamicData, cmd.NewResponseBuilder(s, i))
+ }
+ })
+}
+
+func FormatCustomID(base string, dynamicData any) string {
+ return base + ";" + MarshallCSV(dynamicData)
+}