feat: addded scanning for the PHP shit.

This commit is contained in:
Andrey Parhomenko 2024-01-14 16:25:28 +03:00
parent 8ea98e8586
commit f410b16797
4 changed files with 270 additions and 154 deletions

View file

@ -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)
}
}*/
}

View file

@ -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
View file

@ -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
View 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
}