feat: addded scanning for the PHP shit.
This commit is contained in:
parent
8ea98e8586
commit
f410b16797
4 changed files with 270 additions and 154 deletions
|
@ -2,18 +2,79 @@ package main
|
|||
|
||||
import (
|
||||
"vultras.su/core/bond"
|
||||
"vultras.su/core/bond/urlenc"
|
||||
//"vultras.su/core/bond/methods"
|
||||
"vultras.su/core/bond/statuses"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
//"io"
|
||||
//"net/url"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type JsonInt64 int64
|
||||
func(ji *JsonInt) UnmarshalJSON(bts []byte) error {
|
||||
k, err := strconv.ParseInt(string(bts), 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
type JsonArrayMap[V any] map[int] V
|
||||
func (jam *JsonArrayMap[V]) UnmarshalJSON(bts []byte) error {
|
||||
*jam = make(JsonArrayMap[V])
|
||||
am := *jam
|
||||
j := map[string] json.RawMessage{}
|
||||
err := json.Unmarshal(bts, &j)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v := new(V)
|
||||
for jk, jv := range j {
|
||||
// Getting the key from string.
|
||||
k, err := strconv.ParseInt(jk, 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(jv), v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
am[int(k)] = *v
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type GetNotesOptions struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
type WebhookRequest struct {
|
||||
Leads Leads `json:"leads"`
|
||||
Account Account `json:"account"`
|
||||
}
|
||||
|
||||
type Leads struct {
|
||||
Status JsonArrayMap[Status]`json:"status"`
|
||||
Add JsonArrayMap[Status] `json:"add"`
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
Id string `json:"id"`
|
||||
StatusId string `json:"status_id"`
|
||||
PipelineId string `json:"pipeline_id"`
|
||||
OldStatusId string `json:"old_status_id"`
|
||||
OldPipelineId string `json:"old_pipeline_id"`
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
Id string `json:"id"`
|
||||
SubDomain string `json:"subdomain"`
|
||||
}
|
||||
|
||||
var root = bond.Root(bond.Path().
|
||||
Def(
|
||||
|
@ -21,7 +82,14 @@ Def(
|
|||
/*bond.Method().Def(
|
||||
methods.Post,*/
|
||||
bond.Func(func(c *bond.Context){
|
||||
fmt.Printf("Content-Type: %q\n", c.ContentType())
|
||||
reciever := WebhookRequest{}
|
||||
c.Scan(&reciever)
|
||||
if c.ScanErr() != nil {
|
||||
fmt.Printf("err: %s\n", c.ScanErr())
|
||||
}
|
||||
fmt.Printf("%#v\n", reciever)
|
||||
return
|
||||
/*fmt.Printf("Content-Type: %q\n", c.ContentType())
|
||||
body, err := io.ReadAll(c.R.Body)
|
||||
if err != nil {
|
||||
fmt.Printf("err:%s\n", err)
|
||||
|
@ -45,19 +113,32 @@ Def(
|
|||
fmt.Printf("err:%s\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("\nparsed: %v\n", string(js))
|
||||
fmt.Printf("\nparsed: %v\n", string(js))*/
|
||||
c.SetStatus(statuses.OK)
|
||||
}),
|
||||
//),
|
||||
))
|
||||
|
||||
func main() {
|
||||
srv := bond.Server{
|
||||
requestString := "leads[status][0][id]=2050297&" +
|
||||
"leads[status][0][status_id]=35573056&" +
|
||||
"leads[status][0][pipeline_id]=3643927&" +
|
||||
"leads[status][0][old_status_id]=35572897&" +
|
||||
"leads[status][0][old_pipeline_id]=3643927&" +
|
||||
"account[id]=29085955&" +
|
||||
"account[subdomain]=domain"
|
||||
reciever := WebhookRequest{}
|
||||
err := urlenc.Unmarshal([]byte(requestString), &reciever)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("%#v\n", reciever)
|
||||
/*srv := bond.Server{
|
||||
Addr: ":15080",
|
||||
Handler: root,
|
||||
}
|
||||
err := srv.ListenAndServe()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
|
13
context.go
13
context.go
|
@ -7,6 +7,7 @@ import (
|
|||
"net/url"
|
||||
"fmt"
|
||||
"vultras.su/core/bond/contents"
|
||||
"vultras.su/core/bond/urlenc"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
|
@ -61,15 +62,21 @@ func (c *Context) Close() {
|
|||
}
|
||||
|
||||
// Scan the incoming value from body depending
|
||||
// on the content type of the request.
|
||||
// on the content type of the request into the
|
||||
// structure or map[string] any.
|
||||
func (c *Context) Scan(v any) bool {
|
||||
if c.dec == nil {
|
||||
typ := c.ContentType()
|
||||
switch typ {
|
||||
case contents.Json:
|
||||
c.dec = json.NewDecoder(c.R.Body)
|
||||
//case contents.UrlEncoded:
|
||||
// return false
|
||||
case contents.UrlEncoded:
|
||||
body, _ := io.ReadAll(c.R.Body)
|
||||
err := urlenc.Unmarshal(body, v)
|
||||
if err != nil {
|
||||
c.scanErr = err
|
||||
}
|
||||
return false
|
||||
default:
|
||||
c.scanErr = UnknownContentTypeErr
|
||||
return false
|
||||
|
|
145
parse.go
145
parse.go
|
@ -1,147 +1,2 @@
|
|||
package bond
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func ParseStr(encodedString string, result map[string]interface{}) error {
|
||||
// build nested map.
|
||||
var build func(map[string]interface{}, []string, interface{}) error
|
||||
|
||||
build = func(result map[string]interface{}, keys []string, value interface{}) error {
|
||||
length := len(keys)
|
||||
// trim ',"
|
||||
key := strings.Trim(keys[0], "'\"")
|
||||
if length == 1 {
|
||||
result[key] = value
|
||||
return nil
|
||||
}
|
||||
|
||||
// The end is slice. like f[], f[a][]
|
||||
if keys[1] == "" && length == 2 {
|
||||
// todo nested slice
|
||||
if key == "" {
|
||||
return nil
|
||||
}
|
||||
val, ok := result[key]
|
||||
if !ok {
|
||||
result[key] = []interface{}{value}
|
||||
return nil
|
||||
}
|
||||
children, ok := val.([]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("expected type '[]interface{}' for key '%s', but got '%T'", key, val)
|
||||
}
|
||||
result[key] = append(children, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// The end is slice + map. like f[][a]
|
||||
if keys[1] == "" && length > 2 && keys[2] != "" {
|
||||
val, ok := result[key]
|
||||
if !ok {
|
||||
result[key] = []interface{}{}
|
||||
val = result[key]
|
||||
}
|
||||
children, ok := val.([]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("expected type '[]interface{}' for key '%s', but got '%T'", key, val)
|
||||
}
|
||||
if l := len(children); l > 0 {
|
||||
if child, ok := children[l-1].(map[string]interface{}); ok {
|
||||
if _, ok := child[keys[2]]; !ok {
|
||||
_ = build(child, keys[2:], value)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
child := map[string]interface{}{}
|
||||
_ = build(child, keys[2:], value)
|
||||
result[key] = append(children, child)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// map. like f[a], f[a][b]
|
||||
val, ok := result[key]
|
||||
if !ok {
|
||||
result[key] = map[string]interface{}{}
|
||||
val = result[key]
|
||||
}
|
||||
children, ok := val.(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("expected type 'map[string]interface{}' for key '%s', but got '%T'", key, val)
|
||||
}
|
||||
|
||||
return build(children, keys[1:], value)
|
||||
}
|
||||
|
||||
// split encodedString.
|
||||
parts := strings.Split(encodedString, "&")
|
||||
for _, part := range parts {
|
||||
pos := strings.Index(part, "=")
|
||||
if pos <= 0 {
|
||||
continue
|
||||
}
|
||||
key, err := url.QueryUnescape(part[:pos])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for key[0] == ' ' {
|
||||
key = key[1:]
|
||||
}
|
||||
if key == "" || key[0] == '[' {
|
||||
continue
|
||||
}
|
||||
value, err := url.QueryUnescape(part[pos+1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// split into multiple keys
|
||||
var keys []string
|
||||
left := 0
|
||||
for i, k := range key {
|
||||
if k == '[' && left == 0 {
|
||||
left = i
|
||||
} else if k == ']' {
|
||||
if left > 0 {
|
||||
if len(keys) == 0 {
|
||||
keys = append(keys, key[:left])
|
||||
}
|
||||
keys = append(keys, key[left+1:i])
|
||||
left = 0
|
||||
if i+1 < len(key) && key[i+1] != '[' {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(keys) == 0 {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
// first key
|
||||
first := ""
|
||||
for i, chr := range keys[0] {
|
||||
if chr == ' ' || chr == '.' || chr == '[' {
|
||||
first += "_"
|
||||
} else {
|
||||
first += string(chr)
|
||||
}
|
||||
if chr == '[' {
|
||||
first += keys[0][i+1:]
|
||||
break
|
||||
}
|
||||
}
|
||||
keys[0] = first
|
||||
|
||||
// build nested map
|
||||
if err := build(result, keys, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
173
urlenc/scan.go
Normal file
173
urlenc/scan.go
Normal file
|
@ -0,0 +1,173 @@
|
|||
package urlenc
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func Unmarshal(bts []byte, v any) error {
|
||||
unesc, err := url.QueryUnescape(string(bts))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mp := map[string] any{}
|
||||
err = parseStr(unesc, mp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
js, err := json.Marshal(mp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(js, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseStr(encodedString string, result map[string]any) error {
|
||||
// build nested map.
|
||||
var build func(map[string]any, []string, any) error
|
||||
|
||||
build = func(result map[string]any, keys []string, value any) error {
|
||||
length := len(keys)
|
||||
// trim ',"
|
||||
key := strings.Trim(keys[0], "'\"")
|
||||
if length == 1 {
|
||||
result[key] = value
|
||||
return nil
|
||||
}
|
||||
|
||||
// The end is slice. like f[], f[a][]
|
||||
if keys[1] == "" && length == 2 {
|
||||
// todo nested slice
|
||||
if key == "" {
|
||||
return nil
|
||||
}
|
||||
val, ok := result[key]
|
||||
if !ok {
|
||||
result[key] = []any{value}
|
||||
return nil
|
||||
}
|
||||
children, ok := val.([]any)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected type '[]any' for key '%s', but got '%T'", key, val)
|
||||
}
|
||||
result[key] = append(children, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// The end is slice + map. like f[][a]
|
||||
if keys[1] == "" && length > 2 && keys[2] != "" {
|
||||
val, ok := result[key]
|
||||
if !ok {
|
||||
result[key] = []any{}
|
||||
val = result[key]
|
||||
}
|
||||
children, ok := val.([]any)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected type '[]any' for key '%s', but got '%T'", key, val)
|
||||
}
|
||||
if l := len(children); l > 0 {
|
||||
if child, ok := children[l-1].(map[string]any); ok {
|
||||
if _, ok := child[keys[2]]; !ok {
|
||||
_ = build(child, keys[2:], value)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
child := map[string]any{}
|
||||
_ = build(child, keys[2:], value)
|
||||
result[key] = append(children, child)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// map. like f[a], f[a][b]
|
||||
val, ok := result[key]
|
||||
if !ok {
|
||||
result[key] = map[string]any{}
|
||||
val = result[key]
|
||||
}
|
||||
children, ok := val.(map[string]any)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected type 'map[string]any' for key '%s', but got '%T'", key, val)
|
||||
}
|
||||
|
||||
return build(children, keys[1:], value)
|
||||
}
|
||||
|
||||
// split encodedString.
|
||||
parts := strings.Split(encodedString, "&")
|
||||
for _, part := range parts {
|
||||
pos := strings.Index(part, "=")
|
||||
if pos <= 0 {
|
||||
continue
|
||||
}
|
||||
key, err := url.QueryUnescape(part[:pos])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for key[0] == ' ' {
|
||||
key = key[1:]
|
||||
}
|
||||
if key == "" || key[0] == '[' {
|
||||
continue
|
||||
}
|
||||
value, err := url.QueryUnescape(part[pos+1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// split into multiple keys
|
||||
var keys []string
|
||||
left := 0
|
||||
for i, k := range key {
|
||||
if k == '[' && left == 0 {
|
||||
left = i
|
||||
} else if k == ']' {
|
||||
if left > 0 {
|
||||
if len(keys) == 0 {
|
||||
keys = append(keys, key[:left])
|
||||
}
|
||||
keys = append(keys, key[left+1:i])
|
||||
left = 0
|
||||
if i+1 < len(key) && key[i+1] != '[' {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(keys) == 0 {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
// first key
|
||||
first := ""
|
||||
for i, chr := range keys[0] {
|
||||
if chr == ' ' || chr == '.' || chr == '[' {
|
||||
first += "_"
|
||||
} else {
|
||||
first += string(chr)
|
||||
}
|
||||
if chr == '[' {
|
||||
first += keys[0][i+1:]
|
||||
break
|
||||
}
|
||||
}
|
||||
keys[0] = first
|
||||
|
||||
// build nested map
|
||||
if err := build(result, keys, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in a new issue