diff --git a/config.go b/config.go index 8077e15..bf17d1d 100644 --- a/config.go +++ b/config.go @@ -1,22 +1,62 @@ package imitate import ( + "errors" "io/ioutil" - "log" "os" + "reflect" "strings" + "github.com/davecgh/go-spew/spew" yaml "gopkg.in/yaml.v2" ) +// YamlCurls 为了自定义序列化函数 +type YamlCurls []string + +// UnmarshalYAML YamlCurls反序列化函数 +func (curls *YamlCurls) UnmarshalYAML(unmarshal func(interface{}) error) error { + + var buf interface{} + err := unmarshal(&buf) + if err != nil { + return nil + } + + switch tbuf := buf.(type) { + case string: + *curls = append(*curls, parseCurl(tbuf)) + case []interface{}: + for _, ifa := range tbuf { + *curls = append(*curls, parseCurl(ifa.(string))) + } + default: + return errors.New("read curls is error, " + reflect.TypeOf(buf).String()) + + } + + return nil +} + +// MarshalYAML 序列化函数 +func (curls *YamlCurls) MarshalYAML() (interface{}, error) { + content := "[" + for _, curl := range []string(*curls) { + content += "\"" + curl + "\"" + ", " + } + content = strings.TrimRight(content, ", ") + content += "]" + return content, nil +} + // Config 任务加载的默认配置 type Config struct { - Session int `yaml:"session"` - Mode int `yaml:"mode"` - Proxies []string `yaml:"proxies"` - Retry int `yaml:"retry"` - Priority int `yaml:"priority"` - Curl string `yaml:"curl"` + Session int `yaml:"session"` + Mode int `yaml:"mode"` + Proxies []string `yaml:"proxies"` + Retry int `yaml:"retry"` + Priority int `yaml:"priority"` + Curls YamlCurls `yaml:"curls"` ExecuteInterval `yaml:"execute_interval"` ExecuteAt `yaml:"execute_at"` @@ -76,21 +116,21 @@ func NewConfig(p string) *Config { if err != nil { panic(err) } - // spew.Dump(conf) - - if conf.Curl == "" { - log.Println("the path ", p, "curl is \"\"") - } else { - if conf.Curl[0] == '@' { - curlfile, err := os.Open(conf.Curl[1:]) - defer curlfile.Close() - if err != nil { - panic(err) - } - curldata, err := ioutil.ReadAll(curlfile) - conf.Curl = strings.Trim(string(curldata), "\r\n ") - } - } + spew.Dump(conf) return conf } + +func parseCurl(curl string) string { + if curl[0] == '@' { + curlfile, err := os.Open(curl[1:]) + defer curlfile.Close() + if err != nil { + panic(err) + } + curldata, err := ioutil.ReadAll(curlfile) + return strings.Trim(string(curldata), "\r\n ") + } + + return strings.Trim(curl, "\r\n ") +} diff --git a/execute_plan.go b/execute_plan.go index 9b3c8e1..2acfd09 100644 --- a/execute_plan.go +++ b/execute_plan.go @@ -34,6 +34,13 @@ type PlanResult struct { Resp *requests.Response } +// NewExecutePlan create a plan +func NewExecutePlan() *ExecutePlan { + plan := &ExecutePlan{} + + return plan +} + // AppendIExecute 添加执行计划任务 func (ep *ExecutePlan) AppendIExecute(e IExecute) { ep.ExecuteQueue = append(ep.ExecuteQueue, e) diff --git a/execute_test.go b/execute_test.go index d150377..f5de1d1 100644 --- a/execute_test.go +++ b/execute_test.go @@ -15,13 +15,23 @@ type Person struct { } type Task struct { - GURL *curl2info.CURL + Curl *curl2info.CURL + Conf *Config Plan *ExecutePlan } +func NewTask(conf string, curlinfo string) *Task { + task := &Task{} + + task.Conf = NewConfig(conf) + task.Curl = curl2info.NewCURL(curlinfo) + + return task +} + func TestNewYaml(t *testing.T) { data := spew.Sdump(NewConfig("test.yaml")) - if !(regexp.MustCompile(`Device: \(string\) \(len=12\) "eson-OnePlus"`).MatchString(data) && regexp.MustCompile(`Sec: \(int\) 30`).MatchString(data)) { + if !(regexp.MustCompile(`Device: \(string\) \(len=12\) "eson-OnePlus"`).MatchString(data) && regexp.MustCompile(`Sec: \(int\) 30`).MatchString(data) && regexp.MustCompile(`http://is.snssdk.com/2/article/information/v24/\?`).MatchString(data)) { t.Error(data) } } @@ -41,3 +51,7 @@ func TestExecute(t *testing.T) { log.Println(resp.Content()) } } + +func TestExecutePlan(t *testing.T) { + +} diff --git a/structure.go b/structure.go new file mode 100644 index 0000000..949e02f --- /dev/null +++ b/structure.go @@ -0,0 +1,210 @@ +package imitate + +import ( + "log" + "strings" + + "github.com/davecgh/go-spew/spew" +) + +// Node 循环链表 三色标记 不确定是否会清除循环引用, 网上说会 +type Node struct { + value interface{} + prev *Node + next *Node +} + +// CircularLinked 循环链表 +type CircularLinked struct { + cursor *Node + head *Node + tail *Node + size uint64 +} + +// NewCircularLinked create a CircularLinked +func NewCircularLinked(values ...interface{}) *CircularLinked { + list := &CircularLinked{} + if len(values) > 0 { + list.Append(values...) + } + return list +} + +// Cursor get current Cursor +func (list *CircularLinked) Cursor() *Node { + if list.cursor == nil { + list.cursor = list.head + } + return list.cursor +} + +// CursorNext get next Cursor +func (list *CircularLinked) CursorNext() *Node { + list.cursor = list.Cursor().next + return list.cursor +} + +// CursorPrev get prev Cursor +func (list *CircularLinked) CursorPrev() *Node { + list.cursor = list.Cursor().prev + return list.cursor +} + +// CursorToHead cursor move to head +func (list *CircularLinked) CursorToHead() *Node { + list.cursor = list.head + return list.cursor +} + +// CursorToTail cursor move to tail +func (list *CircularLinked) CursorToTail() *Node { + list.cursor = list.tail + return list.cursor +} + +// Append a value (one or more) at the end of the list (same as Append()) +func (list *CircularLinked) Append(values ...interface{}) { + for _, value := range values { + node := &Node{value: value} + if list.size == 0 { + list.head = node + list.tail = node + node.next = node + node.prev = node + } else { + list.tail.next = node + node.next = list.head + node.prev = list.tail + list.tail = node + } + list.size++ + } +} + +// Remove 移除一些节点 +func (list *CircularLinked) Remove(node *Node) { + + switch list.size { + case 0: + list.errorNotInList(node) + case 1: + if list.head == node { + list.head = nil + list.tail = nil + node.next = nil + node.prev = nil + list.cursor = nil + list.size-- + } else { + list.errorNotInList(node) + } + case 2: + + node.prev = nil + node.next = nil + + switch node { + case list.head: + list.head = list.tail + list.tail.prev = list.head + list.head.next = list.tail + list.cursor = list.head + list.size-- + case list.tail: + list.tail = list.head + list.tail.prev = list.head + list.head.next = list.tail + list.cursor = list.head + list.size-- + default: + list.errorNotInList(node) + } + + default: + switch node { + case list.head: + _, next := list.cutAndSplice(node) + list.size-- + list.head = next + if list.cursor == node { + list.cursor = next + } + case list.tail: + prev, _ := list.cutAndSplice(node) + list.size-- + list.tail = prev + if list.cursor == node { + list.cursor = prev + } + default: + _, next := list.cutAndSplice(node) + list.size-- + if list.cursor == node { + list.cursor = next + } + } + } + +} + +// LookCursor for list show +func (list *CircularLinked) LookCursor() string { + cursor := list.Cursor() + + content := "->[" + cur := list.head + if list.size != 0 { + for size := uint64(0); size < list.size; size++ { + if cursor == cur { + content += "(" + spew.Sprint(cur.value) + ")" + ", " + } else { + content += spew.Sprint(cur.value) + ", " + } + + cur = cur.next + } + } + content = strings.TrimRight(content, ", ") + showlen := len(content) + if showlen >= 64 { + showlen = 32 + } + content += "]" + content[0:showlen] + " ..." + return content +} + +// Clear for list show +func (list *CircularLinked) Clear() { + if list.size != 0 { + list.head.prev = nil + list.tail.next = nil + list.head = nil + list.tail = nil + list.cursor = nil + list.size = 0 + } +} + +// Size for list show +func (list *CircularLinked) Size() uint64 { + return list.size +} + +func (list *CircularLinked) errorNotInList(node *Node) { + log.Println("the node value ", spew.Sprint(node), " is not in list") +} + +func (list *CircularLinked) cutAndSplice(node *Node) (prev, next *Node) { + prev = node.prev + next = node.next + + prev.next = next + + next.prev = prev + + node.prev = nil + node.next = nil + + return prev, next +} diff --git a/structure_test.go b/structure_test.go new file mode 100644 index 0000000..534c8f8 --- /dev/null +++ b/structure_test.go @@ -0,0 +1,67 @@ +package imitate + +import ( + "testing" +) + +func TestCircularLinkedLookUp(t *testing.T) { + + cl := NewCircularLinked(1, 2, 3, 4, 5, 6) + if !(cl.head.value.(int) == 1 && cl.tail.value.(int) == 6) { + t.Error(cl.LookCursor()) + } + + cl = NewCircularLinked(6, 2, 3, 4, 5, 1) + if !(cl.head.value.(int) == 6 && cl.tail.value.(int) == 1) { + t.Error("New List is error:", cl.LookCursor()) + } + + if cl.CursorNext().value.(int) != 2 { + t.Error("CursorNext error:", cl.LookCursor()) + } + + cl = NewCircularLinked(0, 1, 2, 3, 4, 5) + for i := 0; i < 6; i++ { + if cl.Cursor().value.(int) != i { + t.Error("CursorNext error:", cl.LookCursor()) + } + cl.CursorNext() + } + + for i := 0; i < 6; i++ { + if cl.Cursor().value.(int) != i { + t.Error("CursorNext loop error:", cl.LookCursor()) + } + cl.CursorNext() + } + + cl = NewCircularLinked(6, 2, 3, 4, 5, 1) + cl.Remove(cl.Cursor()) + if cl.Cursor().value != 2 { + t.Error("Remove Head is error", cl.LookCursor()) + } + cl.Remove(cl.CursorToTail()) + if cl.Cursor().value != 5 { + t.Error("Remove CursorToTail is error", cl.LookCursor()) + } + + cl.Remove(cl.CursorToHead()) + if cl.Cursor().value != 3 { + t.Error("Remove CursorToHead is error", cl.LookCursor()) + } + + limitCount := 0 + for cl.Size() > 0 { + cl.Remove(cl.Cursor()) + limitCount++ + if limitCount >= 10 { + t.Error("Not Clear", cl.LookCursor()) + break + } + } + + cl.Remove(cl.CursorToHead()) // nil is not in list is success! + if cl.head != nil || cl.tail != nil || cl.cursor != nil { + t.Error("Remove Boundary error") + } +} diff --git a/test.yaml b/test.yaml index 6805794..c871766 100644 --- a/test.yaml +++ b/test.yaml @@ -4,7 +4,8 @@ proxies : ["socks5://10.10.10.1:8080", "socks5://10.10.10.1:8082", "socks5://10. retry : 0 priority : 10000 -curl : "@test.curl" +# curls: "@test.curl" +curls : ["@test.curl", "curl 'https://segmentfault.com/a/1190000004850183' -H 'authority: segmentfault.com' -H 'cache-control: max-age=0' -H 'upgrade-insecure-requests: 1' -H 'user-agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1' -H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8' -H 'accept-encoding: gzip, deflate, br' -H 'accept-language: zh' -H 'cookie: _ga=GA1.2.923011700.1533555581; PHPSESSID=web1~3uf1ijg2h8nctqdof7aa27g1p8; Hm_lvt_e23800c454aa573c0ccb16b52665ac26=1542945905,1542945911,1542967158,1542969075; Hm_lpvt_e23800c454aa573c0ccb16b52665ac26=1542969075' --compressed"] # next_do : "doothers"