feat: 新增fstp文件传输工具包
This commit is contained in:
2
go.mod
2
go.mod
@@ -49,6 +49,7 @@ require (
|
|||||||
github.com/creack/pty v1.1.9 // indirect
|
github.com/creack/pty v1.1.9 // indirect
|
||||||
github.com/go-admin-team/go-admin-core v1.3.12-0.20221121065133-27b7dbe27a8f // indirect
|
github.com/go-admin-team/go-admin-core v1.3.12-0.20221121065133-27b7dbe27a8f // indirect
|
||||||
github.com/go-gsm/charset v1.0.0 // indirect
|
github.com/go-gsm/charset v1.0.0 // indirect
|
||||||
|
github.com/kr/fs v0.1.0 // indirect
|
||||||
golang.org/x/sync v0.6.0 // indirect
|
golang.org/x/sync v0.6.0 // indirect
|
||||||
golang.org/x/time v0.1.0 // indirect
|
golang.org/x/time v0.1.0 // indirect
|
||||||
)
|
)
|
||||||
@@ -112,6 +113,7 @@ require (
|
|||||||
github.com/nyaruka/phonenumbers v1.0.55 // indirect
|
github.com/nyaruka/phonenumbers v1.0.55 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/pkg/sftp v1.13.6
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||||
github.com/reiver/go-oi v1.0.0 // indirect
|
github.com/reiver/go-oi v1.0.0 // indirect
|
||||||
github.com/richardlehane/mscfb v1.0.4 // indirect
|
github.com/richardlehane/mscfb v1.0.4 // indirect
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -435,6 +435,7 @@ github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZX
|
|||||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
@@ -585,6 +586,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||||
|
github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo=
|
||||||
|
github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
@@ -780,6 +783,7 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
|
|||||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||||
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
|
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
@@ -868,6 +872,7 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
|
|||||||
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||||
@@ -964,6 +969,7 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@@ -974,6 +980,7 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||||
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
|
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
|
||||||
@@ -986,6 +993,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package parse
|
package parse
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -10,6 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Number 解析数值型
|
// Number 解析数值型
|
||||||
@@ -165,3 +168,58 @@ func Color(colorStr string) *color.RGBA {
|
|||||||
A: 255, // 不透明
|
A: 255, // 不透明
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConvertConfigToMap 将配置内容转换为Map结构数据
|
||||||
|
//
|
||||||
|
// configType 类型支持:txt json yaml yml
|
||||||
|
func ConvertConfigToMap(configType, content string) (map[string]any, error) {
|
||||||
|
// 类型支持:viper.SupportedExts
|
||||||
|
// config := viper.New()
|
||||||
|
// config.SetConfigType(configType)
|
||||||
|
// err := config.ReadConfig(bytes.NewBuffer([]byte(content)))
|
||||||
|
// return config.AllSettings(), err
|
||||||
|
|
||||||
|
var configMap map[string]interface{}
|
||||||
|
var err error
|
||||||
|
if configType == "txt" {
|
||||||
|
configMap = map[string]interface{}{
|
||||||
|
"txt": content,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if configType == "yaml" || configType == "yml" {
|
||||||
|
err = yaml.Unmarshal([]byte(content), &configMap)
|
||||||
|
}
|
||||||
|
if configType == "json" {
|
||||||
|
err = json.Unmarshal([]byte(content), &configMap)
|
||||||
|
}
|
||||||
|
return configMap, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConvertConfigToFile 将数据写入到指定文件内
|
||||||
|
//
|
||||||
|
// configType 类型支持:txt json yaml yml
|
||||||
|
func ConvertConfigToFile(configType, filePath string, data any) error {
|
||||||
|
// viper.SupportedExts
|
||||||
|
// config := viper.New()
|
||||||
|
// config.SetConfigType(configType)
|
||||||
|
// for key, value := range mapData {
|
||||||
|
// config.Set(key, value)
|
||||||
|
// }
|
||||||
|
// return config.WriteConfigAs(filePath)
|
||||||
|
|
||||||
|
var dataByte []byte
|
||||||
|
var err error
|
||||||
|
if configType == "" || configType == "txt" {
|
||||||
|
dataByte = []byte(data.(string))
|
||||||
|
}
|
||||||
|
if configType == "yaml" || configType == "yml" {
|
||||||
|
dataByte, err = yaml.Marshal(data)
|
||||||
|
}
|
||||||
|
if configType == "json" {
|
||||||
|
dataByte, err = json.Marshal(data)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return os.WriteFile(filePath, dataByte, 0644)
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"be.ems/src/framework/logger"
|
"be.ems/src/framework/logger"
|
||||||
"be.ems/src/framework/utils/cmd"
|
"be.ems/src/framework/utils/cmd"
|
||||||
|
gosftp "github.com/pkg/sftp"
|
||||||
gossh "golang.org/x/crypto/ssh"
|
gossh "golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -239,12 +241,11 @@ func (s *SSHClientSession) Write(cmd string) (int, error) {
|
|||||||
return s.Stdin.Write([]byte(cmd))
|
return s.Stdin.Write([]byte(cmd))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read 读取结果 等待一会才有结果
|
// Read 读取结果
|
||||||
func (s *SSHClientSession) Read() []byte {
|
func (s *SSHClientSession) Read() []byte {
|
||||||
if s.Stdout == nil {
|
if s.Stdout == nil {
|
||||||
return []byte{}
|
return []byte{}
|
||||||
}
|
}
|
||||||
// time.Sleep(300 * time.Millisecond)
|
|
||||||
bs := s.Stdout.Bytes()
|
bs := s.Stdout.Bytes()
|
||||||
if len(bs) > 0 {
|
if len(bs) > 0 {
|
||||||
s.Stdout.Reset()
|
s.Stdout.Reset()
|
||||||
@@ -253,15 +254,6 @@ func (s *SSHClientSession) Read() []byte {
|
|||||||
return []byte{}
|
return []byte{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CombinedOutput 发送命令带结果返回
|
|
||||||
func (s *SSHClientSession) CombinedOutput(cmd string) (string, error) {
|
|
||||||
n, err := s.Write(cmd)
|
|
||||||
if n == 0 || err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return string(s.Read()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// singleWriter SSH客户端会话消息
|
// singleWriter SSH客户端会话消息
|
||||||
type singleWriter struct {
|
type singleWriter struct {
|
||||||
b bytes.Buffer
|
b bytes.Buffer
|
||||||
@@ -283,3 +275,204 @@ func (w *singleWriter) Reset() {
|
|||||||
defer w.mu.Unlock()
|
defer w.mu.Unlock()
|
||||||
w.b.Reset()
|
w.b.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewClientSFTP 创建SSH客户端SFTP对象
|
||||||
|
func (c *ConnSSH) NewClientSFTP() (*SSHClientSFTP, error) {
|
||||||
|
sftpClient, err := gosftp.NewClient(c.Client)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("NewClientSFTP failed to create sftp: => %s", err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &SSHClientSFTP{
|
||||||
|
Client: sftpClient,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSHClientSFTP SSH客户端SFTP对象
|
||||||
|
type SSHClientSFTP struct {
|
||||||
|
Client *gosftp.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close 关闭会话
|
||||||
|
func (s *SSHClientSFTP) Close() {
|
||||||
|
if s.Client != nil {
|
||||||
|
s.Client.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyDirRemoteToLocal 复制目录-远程到本地
|
||||||
|
func (s *SSHClientSFTP) CopyDirRemoteToLocal(remoteDir, localDir string) error {
|
||||||
|
// 列出远程目录中的文件和子目录
|
||||||
|
remoteFiles, err := s.Client.ReadDir(remoteDir)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyDirRemoteToLocal failed to reading remote directory %s: => %s", remoteDir, err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建本地目录
|
||||||
|
err = os.MkdirAll(localDir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyDirRemoteToLocal failed to creating local directory %s: => %s", localDir, err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历远程文件和子目录并复制到本地
|
||||||
|
for _, remoteFile := range remoteFiles {
|
||||||
|
remotePath := filepath.Join(remoteDir, remoteFile.Name())
|
||||||
|
localPath := filepath.Join(localDir, remoteFile.Name())
|
||||||
|
|
||||||
|
if remoteFile.IsDir() {
|
||||||
|
// 如果是子目录,则递归复制子目录
|
||||||
|
err = s.CopyDirRemoteToLocal(remotePath, localPath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyDirRemoteToLocal failed to copying remote directory %s: => %s", remotePath, err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果是文件,则复制文件内容
|
||||||
|
remoteFile, err := s.Client.Open(remotePath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyDirRemoteToLocal failed to opening remote file %s: => %s", remotePath, err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
defer remoteFile.Close()
|
||||||
|
|
||||||
|
localFile, err := os.Create(localPath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyDirRemoteToLocal failed to creating local file %s: => %s", localPath, err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
defer localFile.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(localFile, remoteFile)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyDirRemoteToLocal failed to copying file contents from %s to %s: => %s", remotePath, localPath, err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyDirRemoteToLocal 复制目录-本地到远程
|
||||||
|
func (s *SSHClientSFTP) CopyDirLocalToRemote(localDir, remoteDir string) error {
|
||||||
|
// 创建远程目录
|
||||||
|
err := s.Client.MkdirAll(remoteDir)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyDirLocalToRemote failed to creating remote directory %s: => %s", remoteDir, err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历本地目录中的文件和子目录并复制到远程
|
||||||
|
err = filepath.Walk(localDir, func(localPath string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成远程路径
|
||||||
|
remotePath := filepath.Join(remoteDir, localPath[len(localDir):])
|
||||||
|
|
||||||
|
if info.IsDir() {
|
||||||
|
// 如果是子目录,则创建远程目录
|
||||||
|
err := s.Client.MkdirAll(remotePath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyDirLocalToRemote failed to creating remote directory %s: => %s", remotePath, err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果是文件,则复制文件内容
|
||||||
|
localFile, err := os.Open(localPath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyDirLocalToRemote failed to opening local file %s: => %s", localPath, err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer localFile.Close()
|
||||||
|
|
||||||
|
remoteFile, err := s.Client.Create(remotePath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyDirLocalToRemote failed to creating remote file %s: => %s", remotePath, err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer remoteFile.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(remoteFile, localFile)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyDirLocalToRemote failed to copying file contents from %s to %s: => %s", localPath, remotePath, err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyDirLocalToRemote failed to walking local directory: => %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyDirRemoteToLocal 复制文件-远程到本地
|
||||||
|
func (s *SSHClientSFTP) CopyFileRemoteToLocal(remotePath, localPath string) error {
|
||||||
|
// 打开远程文件
|
||||||
|
remoteFile, err := s.Client.Open(remotePath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyFileRemoteToLocal failed to opening remote file: => %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer remoteFile.Close()
|
||||||
|
|
||||||
|
// 如果目标文件已经存在,先将目标文件重命名
|
||||||
|
if info, err := os.Stat(localPath); err == nil && !info.IsDir() {
|
||||||
|
ext := filepath.Ext(localPath)
|
||||||
|
name := localPath[0 : len(localPath)-len(ext)]
|
||||||
|
newName := fmt.Sprintf("%s-%s%s", name, time.Now().Format("20060102_150405"), ext)
|
||||||
|
err := os.Rename(localPath, newName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建本地文件
|
||||||
|
localFile, err := os.Create(localPath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyFileRemoteToLocal failed to creating local file: => %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer localFile.Close()
|
||||||
|
|
||||||
|
// 复制文件内容
|
||||||
|
_, err = io.Copy(localFile, remoteFile)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyFileRemoteToLocal failed to copying contents: => %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyDirRemoteToLocal 复制文件-本地到远程
|
||||||
|
func (s *SSHClientSFTP) CopyFileLocalToRemote(localPath, remotePath string) error {
|
||||||
|
// 打开本地文件
|
||||||
|
localFile, err := os.Open(localPath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyFileLocalToRemote failed to opening local file: => %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer localFile.Close()
|
||||||
|
|
||||||
|
// 创建远程文件
|
||||||
|
remoteFile, err := s.Client.Create(remotePath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyFileLocalToRemote failed to creating remote file: => %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer remoteFile.Close()
|
||||||
|
|
||||||
|
// 复制文件内容
|
||||||
|
_, err = io.Copy(remoteFile, localFile)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("CopyFileLocalToRemote failed to copying contents: => %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user