From baa77f4468f2cab4d96f4580a2d797fe710ae09c Mon Sep 17 00:00:00 2001 From: ouczb Date: Tue, 13 Feb 2024 19:45:15 +0800 Subject: [PATCH] upload anki proxy --- .gitignore | 3 + go.mod | 7 ++ go.sum | 10 ++ http/miss.go | 21 ++++ proxy/client.go | 51 ++++++++ proxy/packetconnection.go | 85 +++++++++++++ proxy/reader.go | 91 ++++++++++++++ proxy/request.go | 80 ++++++++++++ proxy/server.go | 71 +++++++++++ proxy/type.go | 37 ++++++ python/__pycache__/http.cpython-39.pyc | Bin 0 -> 3855 bytes python/__pycache__/http2.cpython-39.pyc | Bin 0 -> 3817 bytes python/anki.ipynb | 155 ++++++++++++++++++++++++ python/http2.py | 84 +++++++++++++ python/test.ipynb | 64 ++++++++++ run/client/client.go | 14 +++ run/server/server.go | 15 +++ run/test/test.go | 11 ++ zlog/test | 70 +++++++++++ zlog/type.go | 16 +++ zlog/zlog.go | 98 +++++++++++++++ 21 files changed, 983 insertions(+) create mode 100644 .gitignore create mode 100644 go.mod create mode 100644 go.sum create mode 100644 http/miss.go create mode 100644 proxy/client.go create mode 100644 proxy/packetconnection.go create mode 100644 proxy/reader.go create mode 100644 proxy/request.go create mode 100644 proxy/server.go create mode 100644 proxy/type.go create mode 100644 python/__pycache__/http.cpython-39.pyc create mode 100644 python/__pycache__/http2.cpython-39.pyc create mode 100644 python/anki.ipynb create mode 100644 python/http2.py create mode 100644 python/test.ipynb create mode 100644 run/client/client.go create mode 100644 run/server/server.go create mode 100644 run/test/test.go create mode 100644 zlog/test create mode 100644 zlog/type.go create mode 100644 zlog/zlog.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3b65fdd --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.log +.idea/* +*/.ipynb_checkpoints/* \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..cd33f9c --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module zproxy + +go 1.20 + +require go.uber.org/zap v1.25.0 + +require go.uber.org/multierr v1.10.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c4b6d80 --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= +go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/http/miss.go b/http/miss.go new file mode 100644 index 0000000..14a8574 --- /dev/null +++ b/http/miss.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + "io/ioutil" + "net/http" +) + +func main() { + resp, err := http.Get("https://zh.xhamster.com/?ref=porndude") + if err != nil { + fmt.Println("http get error", err) + return + } + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + fmt.Println("read error", err) + return + } + fmt.Println(string(body)) +} diff --git a/proxy/client.go b/proxy/client.go new file mode 100644 index 0000000..40389a7 --- /dev/null +++ b/proxy/client.go @@ -0,0 +1,51 @@ +package proxy + +import ( + "net" + "zproxy/zlog" +) + +type UClientProxy struct { + ServerConn *UPacketConnection +} + +func NewClientProxy() *UClientProxy { + return &UClientProxy{} +} +func (client *UClientProxy) ServeTCP(serverAddr string, clientAddr string) error { + conn, err := net.Dial("tcp", serverAddr) + if err != nil { + return err + } + zlog.Infof("connect server %s", serverAddr) + client.ServerConn = NewPacketConnection(conn) + _, err = client.ServerConn.Write([]byte("anki")) + if err != nil { + return err + } + for { + data := make([]byte, 4) + _, err := client.ServerConn.Read(data, 0, 4) + if err != nil { + return err + } + if string(data) != "anki" { + zlog.Error("rcv package error:", data) + client.ServerConn.Clear() + continue + } + conn, err := net.Dial("tcp", clientAddr) + if err != nil { + zlog.Error("connect local anki error: ", err.Error(), clientAddr) + client.ServerConn.ForwardError(err) + continue + } + pc := NewPacketConnection(conn) + client.ServerConn.Forward(pc) + pc.Forward(client.ServerConn) + err = pc.Close() + if err != nil { + zlog.Error("close local anki error: ", err.Error()) + } + } +} diff --git a/proxy/packetconnection.go b/proxy/packetconnection.go new file mode 100644 index 0000000..f99fbd6 --- /dev/null +++ b/proxy/packetconnection.go @@ -0,0 +1,85 @@ +package proxy + +import ( + "net" + "zproxy/zlog" +) + +type UPacketConnection struct { + *UHttpRequest +} + +// 创建连接的方法 +func NewPacketConnection(conn net.Conn) *UPacketConnection { + //初始化Conn属性 + c := &UPacketConnection{ + UHttpRequest: NewHttpRequest(conn), + } + return c +} +func (pc *UPacketConnection) Forward(target *UPacketConnection) { + pc.DataSize = 0 + pc.IsLoadHeader = false + for !pc.IsLoadHeader { + data, err := pc.ReadLine() + if err != nil { + zlog.Error("read header line error: ", err.Error()) + return + } + _, err = target.Write(data) + if err != nil { + zlog.Error("write header line error: ", err.Error()) + return + } + } + if pc.DataSize == 0 { + return + } + data := make([]byte, 1024) + for pc.DataSize > 0 { + size := min(pc.DataSize, 1024) + n, err := pc.Read(data, 0, size) + if err != nil { + zlog.Error("read body error: ", err.Error()) + return + } + pc.DataSize -= n + zlog.Infof("read body %d %s", n, data[:n]) + _, err = target.Write(data[:n]) + if err != nil { + zlog.Error("write body error: ", err.Error()) + return + } + } +} +func (pc *UPacketConnection) Close() error { + err := pc.Conn.Close() + return err +} +func (pc *UPacketConnection) ForwardError(err error) { + pc.DataSize = 0 + pc.IsLoadHeader = false + zlog.Infof("forward error: ", err.Error()) + for !pc.IsLoadHeader { + _, err := pc.ReadLine() + if err != nil { + zlog.Error("read header line error: ", err.Error()) + return + } + } + for pc.DataSize > 0 { + data := make([]byte, 1024) + size := min(pc.DataSize, 1024) + n, err := pc.Read(data, 0, size) + if err != nil { + zlog.Error("Read body error: ", err.Error()) + return + } + pc.DataSize -= n + } + err = pc.WriteError(err) + if err != nil { + zlog.Error("write error http error: ", err.Error()) + return + } +} diff --git a/proxy/reader.go b/proxy/reader.go new file mode 100644 index 0000000..d16116e --- /dev/null +++ b/proxy/reader.go @@ -0,0 +1,91 @@ +package proxy + +import ( + "bytes" + "io" +) + +func min(a int, b int) int { + if a < b { + return a + } + return b +} + +type UReader struct { + io io.Reader + buf []byte + r, w int + err error +} + +func NewReader(io io.Reader) *UReader { + return &UReader{ + io: io, + buf: make([]byte, 4096), + r: 0, + w: 0, + } +} +func (b *UReader) Read(data []byte, s int, e int) (int, error) { + n := e - s + rn := 0 + for rn < n { + d := min(b.w-b.r, n-rn) + if d > 0 { + copy(data[s+rn:s+rn+d], b.buf[b.r:b.r+d]) + b.r += d + rn += d + if rn >= n { + break + } + } + err := b.fill() + if err != nil { + return rn, err + } + } + return rn, nil + +} +func (b *UReader) ReadLine() ([]byte, error) { + line, err := b.ReadSlice('\n') + return line, err +} +func (b *UReader) ReadSlice(delim byte) ([]byte, error) { + s := 0 // search start index + for { + // Search buffer. + if i := bytes.IndexByte(b.buf[b.r+s:b.w], delim); i >= 0 { + i += s + 1 + b.r += i + return b.buf[b.r-i : b.r], nil + } + err := b.fill() + if err != nil { + return b.buf[b.r:], err + } + } +} +func (b *UReader) fill() error { + d := b.w - b.r + if d >= len(b.buf) { + b.r = 0 + b.w = 0 + return ErrBufferFull + } + // Slide existing data to beginning. + if b.r > 0 { + copy(b.buf, b.buf[b.r:b.w]) + b.w -= b.r + b.r = 0 + } + // Read new data: try a limited number of times. + n, err := b.io.Read(b.buf[b.w:]) + b.w += n + return err +} +func (b *UReader) Clear() { + b.r = 0 + b.w = 0 +} diff --git a/proxy/request.go b/proxy/request.go new file mode 100644 index 0000000..51297dd --- /dev/null +++ b/proxy/request.go @@ -0,0 +1,80 @@ +package proxy + +import ( + "bytes" + "net" + "strconv" + "strings" +) + +type UHttpRequest struct { + Conn net.Conn + io *UReader + IsLoadHeader bool + DataSize int +} + +func NewHttpRequest(conn net.Conn) *UHttpRequest { + return &UHttpRequest{ + Conn: conn, + io: NewReader(conn), + IsLoadHeader: false, + DataSize: 0, + } +} +func (req *UHttpRequest) ReadLine() ([]byte, error) { + line, err := req.io.ReadLine() + if err != nil { + return line, err + } + if !req.IsLoadHeader && bytes.Equal(line, []byte("\r\n")) { + req.IsLoadHeader = true + } + if !req.IsLoadHeader { + k, v, ok := bytes.Cut(line, []byte(":")) + if !ok { + return line, err + } + if bytes.Equal(k, []byte("Content-Length")) { + nv := strings.Trim(string(v), " \r\n") + n, err := strconv.ParseUint(nv, 10, 63) + if err != nil { + return line, err + } + req.DataSize = int(n) + } + } + return line, err +} +func (req *UHttpRequest) Read(data []byte, s int, e int) (int, error) { + return req.io.Read(data, s, e) +} +func (req *UHttpRequest) Write(data []byte) (int, error) { + return req.Conn.Write(data) +} +func (req *UHttpRequest) WriteError(err error) error { + return req.WriteHttp([]byte("HTTP/1.1 200 OK\r\n"), []byte(err.Error())) +} +func (req *UHttpRequest) WriteHttp(header []byte, data []byte) error { + _, err := req.Write(header) + if err != nil { + return err + } + var bufBody bytes.Buffer + bufBody.WriteString("{\n \"error\" : \"") + bufBody.WriteString(string(data)) + bufBody.WriteString("\"\n}") + var bufWrap bytes.Buffer + bufWrap.WriteString("Content-Length:") + bufWrap.WriteString(strconv.Itoa(bufBody.Len())) + bufWrap.WriteString("\r\n\r\n") + _, err = req.Write(bufWrap.Bytes()) + if err != nil { + return err + } + _, err = req.Write(bufBody.Bytes()) + return err +} +func (req *UHttpRequest) Clear() { + req.io.Clear() +} diff --git a/proxy/server.go b/proxy/server.go new file mode 100644 index 0000000..452fc9a --- /dev/null +++ b/proxy/server.go @@ -0,0 +1,71 @@ +package proxy + +import ( + "net" + "zproxy/zlog" +) + +type UServerProxy struct { + AnkiConn *UPacketConnection +} + +func NewServerProxy() *UServerProxy { + return &UServerProxy{} +} +func (server *UServerProxy) NewTcpConnection(client *UPacketConnection) { + defer func() { + if client == server.AnkiConn { + return + } + err := client.Close() + if err != nil { + zlog.Error("close client error: ", err) + } + }() + data := []byte("anki0000") + _, err := client.Read(data, 4, 8) + if err != nil { + zlog.Error("read client error: ", client.Conn.RemoteAddr(), err.Error()) + return + } + zlog.Infof("new client %s %s", client.Conn.RemoteAddr(), data[4:]) + if string(data[4:]) == "anki" { + server.AnkiConn = client + return + } + if server.AnkiConn == nil { + client.ForwardError(ErrNoAnkiProxy) + return + } + _, err = server.AnkiConn.Write(data) + if err != nil { + return + } + client.Forward(server.AnkiConn) + server.AnkiConn.Forward(client) +} +func (server *UServerProxy) ServeTCP(listenAddr string) error { + // listenAddr 只能填端口号 + ln, err := net.Listen("tcp", listenAddr) + if err != nil { + zlog.Error("listen server error: ", err.Error(), listenAddr) + return err + } + zlog.Infof("listen server %s", listenAddr) + defer func(ln net.Listener) { + err := ln.Close() + if err != nil { + zlog.Error("close listen server error: ", err.Error(), listenAddr) + } + }(ln) + for { + conn, err := ln.Accept() + if err != nil { + if IsTimeoutError(err) { + continue + } + return err + } + go server.NewTcpConnection(NewPacketConnection(conn)) + } +} diff --git a/proxy/type.go b/proxy/type.go new file mode 100644 index 0000000..6141b6a --- /dev/null +++ b/proxy/type.go @@ -0,0 +1,37 @@ +package proxy + +type timeoutError interface { + Timeout() bool // Is it a timeout error +} + +// fundamental is an error that has a message and a stack, but no caller. +type errors struct { + msg string +} + +func (e errors) Error() string { + return e.msg +} + +func NewError(msg string) error { + return errors{msg: msg} +} + +var ( + ErrBufferFull = NewError("read: buffer full") + ErrNoAnkiProxy = NewError("anki: no client proxy connect") +) +var ( + ServerAddr = ":8765" + RemoteServerAddr = "175.24.226.114" + ServerAddr + ClientAddr = "127.0.0.1:8765" +) + +// IsTimeoutError checks if the error is a timeout error +func IsTimeoutError(err error) bool { + if err == nil { + return false + } + ne, ok := err.(timeoutError) + return ok && ne.Timeout() +} diff --git a/python/__pycache__/http.cpython-39.pyc b/python/__pycache__/http.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7bf9cfd70c8a7c86be457fbd47a46650a5df4c23 GIT binary patch literal 3855 zcmcIn%W@mX744oE1`mR?OiQGl#FL7X2#y8O7Np3wqDYbaNG!8bky5IfQfg|59*P43 z7^r(-Nhoj=uqxVU<$Qp+#BXGkZ|GI3veGYP<#T%g5EN}~Tp6%?`Z;~?x%ZyFj8|4F z3{U>A|A=pEjQy87%a4Q34HWeRm0*H*Sy;Sz$W7l0E%UZR8*i)Y^xV+pw8rjwy;4{* zZH~4dmeF>EoAR*o1rweq9Wqf$tWI@ehgIQ=@*xXrn5l>=W~vh_ToL>(Yt&xibhh2# z+I=kJfkLBp=l-8>W!Zk3{3({B%3oC?FWh{X^z)JYIvb_kZhY}_b1OK1KkbX`u?n{D z1s`rTw>}LpaHaKW@Z?IX5!@UMy2<@y=c_coc=^(Ao0qNx=fC>$-q&|N2)gNh5`2-g z_p?TDYfomq_ZN)e1ZZkrvM^!jjCl`x|=AKX8r9peP#Yoo60Q|bsbgCI{bw-W=EW}u_fQn?Xe~J zb3SH~GiDv9Bqg~UW14A^kF}fNhDI$j-_Z= z+8F{>?F?e28ou^r@@SZ-TuE{Y?MG4CPxB~}B$h6+o=HynsKPqY&c^Sy?x z9hG!20z7(C7Qvi^g;JRdX% zPh}aas3MN4K6wW%2B>SzES_JSWV^31zz%C{Sqq%eS# z@iz%Nv`D&Ckz_^n2DRQqMMKJbpO0$ugK6WbLl^dX`$Lj$~b* z&hn_i>!pfiEZ*km&mYpC)T5$k??2cs7hG6}{sA9T%-Y+hHqe&|LG?3KIeW$?{CL}h zAMj_`8ZEXPjIolQ`FUnL+3Fbp9rKAb1JYE`E^UHsNCI7tiq%m&695;(Z(~@#gNhEMQMpMY zgd`56PrZevB0w4Uc-`{&X!8e;HPYg%1dx1}Dr1+QQp7Im?TcO|KcwFwt* zh%<*UVpv1}P4w5rTc*Dv&WdwbS2vXQj&{BT&adIKCS)9213zaIc3_RI7x00C*T7d` zHPkj(%sGP5BiHbkwXJQH%Z6us(|EHkse(BHeExKh=+)?9lFtk#(sr(^OPz*Ygt-Z~ zUqFBY>f<;dsv+Q&xgkL_71$5fTOnnRnT9Z)KV%Imw@}pks3_<=P{vTRbwEm3V;jm@ zhL&x#LDfg_;;BW1>u^rCbSr2xI1XkvLMw$5Hoj5 z5@KKj9vc5ow1&Kv* zc^MO1r=*-2pD;f`(FFGb@;{)HvI9@gohkW2A-68TPs2YwgrF}I>5SA5KrmNTP(|3V8(z^4Q;@m>Zj}BOfpjvDNV&&0^6AkbVnGy*{BS0&+Ou4*4GM%I9q)f6`fao6Hv7RH%B;PnfLPT#^9QT&f zQCT0?&uy&KE~U##{vPf5jbv;{6#oiThLXqy3j+0gqMUkx)BI|nOtAP{m6RYz%049J zJbG0myYaA_N3$fn$OX4({zIyW(hOsmh>?Z_0~#YLkmUabCm!3+v`o(UbIejyD{?*L zj9$gT&-Gp3_sbryAnQRENvj%lNo;PEH{`3GQ8(SuWlGlaEbFRSrnN`6Z1HbGCzi!O u8RbP^&zjgO$!&@(AfOhVvV`11NbO%MlH%(eD@+LZd;=KL&$rIheE&Pb1PB2D literal 0 HcmV?d00001 diff --git a/python/__pycache__/http2.cpython-39.pyc b/python/__pycache__/http2.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..93f7664b2cbb57f6d06d16dac6faee63abc5c6d5 GIT binary patch literal 3817 zcmcInOLH5?5uVuxuy_!pWmzKaJT{4w2#y8O5~RqsqLL!{kyvJ>BBfNdrPS6EvlJIx z>_RgOOG1H{kX6w|r=%)Z>4<;gKak5Dlau~JPWgHk0721q4z4UXv-8~P{<`~{X0)EEbp~$Wa#~}jl|ePA znl?w<3us2(y=jjev;zz!P16SYGYG%-^b4a_tStYAg(yR6-Oh11zq zn``&6jD`x0=AHY0xRvL7N&Ndrj_ZF?u{?kCVVo6X`DH#%(lokoxwGk?yPsqtf2{ni zd;SNToz0JZ3|#4c>_55EZTmNe!!*7hZ-0>#7cO7=b?4F*|J)a!-}~~;`+l12#r|h; zZ!d5Aw{~Sdh%a33b~ZZ~uXZ;(AAacHjdmiL%y#uiyyeG6=LU*;A63ifKnWB+s^b^p*KTZ7R1=)OAz^>+=`ZguUdPO)U9dVNWc< zpYsU|oeAqZeV0ypPP6PqWx{Elz)V;b43N5nrni%%aTX2Ydu<-Hl80F?<4`237fI2! zv@-&#+8IVlwLR_0_|Ygl&eEJf6C+8RJdvptN|MkJo0Hb>>3#ELt*qs7=LS*FppMuowI#BiFpkrhKbyNs0rA z8GRL_LyM$K6^T|>Z&2$^R5YZ__xZRvKbSV2ICNn!+EN}mGX##6r!a`KR`HUg(fnL9 z@Y=aFPwVIBw&v%SIJcofg-k-m3`1QH!$B@aDYctn_-GWR<&445Xkm_AQqLS{bR_e7 zbXJ8Lyj87R#^gPY{`?{RNj)lx_WqUaaKVLj=O@-x_6 z!f1`pk#B{ul)3C&OY>fos_UKbaZ>Cqb!ii9LlWp#SgsCxxd6BrejCH`9aMB6jmixg zAtZ4ied;YV6#>e4g}1Bm}Irpnmmhtx8ktRHPXjX_0_A`~jp$Gb&zK#k!W^w0E@gIdJ|CLhC@ri8b^JcEI+niS+_LP!bym z3$%vX28}r{Vf4^71ZHh%TNSchF}`WMSyxp_odCXgI*j#d_%JSJ1`|oI(2b=|+b+Z0 zgxk*`Kne9x91ztI@XB0~pqV=C2kWhnGDl297|$QF29;YV>OE8x^nEB}xY^n#C9H`J z!l7fb?ln?9ty}`;tbiQ>O55j$OW3vVwmIdphe4qG)h6t z+zCmDfen;b(I{|zQowUo@V-Tm0y?|z2KqA12A_J` z9m*stBn74FPE>f0H`$B4%mXEU@eRG{IV1!218w#Wg@e848+G-b>W_ z2GHeYOl+Qza%OzO{1`$~GvwuqZfhvp>JPZzJEZg|&e+Pp|`f z-SPkm#NzPZ1Xt@XNk+K&cjmv;7s5SLr>mH^6E%ZdN%2 z&smI|1!evPDWUPrS6}0sbiAMJfy+^f{z8@EdR=af$wUir5w>Ef4^RY=NZ^s0z=qET9ev+TOe@iuAx1FDFs3=^10 zkcQlR8Y6M#ZK@2{9ofaSOfL8n%u=)}aw+73mAZqU>$#ri)hfJ>YzEmOt!lR7>r~V8{tLTh{~`bY literal 0 HcmV?d00001 diff --git a/python/anki.ipynb b/python/anki.ipynb new file mode 100644 index 0000000..1626197 --- /dev/null +++ b/python/anki.ipynb @@ -0,0 +1,155 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 13, + "id": "1664172b", + "metadata": {}, + "outputs": [], + "source": [ + "from http2 import *\n", + "class AnkiClient(Http):\n", + " def __init__(self):\n", + " Http.__init__(self)\n", + " self.url = 'http://127.0.0.1:8764'\n", + " self.version = None\n", + " def api(self, data):\n", + " print(data)\n", + " data = json.dumps(data)\n", + " res = self._post(self.url, data)\n", + " return res\n", + " def make_version(self):\n", + " self.version = self.api({\"action\":\"version\"})\n", + " return self.version\n", + " def deckNames(self):\n", + " return self.api({\"action\":\"deckNames\"})\n", + " def modelNames(self):\n", + " return self.api({\"action\":\"modelNames\"})\n", + " def modelFieldNames(self, modelName):\n", + " return self.api({\"action\":\"modelFieldNames\", \"params\" :{\"modelName\" : modelName}})\n", + " def addNote(self, note):\n", + " return self.api({\"action\":\"addNote\", \"params\" : {\"note\": note}})" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "ee987c62", + "metadata": {}, + "outputs": [], + "source": [ + "anki = AnkiClient()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "58e77a6b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'action': 'deckNames'}\n", + "_post http://127.0.0.1:8764\n" + ] + }, + { + "data": { + "text/plain": [ + "b'[\"Git\", \"\\\\u53e5\\\\u7d20\", \"\\\\u793a\\\\u4f8b\\\\u724c\\\\u7ec4\", \"\\\\u7cfb\\\\u7edf\\\\u9ed8\\\\u8ba4\", \"\\\\u82f1\\\\u8bed\", \"\\\\u8d56\\\\u4e16\\\\u96c4\\\\u97f3\\\\u6807\", \"\\\\u97f3\\\\u6807\"]'" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t = anki.deckNames()\n", + "t" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "c3b5b237", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "b'{\\n error = \"anki: no client proxy connect\"\\n}'" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "53bd0e19", + "metadata": {}, + "outputs": [], + "source": [ + "b = b'{\\n error = \"anki: no client proxy connect\"\\n}'" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "9d89217c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " error = \"anki: no client proxy connect\"\n", + "}\n" + ] + } + ], + "source": [ + "print(b.decode())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "203e9f90", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/python/http2.py b/python/http2.py new file mode 100644 index 0000000..a745f48 --- /dev/null +++ b/python/http2.py @@ -0,0 +1,84 @@ +import inspect +import json, requests , zlib +from functools import wraps +from http.cookiejar import LWPCookieJar +import http.cookiejar as cookielib +default_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\ +/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} +class Session(requests.Session): + def __init__(self, headers={}, cookie_file=None): + requests.Session.__init__(self) + if cookie_file: + self.cookies = LWPCookieJar(filename = cookie_file) + self.cookies.load(ignore_discard = True) + self.update(headers) + self.auth = ('user', 'pass') + def save(self, filename = None): + self.cookies.save() + def update(self, headers): + self.headers.update(headers) +def http_error(code): + def _with(func): + @wraps(func) + def _deco(self, url): + return func(self, url) + _deco.__error_code__ = code + return _deco + return _with +class Http(): + def __init__(self, headers = default_headers, session = None): + session = session or Session() + session.update(headers) + self.session = session + self._type = 'str' + self._error_dict = self._get_error_dict() + def _gets(self, url, data = None): + res = self.session.get(url, params = data) + self._error(res, url) + return self._res_data(res, self._type) + def _posts(self, url, data = None): + res = self.session.get(url, params = data) + self._error(res, url) + return self._res_data(res, self._type) + def _get(self, url, data = None): + print("_get", url) + res = requests.get(url, params = data, headers = self.session.headers) + self._error(res, url) + return self._res_data(res, self._type) + def _post(self, url, data): + print("_post", url) + res = requests.get(url, data = data, headers = self.session.headers) + self._error(res, url) + return self._res_data(res, self._type) + def _get_error_dict(self): + error_dict = {} + methods = inspect.getmembers(self, predicate=inspect.ismethod) + for method in methods: + error_code = getattr(method[1], '__error_code__', None) + if error_code: + error_dict[error_code] = method[1] + return error_dict + def _error(self, res, url): + code = res.status_code + if code == 200: + return + print(res.content) + if code in self._error_dict: + self._error_dict[code](url) + return + raise RuntimeError(code + '- unknown error ' + url) + @http_error(403) + def _error_403(self, url): + raise RuntimeError('error:403 - Forbidden ' + url) + @http_error(404) + def _error_404(self, url): + raise RuntimeError('error:404 - Not Found ' + url) + def _res_data(self, res, _type): +# encoding = None +# if 'Content-Encoding' in res.headers: +# encoding = res.headers['Content-Encoding'] +# if encoding == 'gzip': +# res.content = zlib.decompress(res.content, 16 + zlib.MAX_WBITS) +# if _type == 'json': +# return json.loads(res.content) + return res.content \ No newline at end of file diff --git a/python/test.ipynb b/python/test.ipynb new file mode 100644 index 0000000..6948fe8 --- /dev/null +++ b/python/test.ipynb @@ -0,0 +1,64 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "3f40720a", + "metadata": {}, + "outputs": [], + "source": [ + "import requests" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d2986616", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "requests.get(\"http://localhost:8080/\",data = \"helloworld\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f2dd59b", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/run/client/client.go b/run/client/client.go new file mode 100644 index 0000000..2e89e72 --- /dev/null +++ b/run/client/client.go @@ -0,0 +1,14 @@ +package main + +import ( + "zproxy/proxy" + "zproxy/zlog" +) + +func main() { + client := proxy.NewClientProxy() + err := client.ServeTCP(proxy.RemoteServerAddr, proxy.ClientAddr) + if err != nil { + zlog.Error("exist client remote proxy: ", err.Error()) + } +} diff --git a/run/server/server.go b/run/server/server.go new file mode 100644 index 0000000..87f17d6 --- /dev/null +++ b/run/server/server.go @@ -0,0 +1,15 @@ +package main + +import ( + "zproxy/proxy" + "zproxy/zlog" +) + +func main() { + server := proxy.NewServerProxy() + err := server.ServeTCP(proxy.ServerAddr) + if err != nil { + zlog.Error("exist server proxy: ", err.Error()) + return + } +} diff --git a/run/test/test.go b/run/test/test.go new file mode 100644 index 0000000..b698c65 --- /dev/null +++ b/run/test/test.go @@ -0,0 +1,11 @@ +package main + +import "net/http" + +func main() { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(200) + w.Write([]byte("ok")) + }) + http.ListenAndServe(":8080", nil) +} diff --git a/zlog/test b/zlog/test new file mode 100644 index 0000000..6f0f364 --- /dev/null +++ b/zlog/test @@ -0,0 +1,70 @@ +from .http import * +import json,functools +class util: + def api(func): + @functools.wraps(func) + def wrapper(self,**kwargs): + self._api({"params" : kwargs , "action":func.__name__ }) + self.res = func(self, **kwargs) or self.res + return self.res + return wrapper +class AnkiClient(Http): + util = util + def __init__(self, url = None): + Http.__init__(self) + self.url = url or 'http://127.0.0.1:8765' + self._version = None + self.res = None + def _api(self, data): + if self._version and type(self._version) == int: + data["version"] = self._version + data = json.dumps(data) + res = self._post(self.url, data) + self.res = json.loads(res) + return self.res + @util.api + def version(self): + self._version = self.res + pass + @util.api + def deckNames(self): + pass + @util.api + def modelNames(self): + pass + @util.api + def modelFieldNames(self, modelName = "示例牌组"): + pass + @util.api + def modelFieldDescriptions(self, modelName = "示例牌组"): + pass + @util.api + def modelTemplates(self, modelName = "示例牌组"): + pass + @util.api + def addNote(self, note = {}): + pass + @util.api + def findNotes(self, query = "note:basic"): + pass + @util.api + def updateNote(self, note = {}): + pass + @util.api + def updateNoteTags(self, note = {}, tags = []): + pass + @util.api + def notesInfo(self, notes = []): + pass + @util.api + def findCards(self, query = "deck:示例牌组"): + pass + @util.api + def cardsInfo(self, cards = []): + pass + @util.api + def updateNoteFields(self, note = {}): + pass + @util.api + def createModel(self, modelName = "basic", inOrderFields = {}, cardTemplates = {}, css = None, isCloze = False): + pass \ No newline at end of file diff --git a/zlog/type.go b/zlog/type.go new file mode 100644 index 0000000..8fba21f --- /dev/null +++ b/zlog/type.go @@ -0,0 +1,16 @@ +package zlog + +import ( + "go.uber.org/zap/zapcore" +) + +// Level is type of log levels +type Level = zapcore.Level + +type FLogf = func(template string, args ...interface{}) +type FLog = func(args ...interface{}) + +var ( + Debugf, Infof, Warnf, Errorf, Panicf, Fatalf FLogf + Debug, Error, Panic, Fatal FLog +) diff --git a/zlog/zlog.go b/zlog/zlog.go new file mode 100644 index 0000000..f121cc4 --- /dev/null +++ b/zlog/zlog.go @@ -0,0 +1,98 @@ +package zlog + +import ( + "go.uber.org/zap" + "strings" +) + +var ( + cfg zap.Config + logger *zap.Logger + sugar *zap.SugaredLogger + source string + currentLevel Level +) + +func init() { + currentLevel = zap.DebugLevel + cfg = zap.NewDevelopmentConfig() + cfg.Development = true + rebuildLoggerFromCfg() +} + +// SetSource sets the component name (dispatcher/gate/game) of gwlog module +func SetSource(source_ string) { + source = source_ + rebuildLoggerFromCfg() +} + +func SetParseLevel(slv string) { + lv := ParseLevel(slv) + SetLevel(lv) +} + +// SetLevel sets the zlog level +func SetLevel(lv Level) { + currentLevel = lv + cfg.Level.SetLevel(lv) +} + +// GetLevel get the current zlog level +func GetLevel() Level { + return currentLevel +} + +// SetOutput sets the output writer +func SetOutput(outputs []string) { + cfg.OutputPaths = outputs + rebuildLoggerFromCfg() +} + +// ParseLevel converts string to Levels +func ParseLevel(s string) Level { + if strings.ToLower(s) == "debug" { + return zap.DebugLevel + } else if strings.ToLower(s) == "info" { + return zap.InfoLevel + } else if strings.ToLower(s) == "warn" || strings.ToLower(s) == "warning" { + return zap.WarnLevel + } else if strings.ToLower(s) == "error" { + return zap.ErrorLevel + } else if strings.ToLower(s) == "panic" { + return zap.PanicLevel + } else if strings.ToLower(s) == "fatal" { + return zap.FatalLevel + } + Errorf("ParseLevel: unknown level: %s", s) + return zap.DebugLevel +} + +func rebuildLoggerFromCfg() { + newLogger, err := cfg.Build() + if err != nil { + panic(err) + return + } + if logger != nil { + logger.Sync() + } + logger = newLogger + if source != "" { + logger = logger.With(zap.String("source", source)) + } + sugar = logger.Sugar() + initFLog() +} +func initFLog() { + Debugf = sugar.Debugf + Infof = sugar.Infof + Warnf = sugar.Warnf + Errorf = sugar.Errorf + Panicf = sugar.Panicf + Fatalf = sugar.Fatalf + + Debug = sugar.Debug + Error = sugar.Error + Panic = sugar.Panic + Fatal = sugar.Fatal +}