fix: content length & dns
This commit is contained in:
parent
fdee77d778
commit
90d3d676f3
2
Makefile
2
Makefile
@ -12,7 +12,7 @@ TARGET_SDK := android23
|
|||||||
TARGET_ARCH := aarch64 # optional: armv7a i686 x86_64
|
TARGET_ARCH := aarch64 # optional: armv7a i686 x86_64
|
||||||
|
|
||||||
CGO_ENABLED := 1
|
CGO_ENABLED := 1
|
||||||
GO_SRC := $(shell find . -name '*.go')
|
GO_SRC := $(shell find . -name '*.go' | grep -v '_test.go$$')
|
||||||
NDK_TOOLCHAIN := ~/Library/Android/sdk/ndk/$(NDK_VERSION)/toolchains/llvm/prebuilt/$(BUILD_MACHINE)-$(BUILD_ARCH)
|
NDK_TOOLCHAIN := ~/Library/Android/sdk/ndk/$(NDK_VERSION)/toolchains/llvm/prebuilt/$(BUILD_MACHINE)-$(BUILD_ARCH)
|
||||||
CC := $(NDK_TOOLCHAIN)/bin/$(TARGET_ARCH)-linux-$(TARGET_SDK)-clang
|
CC := $(NDK_TOOLCHAIN)/bin/$(TARGET_ARCH)-linux-$(TARGET_SDK)-clang
|
||||||
TEST_OUTPUT = '$(shell cd $(BUILD_PATH) && ./test | head -c 12)'
|
TEST_OUTPUT = '$(shell cd $(BUILD_PATH) && ./test | head -c 12)'
|
||||||
|
19
dns.go
19
dns.go
@ -48,14 +48,28 @@ func (ds *dnsservers) add(m map[string][]string) {
|
|||||||
func (ds *dnsservers) dial(ctx context.Context) (tlsConn *tls.Conn, err error) {
|
func (ds *dnsservers) dial(ctx context.Context) (tlsConn *tls.Conn, err error) {
|
||||||
ds.RLock()
|
ds.RLock()
|
||||||
defer ds.RUnlock()
|
defer ds.RUnlock()
|
||||||
|
|
||||||
|
if dialer.Timeout != 0 {
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
ctx, cancel = context.WithTimeout(ctx, dialer.Timeout)
|
||||||
|
defer cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !dialer.Deadline.IsZero() {
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
ctx, cancel = context.WithDeadline(ctx, dialer.Deadline)
|
||||||
|
defer cancel()
|
||||||
|
}
|
||||||
|
|
||||||
var conn net.Conn
|
var conn net.Conn
|
||||||
for host, addrs := range ds.m {
|
for host, addrs := range ds.m {
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
if !addr.E {
|
if !addr.E {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
conn, err = net.Dial("tcp", addr.A)
|
conn, err = dialer.DialContext(ctx, "tcp", addr.A)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
addr.E = false // no need to acquire write lock
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tlsConn = terasu.Use(tls.Client(conn, &tls.Config{ServerName: host}))
|
tlsConn = terasu.Use(tls.Client(conn, &tls.Config{ServerName: host}))
|
||||||
@ -63,6 +77,7 @@ func (ds *dnsservers) dial(ctx context.Context) (tlsConn *tls.Conn, err error) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
_ = tlsConn.Close()
|
||||||
addr.E = false // no need to acquire write lock
|
addr.E = false // no need to acquire write lock
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,7 +144,7 @@ var dotv4servers = dnsservers{
|
|||||||
|
|
||||||
var resolver = &net.Resolver{
|
var resolver = &net.Resolver{
|
||||||
PreferGo: true,
|
PreferGo: true,
|
||||||
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
|
Dial: func(ctx context.Context, _, _ string) (net.Conn, error) {
|
||||||
if canUseIPv6.Get() {
|
if canUseIPv6.Get() {
|
||||||
return dotv6servers.dial(ctx)
|
return dotv6servers.dial(ctx)
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@ func TestResolver(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Log(addrs)
|
t.Log(addrs)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDNS(t *testing.T) {
|
func TestDNS(t *testing.T) {
|
||||||
|
6
go.mod
6
go.mod
@ -3,6 +3,10 @@ module comandy
|
|||||||
go 1.22.1
|
go 1.22.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/FloatTech/ttl v0.0.0-20230307105452-d6f7b2b647d1
|
||||||
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e
|
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e
|
||||||
github.com/fumiama/terasu v0.0.0-20240414143030-44fae3a81905
|
github.com/fumiama/terasu v0.0.0-20240415131749-e65650a52c3c
|
||||||
|
golang.org/x/net v0.24.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require golang.org/x/text v0.14.0 // indirect
|
||||||
|
18
go.sum
18
go.sum
@ -1,4 +1,18 @@
|
|||||||
|
github.com/FloatTech/ttl v0.0.0-20230307105452-d6f7b2b647d1 h1:g4pTnDJUW4VbJ9NvoRfUvdjDrHz/6QhfN/LoIIpICbo=
|
||||||
|
github.com/FloatTech/ttl v0.0.0-20230307105452-d6f7b2b647d1/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
||||||
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e h1:wR3MXQ3VbUlPKOOUwLOYgh/QaJThBTYtsl673O3lqSA=
|
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e h1:wR3MXQ3VbUlPKOOUwLOYgh/QaJThBTYtsl673O3lqSA=
|
||||||
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w=
|
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w=
|
||||||
github.com/fumiama/terasu v0.0.0-20240414143030-44fae3a81905 h1:PHf84+ujLpFGJbfytrwZT6/D7KojmjFm5Itv6te6WUA=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/fumiama/terasu v0.0.0-20240414143030-44fae3a81905/go.mod h1:BFl0X1+rGJf8bLHl/kO+v05ryHrj/R4kyCrK89NvegA=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/fumiama/terasu v0.0.0-20240415131749-e65650a52c3c h1:RxkHkeanPDrZrEEcUcosgBULmL8UDkSasvwP+jpdIZQ=
|
||||||
|
github.com/fumiama/terasu v0.0.0-20240415131749-e65650a52c3c/go.mod h1:BFl0X1+rGJf8bLHl/kO+v05ryHrj/R4kyCrK89NvegA=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||||
|
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
141
http.go
141
http.go
@ -5,36 +5,81 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/FloatTech/ttl"
|
||||||
"github.com/fumiama/terasu"
|
"github.com/fumiama/terasu"
|
||||||
|
"golang.org/x/net/http2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var dialer = net.Dialer{
|
var dialer = net.Dialer{
|
||||||
Timeout: time.Minute,
|
Timeout: time.Minute,
|
||||||
}
|
}
|
||||||
|
|
||||||
var cli = http.Client{
|
var lookupTable = ttl.NewCache[string, []string](time.Hour)
|
||||||
Transport: &http.Transport{
|
|
||||||
DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
type comandyClient http.Client
|
||||||
conn, err := dialer.DialContext(ctx, "tcp", addr)
|
|
||||||
|
var cli = comandyClient(http.Client{
|
||||||
|
Transport: &http2.Transport{
|
||||||
|
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||||
|
if dialer.Timeout != 0 {
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
ctx, cancel = context.WithTimeout(ctx, dialer.Timeout)
|
||||||
|
defer cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !dialer.Deadline.IsZero() {
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
ctx, cancel = context.WithDeadline(ctx, dialer.Deadline)
|
||||||
|
defer cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
host, port, err := net.SplitHostPort(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
host, _, err := net.SplitHostPort(addr)
|
addrs := lookupTable.Get(host)
|
||||||
|
if len(addrs) == 0 {
|
||||||
|
addrs, err = resolver.LookupHost(ctx, host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return terasu.Use(tls.Client(conn, &tls.Config{
|
lookupTable.Set(host, addrs)
|
||||||
ServerName: host,
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
})), nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
if len(addr) == 0 {
|
||||||
|
return nil, errors.New("empty host addr")
|
||||||
|
}
|
||||||
|
var tlsConn *tls.Conn
|
||||||
|
for _, a := range addrs {
|
||||||
|
if strings.Contains(a, ":") {
|
||||||
|
a = "[" + a + "]:" + port
|
||||||
|
} else {
|
||||||
|
a += ":" + port
|
||||||
|
}
|
||||||
|
conn, err := dialer.DialContext(ctx, network, a)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tlsConn = terasu.Use(tls.Client(conn, cfg))
|
||||||
|
err = tlsConn.HandshakeContext(ctx)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_ = tlsConn.Close()
|
||||||
|
}
|
||||||
|
return tlsConn, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
type capsule struct {
|
type capsule struct {
|
||||||
C int `json:"code,omitempty"`
|
C int `json:"code,omitempty"`
|
||||||
@ -59,3 +104,77 @@ func (r *capsule) printstrerr(err string) string {
|
|||||||
_ = json.NewEncoder(&buf).Encode(r)
|
_ = json.NewEncoder(&buf).Encode(r)
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cli *comandyClient) request(para string) string {
|
||||||
|
r := capsule{}
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
_ = canUseIPv6.Get()
|
||||||
|
}()
|
||||||
|
err := json.Unmarshal(stringToBytes(para), &r)
|
||||||
|
if err != nil {
|
||||||
|
return r.printerr(err)
|
||||||
|
}
|
||||||
|
if r.U == "" || !strings.HasPrefix(r.U, "https://") {
|
||||||
|
return r.printstrerr("invalid url '" + r.U + "'")
|
||||||
|
}
|
||||||
|
if r.M != "GET" && r.M != "POST" && r.M != "DELETE" {
|
||||||
|
return r.printstrerr("invalid method '" + r.U + "'")
|
||||||
|
}
|
||||||
|
var body io.Reader
|
||||||
|
if len(r.D) > 0 {
|
||||||
|
body = strings.NewReader(r.D)
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(r.M, r.U, body)
|
||||||
|
if err != nil {
|
||||||
|
return r.printerr(err)
|
||||||
|
}
|
||||||
|
for k, vs := range r.H {
|
||||||
|
lk := strings.ToLower(k)
|
||||||
|
if strings.HasPrefix(lk, "x-") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch x := vs.(type) {
|
||||||
|
case string:
|
||||||
|
req.Header.Add(k, x)
|
||||||
|
case []string:
|
||||||
|
for _, v := range x {
|
||||||
|
req.Header.Add(k, v)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return r.printstrerr("unsupported H type " + reflect.ValueOf(x).Type().Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(r.U)
|
||||||
|
wg.Wait()
|
||||||
|
resp, err := (*http.Client)(cli).Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return r.printerr(err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
sb := strings.Builder{}
|
||||||
|
enc := base64.NewEncoder(base64.StdEncoding, &sb)
|
||||||
|
_, err = io.Copy(enc, resp.Body)
|
||||||
|
_ = enc.Close()
|
||||||
|
if err != nil {
|
||||||
|
return r.printerr(err)
|
||||||
|
}
|
||||||
|
r.C = resp.StatusCode
|
||||||
|
r.H = make(map[string]any, len(resp.Header)*2)
|
||||||
|
for k, vs := range resp.Header {
|
||||||
|
if len(vs) == 1 {
|
||||||
|
r.H[k] = vs[0]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r.H[k] = vs
|
||||||
|
}
|
||||||
|
r.D = sb.String()
|
||||||
|
outbuf := strings.Builder{}
|
||||||
|
err = json.NewEncoder(&outbuf).Encode(&r)
|
||||||
|
if err != nil {
|
||||||
|
return r.printerr(err)
|
||||||
|
}
|
||||||
|
return outbuf.String()
|
||||||
|
}
|
||||||
|
49
http_test.go
Normal file
49
http_test.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestClientGet(t *testing.T) {
|
||||||
|
_ = canUseIPv6.Get()
|
||||||
|
req, err := http.NewRequest("GET", "https://api.mangacopy.com/api/v3/h5/homeIndex?platform=3", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
resp, err := (*http.Client)(&cli).Do(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
t.Log("[T] response code", resp.StatusCode)
|
||||||
|
for k, vs := range resp.Header {
|
||||||
|
for _, v := range vs {
|
||||||
|
t.Log("[T] response header", k+":", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(bytesToString(data))
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRequest(t *testing.T) {
|
||||||
|
r := cli.request(`{"code":0,"headers":{"authorization":"Token ","host":"api.mangacopy.com","source":"copyApp","webp":"1","region":"1","version":"2.1.7","platform":"3","user-agent":"COPY/2.1.7"},"method":"GET","url":"https://api.mangacopy.com/api/v3/h5/homeIndex?platform\u003d3"}`)
|
||||||
|
t.Log(r)
|
||||||
|
c := capsule{}
|
||||||
|
err := json.Unmarshal(stringToBytes(r), &c)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if c.C != http.StatusOK {
|
||||||
|
t.Fatal("status code", c.C)
|
||||||
|
}
|
||||||
|
if len(c.D) == 0 {
|
||||||
|
t.Fatal("empty data")
|
||||||
|
}
|
||||||
|
}
|
69
main.go
69
main.go
@ -3,12 +3,7 @@ package main
|
|||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {}
|
func main() {}
|
||||||
@ -45,67 +40,5 @@ func add_dns(para *C.char, is_ipv6 C.int) *C.char {
|
|||||||
//
|
//
|
||||||
//export request
|
//export request
|
||||||
func request(para *C.char) *C.char {
|
func request(para *C.char) *C.char {
|
||||||
r := capsule{}
|
return C.CString(cli.request(C.GoString(para)))
|
||||||
err := json.Unmarshal(stringToBytes(C.GoString(para)), &r)
|
|
||||||
if err != nil {
|
|
||||||
return C.CString(r.printerr(err))
|
|
||||||
}
|
|
||||||
if r.U == "" || !strings.HasPrefix(r.U, "https://") {
|
|
||||||
return C.CString(r.printstrerr("invalid url '" + r.U + "'"))
|
|
||||||
}
|
|
||||||
if r.M != "GET" && r.M != "POST" && r.M != "DELETE" {
|
|
||||||
return C.CString(r.printstrerr("invalid method '" + r.U + "'"))
|
|
||||||
}
|
|
||||||
var body io.Reader
|
|
||||||
if len(r.D) > 0 {
|
|
||||||
body = strings.NewReader(r.D)
|
|
||||||
}
|
|
||||||
req, err := http.NewRequest(r.M, r.U, body)
|
|
||||||
if err != nil {
|
|
||||||
return C.CString(r.printerr(err))
|
|
||||||
}
|
|
||||||
for k, vs := range r.H {
|
|
||||||
lk := strings.ToLower(k)
|
|
||||||
if strings.HasPrefix(lk, "x-") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch x := vs.(type) {
|
|
||||||
case string:
|
|
||||||
req.Header.Add(k, x)
|
|
||||||
case []string:
|
|
||||||
for _, v := range x {
|
|
||||||
req.Header.Add(k, v)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return C.CString(r.printstrerr("unsupported H type " + reflect.ValueOf(x).Type().Name()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resp, err := cli.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return C.CString(r.printerr(err))
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
sb := strings.Builder{}
|
|
||||||
enc := base64.NewEncoder(base64.StdEncoding, &sb)
|
|
||||||
_, err = io.CopyN(enc, resp.Body, resp.ContentLength)
|
|
||||||
_ = enc.Close()
|
|
||||||
if err != nil {
|
|
||||||
return C.CString(r.printerr(err))
|
|
||||||
}
|
|
||||||
r.C = resp.StatusCode
|
|
||||||
r.H = make(map[string]any, len(resp.Header)*2)
|
|
||||||
for k, vs := range resp.Header {
|
|
||||||
if len(vs) == 1 {
|
|
||||||
r.H[k] = vs[0]
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
r.H[k] = vs
|
|
||||||
}
|
|
||||||
r.D = sb.String()
|
|
||||||
outbuf := strings.Builder{}
|
|
||||||
err = json.NewEncoder(&outbuf).Encode(&r)
|
|
||||||
if err != nil {
|
|
||||||
return C.CString(r.printerr(err))
|
|
||||||
}
|
|
||||||
return C.CString(outbuf.String())
|
|
||||||
}
|
}
|
||||||
|
2
utils.go
2
utils.go
@ -14,12 +14,10 @@ type slice struct {
|
|||||||
cap int
|
cap int
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// bytesToString 没有内存开销的转换
|
// bytesToString 没有内存开销的转换
|
||||||
func bytesToString(b []byte) string {
|
func bytesToString(b []byte) string {
|
||||||
return *(*string)(unsafe.Pointer(&b))
|
return *(*string)(unsafe.Pointer(&b))
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// stringToBytes 没有内存开销的转换
|
// stringToBytes 没有内存开销的转换
|
||||||
func stringToBytes(s string) (b []byte) {
|
func stringToBytes(s string) (b []byte) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user