mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
add *Bytes functions for ghttp.Client; improve gcmd/gfile
This commit is contained in:
@ -4,8 +4,6 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// HTTP客户端请求.
|
||||
|
||||
package ghttp
|
||||
|
||||
func Get(url string) (*ClientResponse, error) {
|
||||
@ -44,27 +42,22 @@ func Trace(url string, data ...interface{}) (*ClientResponse, error) {
|
||||
return DoRequest("TRACE", url, data...)
|
||||
}
|
||||
|
||||
// 该方法支持二进制提交数据
|
||||
func DoRequest(method, url string, data ...interface{}) (*ClientResponse, error) {
|
||||
return NewClient().DoRequest(method, url, data...)
|
||||
}
|
||||
|
||||
// GET请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
|
||||
func GetContent(url string, data ...interface{}) string {
|
||||
return RequestContent("GET", url, data...)
|
||||
}
|
||||
|
||||
// PUT请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
|
||||
func PutContent(url string, data ...interface{}) string {
|
||||
return RequestContent("PUT", url, data...)
|
||||
}
|
||||
|
||||
// POST请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
|
||||
func PostContent(url string, data ...interface{}) string {
|
||||
return RequestContent("POST", url, data...)
|
||||
}
|
||||
|
||||
// DELETE请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
|
||||
func DeleteContent(url string, data ...interface{}) string {
|
||||
return RequestContent("DELETE", url, data...)
|
||||
}
|
||||
@ -89,7 +82,46 @@ func TraceContent(url string, data ...interface{}) string {
|
||||
return RequestContent("TRACE", url, data...)
|
||||
}
|
||||
|
||||
// 请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
|
||||
func RequestContent(method string, url string, data ...interface{}) string {
|
||||
return NewClient().DoRequestContent(method, url, data...)
|
||||
return NewClient().RequestContent(method, url, data...)
|
||||
}
|
||||
|
||||
func GetBytes(url string, data ...interface{}) []byte {
|
||||
return RequestBytes("GET", url, data...)
|
||||
}
|
||||
|
||||
func PutBytes(url string, data ...interface{}) []byte {
|
||||
return RequestBytes("PUT", url, data...)
|
||||
}
|
||||
|
||||
func PostBytes(url string, data ...interface{}) []byte {
|
||||
return RequestBytes("POST", url, data...)
|
||||
}
|
||||
|
||||
func DeleteBytes(url string, data ...interface{}) []byte {
|
||||
return RequestBytes("DELETE", url, data...)
|
||||
}
|
||||
|
||||
func HeadBytes(url string, data ...interface{}) []byte {
|
||||
return RequestBytes("HEAD", url, data...)
|
||||
}
|
||||
|
||||
func PatchBytes(url string, data ...interface{}) []byte {
|
||||
return RequestBytes("PATCH", url, data...)
|
||||
}
|
||||
|
||||
func ConnectBytes(url string, data ...interface{}) []byte {
|
||||
return RequestBytes("CONNECT", url, data...)
|
||||
}
|
||||
|
||||
func OptionsBytes(url string, data ...interface{}) []byte {
|
||||
return RequestBytes("OPTIONS", url, data...)
|
||||
}
|
||||
|
||||
func TraceBytes(url string, data ...interface{}) []byte {
|
||||
return RequestBytes("TRACE", url, data...)
|
||||
}
|
||||
|
||||
func RequestBytes(method string, url string, data ...interface{}) []byte {
|
||||
return NewClient().RequestBytes(method, url, data...)
|
||||
}
|
||||
|
||||
53
g/net/ghttp/ghttp_client_bytes.go
Normal file
53
g/net/ghttp/ghttp_client_bytes.go
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package ghttp
|
||||
|
||||
func (c *Client) GetBytes(url string, data ...interface{}) []byte {
|
||||
return c.RequestBytes("GET", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) PutBytes(url string, data ...interface{}) []byte {
|
||||
return c.RequestBytes("PUT", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) PostBytes(url string, data ...interface{}) []byte {
|
||||
return c.RequestBytes("POST", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) DeleteBytes(url string, data ...interface{}) []byte {
|
||||
return c.RequestBytes("DELETE", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) HeadBytes(url string, data ...interface{}) []byte {
|
||||
return c.RequestBytes("HEAD", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) PatchBytes(url string, data ...interface{}) []byte {
|
||||
return c.RequestBytes("PATCH", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) ConnectBytes(url string, data ...interface{}) []byte {
|
||||
return c.RequestBytes("CONNECT", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) OptionsBytes(url string, data ...interface{}) []byte {
|
||||
return c.RequestBytes("OPTIONS", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) TraceBytes(url string, data ...interface{}) []byte {
|
||||
return c.RequestBytes("TRACE", url, data...)
|
||||
}
|
||||
|
||||
// 请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
|
||||
func (c *Client) RequestBytes(method string, url string, data ...interface{}) []byte {
|
||||
response, err := c.DoRequest(method, url, data...)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer response.Close()
|
||||
return response.ReadAll()
|
||||
}
|
||||
47
g/net/ghttp/ghttp_client_content.go
Normal file
47
g/net/ghttp/ghttp_client_content.go
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package ghttp
|
||||
|
||||
func (c *Client) GetContent(url string, data ...interface{}) string {
|
||||
return string(c.RequestBytes("GET", url, data...))
|
||||
}
|
||||
|
||||
func (c *Client) PutContent(url string, data ...interface{}) string {
|
||||
return string(c.RequestBytes("PUT", url, data...))
|
||||
}
|
||||
|
||||
func (c *Client) PostContent(url string, data ...interface{}) string {
|
||||
return string(c.RequestBytes("POST", url, data...))
|
||||
}
|
||||
|
||||
func (c *Client) DeleteContent(url string, data ...interface{}) string {
|
||||
return string(c.RequestBytes("DELETE", url, data...))
|
||||
}
|
||||
|
||||
func (c *Client) HeadContent(url string, data ...interface{}) string {
|
||||
return string(c.RequestBytes("HEAD", url, data...))
|
||||
}
|
||||
|
||||
func (c *Client) PatchContent(url string, data ...interface{}) string {
|
||||
return string(c.RequestBytes("PATCH", url, data...))
|
||||
}
|
||||
|
||||
func (c *Client) ConnectContent(url string, data ...interface{}) string {
|
||||
return string(c.RequestBytes("CONNECT", url, data...))
|
||||
}
|
||||
|
||||
func (c *Client) OptionsContent(url string, data ...interface{}) string {
|
||||
return string(c.RequestBytes("OPTIONS", url, data...))
|
||||
}
|
||||
|
||||
func (c *Client) TraceContent(url string, data ...interface{}) string {
|
||||
return string(c.RequestBytes("TRACE", url, data...))
|
||||
}
|
||||
|
||||
func (c *Client) RequestContent(method string, url string, data ...interface{}) string {
|
||||
return string(c.RequestBytes(method, url, data...))
|
||||
}
|
||||
@ -223,56 +223,6 @@ func (c *Client) Trace(url string, data ...interface{}) (*ClientResponse, error)
|
||||
return c.DoRequest("TRACE", url, data...)
|
||||
}
|
||||
|
||||
// GET请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
|
||||
func (c *Client) GetContent(url string, data ...interface{}) string {
|
||||
return c.DoRequestContent("GET", url, data...)
|
||||
}
|
||||
|
||||
// PUT请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
|
||||
func (c *Client) PutContent(url string, data ...interface{}) string {
|
||||
return c.DoRequestContent("PUT", url, data...)
|
||||
}
|
||||
|
||||
// POST请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
|
||||
func (c *Client) PostContent(url string, data ...interface{}) string {
|
||||
return c.DoRequestContent("POST", url, data...)
|
||||
}
|
||||
|
||||
// DELETE请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
|
||||
func (c *Client) DeleteContent(url string, data ...interface{}) string {
|
||||
return c.DoRequestContent("DELETE", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) HeadContent(url string, data ...interface{}) string {
|
||||
return c.DoRequestContent("HEAD", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) PatchContent(url string, data ...interface{}) string {
|
||||
return c.DoRequestContent("PATCH", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) ConnectContent(url string, data ...interface{}) string {
|
||||
return c.DoRequestContent("CONNECT", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) OptionsContent(url string, data ...interface{}) string {
|
||||
return c.DoRequestContent("OPTIONS", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) TraceContent(url string, data ...interface{}) string {
|
||||
return c.DoRequestContent("TRACE", url, data...)
|
||||
}
|
||||
|
||||
// 请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
|
||||
func (c *Client) DoRequestContent(method string, url string, data ...interface{}) string {
|
||||
response, err := c.DoRequest(method, url, data...)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer response.Close()
|
||||
return string(response.ReadAll())
|
||||
}
|
||||
|
||||
// 请求并返回response对象
|
||||
func (c *Client) DoRequest(method, url string, data ...interface{}) (*ClientResponse, error) {
|
||||
if strings.EqualFold("POST", method) {
|
||||
|
||||
@ -79,3 +79,22 @@ func AutoRun() {
|
||||
glog.Fatal("no command found")
|
||||
}
|
||||
}
|
||||
|
||||
// BuildOptions builds the options as string.
|
||||
func BuildOptions(m map[string]string, prefix ...string) string {
|
||||
options := ""
|
||||
leadstr := "-"
|
||||
if len(prefix) > 0 {
|
||||
leadstr = prefix[0]
|
||||
}
|
||||
for k, v := range m {
|
||||
if len(options) > 0 {
|
||||
options += " "
|
||||
}
|
||||
options += leadstr + k
|
||||
if v != "" {
|
||||
options += "=" + v
|
||||
}
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
@ -14,6 +14,11 @@ func (c *gCmdOption) GetAll() map[string]string {
|
||||
return c.options
|
||||
}
|
||||
|
||||
// BuildOptions builds the options as string.
|
||||
func (c *gCmdOption) Build(prefix ...string) string {
|
||||
return BuildOptions(c.options, prefix...)
|
||||
}
|
||||
|
||||
// Get returns the option value string specified by <key>,
|
||||
// if value dose not exist, then returns <def>.
|
||||
func (c *gCmdOption) Get(key string, def ...string) string {
|
||||
@ -25,6 +30,11 @@ func (c *gCmdOption) Get(key string, def ...string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Set sets the option named <key> with value <value>.
|
||||
func (c *gCmdOption) Set(key string, value string) {
|
||||
c.options[key] = value
|
||||
}
|
||||
|
||||
// GetVar returns the option value as *gvar.Var object specified by <key>,
|
||||
// if value does not exist, then returns <def> as its default value.
|
||||
func (c *gCmdOption) GetVar(key string, def ...string) *gvar.Var {
|
||||
|
||||
@ -398,8 +398,17 @@ func RealPath(path string) string {
|
||||
|
||||
// SelfPath returns absolute file path of current running process(binary).
|
||||
func SelfPath() string {
|
||||
p, _ := filepath.Abs(os.Args[0])
|
||||
return p
|
||||
path, _ := exec.LookPath(os.Args[0])
|
||||
if path != "" {
|
||||
path, _ = filepath.Abs(path)
|
||||
if path != "" {
|
||||
return path
|
||||
}
|
||||
}
|
||||
if path == "" {
|
||||
path, _ = filepath.Abs(os.Args[0])
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// SelfName returns file name of current running process(binary).
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
package gfile
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@ -21,12 +20,18 @@ const (
|
||||
// GetContents returns the file content of <path> as string.
|
||||
// It returns en empty string if it fails reading.
|
||||
func GetContents(path string) string {
|
||||
return string(GetBinContents(path))
|
||||
return string(GetBytes(path))
|
||||
}
|
||||
|
||||
// GetBinContents returns the file content of <path> as []byte.
|
||||
// It returns nil if it fails reading.
|
||||
// GetBinContents is alias of GetBytes.
|
||||
// Deprecated.
|
||||
func GetBinContents(path string) []byte {
|
||||
return GetBytes(path)
|
||||
}
|
||||
|
||||
// GetBytes returns the file content of <path> as []byte.
|
||||
// It returns nil if it fails reading.
|
||||
func GetBytes(path string) []byte {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil
|
||||
@ -74,15 +79,27 @@ func PutContentsAppend(path string, content string) error {
|
||||
return putContents(path, []byte(content), os.O_WRONLY|os.O_CREATE|os.O_APPEND, gDEFAULT_PERM)
|
||||
}
|
||||
|
||||
// PutBinContents puts binary <content> to file of <path>.
|
||||
// It creates file of <path> recursively if it does not exist.
|
||||
// PutBinContents is alias of PutBytes.
|
||||
// Deprecated.
|
||||
func PutBinContents(path string, content []byte) error {
|
||||
return PutBytes(path, content)
|
||||
}
|
||||
|
||||
// PutBytes puts binary <content> to file of <path>.
|
||||
// It creates file of <path> recursively if it does not exist.
|
||||
func PutBytes(path string, content []byte) error {
|
||||
return putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, gDEFAULT_PERM)
|
||||
}
|
||||
|
||||
// PutBinContentsAppend appends binary <content> to file of <path>.
|
||||
// It creates file of <path> recursively if it does not exist.
|
||||
// PutBinContentsAppend is alias of PutBytesAppend.
|
||||
// Deprecated.
|
||||
func PutBinContentsAppend(path string, content []byte) error {
|
||||
return PutBytesAppend(path, content)
|
||||
}
|
||||
|
||||
// PutBytesAppend appends binary <content> to file of <path>.
|
||||
// It creates file of <path> recursively if it does not exist.
|
||||
func PutBytesAppend(path string, content []byte) error {
|
||||
return putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_APPEND, gDEFAULT_PERM)
|
||||
}
|
||||
|
||||
@ -115,34 +132,52 @@ func GetNextCharOffsetByPath(path string, char byte, start int64) int64 {
|
||||
return -1
|
||||
}
|
||||
|
||||
// GetBinContentsTilChar returns the contents of the file as []byte
|
||||
// GetBinContentsTilChar is alias of GetBytesTilChar.
|
||||
// Deprecated.
|
||||
func GetBinContentsTilChar(reader io.ReaderAt, char byte, start int64) ([]byte, int64) {
|
||||
return GetBytesTilChar(reader, char, start)
|
||||
}
|
||||
|
||||
// GetBytesTilChar returns the contents of the file as []byte
|
||||
// until the next specified byte <char> position.
|
||||
//
|
||||
// Note: Returned value contains the character of the last position.
|
||||
func GetBinContentsTilChar(reader io.ReaderAt, char byte, start int64) ([]byte, int64) {
|
||||
func GetBytesTilChar(reader io.ReaderAt, char byte, start int64) ([]byte, int64) {
|
||||
if offset := GetNextCharOffset(reader, char, start); offset != -1 {
|
||||
return GetBinContentsByTwoOffsets(reader, start, offset+1), offset
|
||||
return GetBytesByTwoOffsets(reader, start, offset+1), offset
|
||||
}
|
||||
return nil, -1
|
||||
}
|
||||
|
||||
// GetBinContentsTilCharByPath returns the contents of the file given by <path> as []byte
|
||||
// GetBinContentsTilCharByPath is alias of GetBytesTilCharByPath.
|
||||
// Deprecated.
|
||||
func GetBinContentsTilCharByPath(path string, char byte, start int64) ([]byte, int64) {
|
||||
return GetBytesTilCharByPath(path, char, start)
|
||||
}
|
||||
|
||||
// GetBytesTilCharByPath returns the contents of the file given by <path> as []byte
|
||||
// until the next specified byte <char> position.
|
||||
// It opens file of <path> for reading with os.O_RDONLY flag and default perm.
|
||||
//
|
||||
// Note: Returned value contains the character of the last position.
|
||||
func GetBinContentsTilCharByPath(path string, char byte, start int64) ([]byte, int64) {
|
||||
func GetBytesTilCharByPath(path string, char byte, start int64) ([]byte, int64) {
|
||||
if f, err := OpenWithFlagPerm(path, os.O_RDONLY, gDEFAULT_PERM); err == nil {
|
||||
defer f.Close()
|
||||
return GetBinContentsTilChar(f, char, start)
|
||||
return GetBytesTilChar(f, char, start)
|
||||
}
|
||||
return nil, -1
|
||||
}
|
||||
|
||||
// GetBinContentsByTwoOffsets returns the binary content as []byte from <start> to <end>.
|
||||
// GetBinContentsByTwoOffsets is alias of GetBytesByTwoOffsets.
|
||||
// Deprecated.
|
||||
func GetBinContentsByTwoOffsets(reader io.ReaderAt, start int64, end int64) []byte {
|
||||
return GetBytesByTwoOffsets(reader, start, end)
|
||||
}
|
||||
|
||||
// GetBytesByTwoOffsets returns the binary content as []byte from <start> to <end>.
|
||||
// Note: Returned value does not contain the character of the last position, which means
|
||||
// it returns content range as [start, end).
|
||||
func GetBinContentsByTwoOffsets(reader io.ReaderAt, start int64, end int64) []byte {
|
||||
func GetBytesByTwoOffsets(reader io.ReaderAt, start int64, end int64) []byte {
|
||||
buffer := make([]byte, end-start)
|
||||
if _, err := reader.ReadAt(buffer, start); err != nil {
|
||||
return nil
|
||||
@ -150,30 +185,20 @@ func GetBinContentsByTwoOffsets(reader io.ReaderAt, start int64, end int64) []by
|
||||
return buffer
|
||||
}
|
||||
|
||||
// GetBinContentsByTwoOffsetsByPath returns the binary content as []byte from <start> to <end>.
|
||||
// GetBinContentsByTwoOffsetsByPath is alias of GetBytesByTwoOffsetsByPath.
|
||||
// Deprecated.
|
||||
func GetBinContentsByTwoOffsetsByPath(path string, start int64, end int64) []byte {
|
||||
return GetBytesByTwoOffsetsByPath(path, start, end)
|
||||
}
|
||||
|
||||
// GetBytesByTwoOffsetsByPath returns the binary content as []byte from <start> to <end>.
|
||||
// Note: Returned value does not contain the character of the last position, which means
|
||||
// it returns content range as [start, end).
|
||||
// It opens file of <path> for reading with os.O_RDONLY flag and default perm.
|
||||
func GetBinContentsByTwoOffsetsByPath(path string, start int64, end int64) []byte {
|
||||
func GetBytesByTwoOffsetsByPath(path string, start int64, end int64) []byte {
|
||||
if f, err := OpenWithFlagPerm(path, os.O_RDONLY, gDEFAULT_PERM); err == nil {
|
||||
defer f.Close()
|
||||
return GetBinContentsByTwoOffsets(f, start, end)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Replace replaces content for files under <path>.
|
||||
// The parameter <pattern> specifies the file pattern which matches to be replaced.
|
||||
// It does replacement recursively if given parameter <recursive> is true.
|
||||
func Replace(search, replace, path, pattern string, recursive ...bool) error {
|
||||
files, err := ScanDir(path, pattern, recursive...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, file := range files {
|
||||
if err = PutContents(file, gstr.Replace(GetContents(file), search, replace)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
49
g/os/gfile/gfile_replace.go
Normal file
49
g/os/gfile/gfile_replace.go
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright 2017-2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gfile
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
)
|
||||
|
||||
// Replace replaces content for files under <path>.
|
||||
// The parameter <pattern> specifies the file pattern which matches to be replaced.
|
||||
// It does replacement recursively if given parameter <recursive> is true.
|
||||
func Replace(search, replace, path, pattern string, recursive ...bool) error {
|
||||
files, err := ScanDir(path, pattern, recursive...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, file := range files {
|
||||
if err = PutContents(file, gstr.Replace(GetContents(file), search, replace)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// ReplaceFunc replaces content for files under <path> with callback function <f>.
|
||||
// The parameter <pattern> specifies the file pattern which matches to be replaced.
|
||||
// It does replacement recursively if given parameter <recursive> is true.
|
||||
func ReplaceFunc(f func(content string) string, path, pattern string, recursive ...bool) error {
|
||||
files, err := ScanDir(path, pattern, recursive...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data := ""
|
||||
result := ""
|
||||
for _, file := range files {
|
||||
data = GetContents(file)
|
||||
result = f(data)
|
||||
if data != result {
|
||||
if err = PutContents(file, result); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user