1.4.5.2
This commit is contained in:
348
EdgeNode/internal/js/lib_net_http_client.go
Normal file
348
EdgeNode/internal/js/lib_net_http_client.go
Normal file
@@ -0,0 +1,348 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build script
|
||||
|
||||
package js
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var sharedHTTPClientPool = utils.NewHTTPClient(30 * time.Second)
|
||||
|
||||
func init() {
|
||||
if !teaconst.IsMain {
|
||||
return
|
||||
}
|
||||
|
||||
SharedLibraryManager.Register(&JSNetHTTPClientLibrary{})
|
||||
}
|
||||
|
||||
type JSNetHTTPClientLibrary struct {
|
||||
JSBaseLibrary
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibrary) JSNamespace() string {
|
||||
return "gojs.net.http.client.JSNetHTTPClientLibrary"
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibrary) JSPrototype() string {
|
||||
return `
|
||||
gojs.net.http.client.Request = class {
|
||||
#url
|
||||
#headers = {}
|
||||
#method
|
||||
#body
|
||||
|
||||
constructor(url) {
|
||||
this.#url = url
|
||||
}
|
||||
|
||||
get url() {
|
||||
return this.#url
|
||||
}
|
||||
|
||||
addHeader(name, value) {
|
||||
if (typeof(name) == "string" && typeof(value) == "string") {
|
||||
if (typeof(this.#headers[name]) == "undefined") {
|
||||
this.#headers[name] = [value]
|
||||
} else {
|
||||
this.#headers[name].push(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get headers() {
|
||||
return this.#headers
|
||||
}
|
||||
|
||||
setContentType(contentType) {
|
||||
this.#headers["Content-Type"] = [contentType]
|
||||
}
|
||||
|
||||
setUserAgent(userAgent) {
|
||||
this.#headers["User-Agent"] = [userAgent]
|
||||
}
|
||||
|
||||
setMethod(method) {
|
||||
this.#method = method
|
||||
}
|
||||
|
||||
get method() {
|
||||
return this.#method
|
||||
}
|
||||
|
||||
setBody(body) {
|
||||
this.#body = body
|
||||
}
|
||||
|
||||
get body() {
|
||||
return this.#body
|
||||
}
|
||||
|
||||
get() {
|
||||
this.setMethod("GET")
|
||||
return gojs.net.http.client.DefaultClient.do(this)
|
||||
}
|
||||
|
||||
post() {
|
||||
this.setMethod("POST")
|
||||
return gojs.net.http.client.DefaultClient.do(this)
|
||||
}
|
||||
}
|
||||
|
||||
gojs.net.http.client.Response = class {
|
||||
#goObjectId
|
||||
|
||||
constructor(goObjectId) {
|
||||
this.#goObjectId = goObjectId
|
||||
}
|
||||
|
||||
get goObjectId() {
|
||||
return this.#goObjectId
|
||||
}
|
||||
|
||||
get error() {
|
||||
return $this.ResponseError(this.#goObjectId)
|
||||
}
|
||||
|
||||
get contentLength() {
|
||||
return $this.ResponseContentLength(this.#goObjectId)
|
||||
}
|
||||
|
||||
get status() {
|
||||
return $this.ResponseStatus(this.#goObjectId)
|
||||
}
|
||||
|
||||
get headers() {
|
||||
return $this.ResponseHeaders(this.#goObjectId)
|
||||
}
|
||||
|
||||
get body() {
|
||||
return $this.ResponseBodyString(this.#goObjectId)
|
||||
}
|
||||
|
||||
get bodyObject() {
|
||||
return JSON.parse(this.body)
|
||||
}
|
||||
}
|
||||
|
||||
gojs.net.http.client.Client = class {
|
||||
do(req) {
|
||||
let respObjectId = $this.Do({
|
||||
"url": req.url,
|
||||
"method": req.method,
|
||||
"headers": req.headers,
|
||||
"headerKeys": Object.keys(req.headers),
|
||||
"body": req.body,
|
||||
})
|
||||
return new gojs.net.http.client.Response(respObjectId)
|
||||
}
|
||||
}
|
||||
|
||||
gojs.net.http.client.DefaultClient = new gojs.net.http.client.Client()
|
||||
`
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibrary) JSDone(ctx *Context) {
|
||||
// TODO 因为每个请求会执行,所以这里需要性能,可能需要有调用的时候才执行
|
||||
var objMap = ctx.GoObjectMap()
|
||||
for _, obj := range objMap {
|
||||
if obj != nil {
|
||||
resp, ok := obj.(*JSNetHTTPClientLibraryResponse)
|
||||
if ok {
|
||||
resp.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibrary) Do(arguments *FunctionArguments) (uint32, error) {
|
||||
obj, ok := arguments.ObjectAt(0)
|
||||
if !ok {
|
||||
return 0, ErrGoObjectNotFound
|
||||
}
|
||||
|
||||
if obj.IsNullOrUndefined() {
|
||||
return 0, ErrGoObjectNotFound
|
||||
}
|
||||
|
||||
urlString, _ := obj.GetString("url")
|
||||
_, err := url.Parse(urlString)
|
||||
if err != nil {
|
||||
return 0, errors.New("invalid url: '" + urlString + "'")
|
||||
}
|
||||
|
||||
method, _ := obj.GetString("method")
|
||||
if len(method) == 0 {
|
||||
method = http.MethodGet
|
||||
}
|
||||
method = strings.ToUpper(method)
|
||||
|
||||
var headers = http.Header{}
|
||||
headerObj, ok := obj.GetObject("headers")
|
||||
if ok && !headerObj.IsNullOrUndefined() {
|
||||
headerKeysArray, _ := obj.GetStringsArray("headerKeys")
|
||||
for _, headerKey := range headerKeysArray {
|
||||
headerValues, _ := headerObj.GetStringsArray(headerKey)
|
||||
if len(headerValues) > 0 {
|
||||
headers[headerKey] = headerValues
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var bodyReader io.Reader
|
||||
bodyString, _ := obj.GetString("body")
|
||||
if len(bodyString) > 0 {
|
||||
bodyReader = bytes.NewReader([]byte(bodyString))
|
||||
}
|
||||
req, err := http.NewRequest(method, urlString, bodyReader)
|
||||
if err != nil {
|
||||
var goObjectId = arguments.Context().AddGoObject(NewJSNetHTTPClientLibraryResponse(nil, err))
|
||||
return goObjectId, nil
|
||||
}
|
||||
|
||||
var hasContentType = false
|
||||
var hasUserAgent = false
|
||||
req.Header = headers
|
||||
for k := range headers {
|
||||
if strings.ToLower(k) == "content-type" {
|
||||
hasContentType = true
|
||||
}
|
||||
if strings.ToLower(k) == "user-agent" {
|
||||
hasUserAgent = true
|
||||
}
|
||||
}
|
||||
if !hasContentType && method == http.MethodPost {
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
}
|
||||
if !hasUserAgent {
|
||||
req.Header.Set("User-Agent", teaconst.GlobalProductName+"-Node-Script/"+teaconst.Version)
|
||||
}
|
||||
|
||||
resp, err := sharedHTTPClientPool.Do(req)
|
||||
if err != nil {
|
||||
var goObjectId = arguments.Context().AddGoObject(NewJSNetHTTPClientLibraryResponse(nil, err))
|
||||
return goObjectId, nil
|
||||
}
|
||||
|
||||
var goObjectId = arguments.Context().AddGoObject(NewJSNetHTTPClientLibraryResponse(resp, err))
|
||||
return goObjectId, nil
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibrary) ResponseError(arguments *FunctionArguments) (any, error) {
|
||||
obj, ok := arguments.GoObjectAt(0)
|
||||
if !ok {
|
||||
return "", ErrGoObjectNotFound
|
||||
}
|
||||
var err = obj.(*JSNetHTTPClientLibraryResponse).Error()
|
||||
if err != nil {
|
||||
return maps.Map{"message": err.Error()}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibrary) ResponseStatus(arguments *FunctionArguments) (int, error) {
|
||||
obj, ok := arguments.GoObjectAt(0)
|
||||
if !ok {
|
||||
return 0, ErrGoObjectNotFound
|
||||
}
|
||||
return obj.(*JSNetHTTPClientLibraryResponse).Status(), nil
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibrary) ResponseContentLength(arguments *FunctionArguments) (int64, error) {
|
||||
obj, ok := arguments.GoObjectAt(0)
|
||||
if !ok {
|
||||
return 0, ErrGoObjectNotFound
|
||||
}
|
||||
return obj.(*JSNetHTTPClientLibraryResponse).ContentLength(), nil
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibrary) ResponseHeaders(arguments *FunctionArguments) (http.Header, error) {
|
||||
obj, ok := arguments.GoObjectAt(0)
|
||||
if !ok {
|
||||
return nil, ErrGoObjectNotFound
|
||||
}
|
||||
return obj.(*JSNetHTTPClientLibraryResponse).Headers(), nil
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibrary) ResponseBodyString(arguments *FunctionArguments) (string, error) {
|
||||
obj, ok := arguments.GoObjectAt(0)
|
||||
if !ok {
|
||||
return "", ErrGoObjectNotFound
|
||||
}
|
||||
s, _ := obj.(*JSNetHTTPClientLibraryResponse).BodyString()
|
||||
return s, nil
|
||||
}
|
||||
|
||||
type JSNetHTTPClientLibraryResponse struct {
|
||||
resp *http.Response
|
||||
err error
|
||||
|
||||
body []byte
|
||||
bodyRead bool
|
||||
}
|
||||
|
||||
func NewJSNetHTTPClientLibraryResponse(resp *http.Response, err error) *JSNetHTTPClientLibraryResponse {
|
||||
return &JSNetHTTPClientLibraryResponse{resp: resp, err: err}
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibraryResponse) Close() {
|
||||
if this.resp != nil && this.resp.Body != nil {
|
||||
_ = this.resp.Body.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibraryResponse) Error() error {
|
||||
return this.err
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibraryResponse) Status() int {
|
||||
if this.resp != nil {
|
||||
return this.resp.StatusCode
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibraryResponse) ContentLength() int64 {
|
||||
if this.resp != nil {
|
||||
return this.resp.ContentLength
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibraryResponse) Headers() http.Header {
|
||||
if this.resp != nil {
|
||||
return this.resp.Header
|
||||
}
|
||||
return http.Header{}
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibraryResponse) BodyString() (string, error) {
|
||||
if this.resp != nil {
|
||||
data, err := this.readBody()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (this *JSNetHTTPClientLibraryResponse) readBody() ([]byte, error) {
|
||||
if this.bodyRead {
|
||||
return this.body, nil
|
||||
}
|
||||
data, err := io.ReadAll(this.resp.Body)
|
||||
this.body = data
|
||||
this.bodyRead = true
|
||||
return data, err
|
||||
}
|
||||
Reference in New Issue
Block a user