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