upload anki proxy
This commit is contained in:
		
						commit
						baa77f4468
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| *.log | ||||
| .idea/* | ||||
| */.ipynb_checkpoints/* | ||||
							
								
								
									
										7
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
							
								
								
									
										10
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							| @ -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= | ||||
							
								
								
									
										21
									
								
								http/miss.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								http/miss.go
									
									
									
									
									
										Normal file
									
								
							| @ -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)) | ||||
| } | ||||
							
								
								
									
										51
									
								
								proxy/client.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								proxy/client.go
									
									
									
									
									
										Normal file
									
								
							| @ -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()) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										85
									
								
								proxy/packetconnection.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								proxy/packetconnection.go
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										91
									
								
								proxy/reader.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								proxy/reader.go
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| } | ||||
							
								
								
									
										80
									
								
								proxy/request.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								proxy/request.go
									
									
									
									
									
										Normal file
									
								
							| @ -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() | ||||
| } | ||||
							
								
								
									
										71
									
								
								proxy/server.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								proxy/server.go
									
									
									
									
									
										Normal file
									
								
							| @ -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)) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										37
									
								
								proxy/type.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								proxy/type.go
									
									
									
									
									
										Normal file
									
								
							| @ -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() | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								python/__pycache__/http.cpython-39.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								python/__pycache__/http.cpython-39.pyc
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								python/__pycache__/http2.cpython-39.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								python/__pycache__/http2.cpython-39.pyc
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										155
									
								
								python/anki.ipynb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								python/anki.ipynb
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| } | ||||
							
								
								
									
										84
									
								
								python/http2.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								python/http2.py
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
							
								
								
									
										64
									
								
								python/test.ipynb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								python/test.ipynb
									
									
									
									
									
										Normal file
									
								
							| @ -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": [ | ||||
|        "<Response [200]>" | ||||
|       ] | ||||
|      }, | ||||
|      "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 | ||||
| } | ||||
							
								
								
									
										14
									
								
								run/client/client.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								run/client/client.go
									
									
									
									
									
										Normal file
									
								
							| @ -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()) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										15
									
								
								run/server/server.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								run/server/server.go
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										11
									
								
								run/test/test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								run/test/test.go
									
									
									
									
									
										Normal file
									
								
							| @ -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) | ||||
| } | ||||
							
								
								
									
										70
									
								
								zlog/test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								zlog/test
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
							
								
								
									
										16
									
								
								zlog/type.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								zlog/type.go
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| ) | ||||
							
								
								
									
										98
									
								
								zlog/zlog.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								zlog/zlog.go
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user