Browse Source

fix:新增保存连接到本地文件

GTong 7 months ago
parent
commit
5324e4cef6

+ 22 - 0
api/api.go

@@ -0,0 +1,22 @@
+package api
+
+// 定义结构体
+type ConnectInfoRequest struct {
+	Id  string  `json:"id" toml:"id"`
+	Ssh SshInfo `json:"ssh_info" toml:"server"`
+	Db  DbInfo  `json:"db_info" toml:"db"`
+}
+
+type SshInfo struct {
+	Username string `json:"username" toml:"ssh_username"`
+	Password string `json:"password" toml:"ssh_password"`
+	Host     string `json:"host" toml:"ssh_ip"`
+	Port     string `json:"port" toml:"ssh_port"`
+}
+
+type DbInfo struct {
+	User     string `json:"user" toml:"db_user"`
+	Password string `json:"password" toml:"db_password"`
+	Database string `json:"database" toml:"db_database"`
+	Port     string `json:"port" toml:"db_port"`
+}

+ 11 - 0
config/127.0.0.1 copy/listen.toml

@@ -0,0 +1,11 @@
+[db]
+db_database = 'test'
+db_password = 'SYSDBA'
+db_port = '5236'
+db_user = 'SYSDBA'
+
+[server]
+ssh_ip = '122.0.0.9'
+ssh_password = '845895'
+ssh_port = '22'
+ssh_username = 'gtong'

File diff suppressed because it is too large
+ 1 - 0
config/127.0.0.1 copy/os_info_20241009_172149.toml


+ 11 - 0
config/127.0.0.1/listen.toml

@@ -0,0 +1,11 @@
+[db]
+db_database = 'test'
+db_password = 'SYSDBA'
+db_port = '5236'
+db_user = 'SYSDBA'
+
+[server]
+ssh_ip = '127.0.0.1'
+ssh_password = '845895'
+ssh_port = '22'
+ssh_username = 'gtong'

+ 11 - 0
config/test/listen.toml

@@ -0,0 +1,11 @@
+[db]
+db_database = 'test'
+db_password = 'SYSDBA'
+db_port = '5236'
+db_user = 'SYSDBA'
+
+[server]
+ssh_ip = '122.01.0.9'
+ssh_password = '845895'
+ssh_port = '22'
+ssh_username = 'gtong'

File diff suppressed because it is too large
+ 1 - 0
config/test/os_info_20241009_172149.toml


+ 8 - 0
dba.toml

@@ -0,0 +1,8 @@
+[config]
+ip = "127.0.0.1"
+port = "8080"
+
+
+
+[logs]
+app_log = "./logs"

+ 49 - 2
go.mod

@@ -2,6 +2,53 @@ module xg_dba
 
 go 1.22.2
 
-require golang.org/x/crypto v0.27.0
+require (
+	github.com/BurntSushi/toml v1.4.0
+	github.com/gin-gonic/gin v1.10.0
+	github.com/sirupsen/logrus v1.9.3
+	github.com/spf13/viper v1.19.0
+	golang.org/x/crypto v0.27.0
+)
 
-require golang.org/x/sys v0.25.0 // indirect
+require (
+	github.com/bytedance/sonic v1.11.6 // indirect
+	github.com/bytedance/sonic/loader v0.1.1 // indirect
+	github.com/cloudwego/base64x v0.1.4 // indirect
+	github.com/cloudwego/iasm v0.2.0 // indirect
+	github.com/fsnotify/fsnotify v1.7.0 // indirect
+	github.com/gabriel-vasile/mimetype v1.4.3 // indirect
+	github.com/gin-contrib/sse v0.1.0 // indirect
+	github.com/go-playground/locales v0.14.1 // indirect
+	github.com/go-playground/universal-translator v0.18.1 // indirect
+	github.com/go-playground/validator/v10 v10.20.0 // indirect
+	github.com/goccy/go-json v0.10.2 // indirect
+	github.com/hashicorp/hcl v1.0.0 // indirect
+	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.7 // indirect
+	github.com/leodido/go-urn v1.4.0 // indirect
+	github.com/magiconair/properties v1.8.7 // indirect
+	github.com/mattn/go-isatty v0.0.20 // indirect
+	github.com/mitchellh/mapstructure v1.5.0 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
+	github.com/sagikazarmark/locafero v0.4.0 // indirect
+	github.com/sagikazarmark/slog-shim v0.1.0 // indirect
+	github.com/sourcegraph/conc v0.3.0 // indirect
+	github.com/spf13/afero v1.11.0 // indirect
+	github.com/spf13/cast v1.6.0 // indirect
+	github.com/spf13/pflag v1.0.5 // indirect
+	github.com/subosito/gotenv v1.6.0 // indirect
+	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
+	github.com/ugorji/go/codec v1.2.12 // indirect
+	go.uber.org/atomic v1.9.0 // indirect
+	go.uber.org/multierr v1.9.0 // indirect
+	golang.org/x/arch v0.8.0 // indirect
+	golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
+	golang.org/x/net v0.25.0 // indirect
+	golang.org/x/sys v0.25.0 // indirect
+	golang.org/x/text v0.18.0 // indirect
+	google.golang.org/protobuf v1.34.1 // indirect
+	gopkg.in/ini.v1 v1.67.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+)

+ 131 - 0
go.sum

@@ -1,6 +1,137 @@
+github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
+github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
+github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
+github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
+github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
+github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
+github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
+github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
+github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
+github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
+github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
+github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
+github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
+github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
+github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
+github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
+github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
+github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
+github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
+github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
+github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
+github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
+github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
+github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
+github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
+github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
+github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
+github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
+github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
+github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
+github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
+github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
+github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
+github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
+github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
+github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
+github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
+github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
+github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
+github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
+github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
+go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
+go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
+golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
 golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
 golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
+golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
+golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
 golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
 golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
+golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
+golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
+google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

+ 25 - 0
internal/controllers/connect/connect.go

@@ -0,0 +1,25 @@
+package connect
+
+import (
+	"net/http"
+	"xg_dba/api"
+	services "xg_dba/internal/services/connect"
+
+	"github.com/gin-gonic/gin"
+)
+
+// 获取连接信息
+func SaveConnectInfo_controller(c *gin.Context) {
+	connectInfo := api.ConnectInfoRequest{}
+	if err := c.BindJSON(&connectInfo); err != nil {
+		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+		return
+	}
+	//存储到本地
+	localPath := "./config/" + connectInfo.Ssh.Host + "/" + connectInfo.Ssh.Host + ".toml"
+	if err := services.SetConnectInfo_service(connectInfo, localPath); err != nil {
+		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+		return
+	}
+	c.JSON(http.StatusOK, connectInfo)
+}

+ 11 - 0
internal/controllers/system/system_info.go

@@ -0,0 +1,11 @@
+package system
+
+import (
+	"github.com/gin-gonic/gin"
+)
+
+// 设置系统信息
+func SetSystemInfo_controller(c *gin.Context) {
+	//获取连接信息
+
+}

+ 63 - 0
internal/global/config.go

@@ -0,0 +1,63 @@
+package global
+
+import (
+	"fmt"
+	"log"
+	"os"
+
+	"github.com/BurntSushi/toml"
+)
+
+type Config struct {
+	App  AppConfig `toml:"config"`
+	Logs LogConfig `toml:"logs"`
+}
+
+type AppConfig struct {
+	Ip   string `toml:"ip"`
+	Port string `toml:"port"`
+}
+
+type LogConfig struct {
+	AppLog string `toml:"app_log"`
+}
+
+func fileExists(filePath string) bool {
+	_, err := os.Stat(filePath)
+	if os.IsNotExist(err) {
+		return false
+	}
+	return err == nil
+}
+
+func createFileWithContent(filePath, content string) error {
+	return os.WriteFile(filePath, []byte(content), 0644)
+}
+
+// LoadConfig 从给定的 TOML 文件路径加载配置
+func LoadConfig(filePath string) *Config {
+	var config Config
+
+	if !fileExists(filePath) {
+		content := `[config]
+ip = "127.0.0.1"
+port = "8080"
+
+[logs]
+app_log = "./logs"
+`
+		err := createFileWithContent(filePath, content)
+		if err != nil {
+			fmt.Printf("创建文件失败: %v\n", err)
+		} else {
+			fmt.Printf("文件 %s 已成功创建\n", filePath)
+		}
+	}
+
+	// 读取并解析 TOML 文件
+	if _, err := toml.DecodeFile(filePath, &config); err != nil {
+		log.Fatalf("无法解析配置文件: %s", err)
+	}
+
+	return &config
+}

+ 10 - 0
internal/global/init.go

@@ -0,0 +1,10 @@
+package global
+
+import "fmt"
+
+func GlobalInit() {
+	fmt.Println("Init function from package global")
+	cfg := LoadConfig("./dba.toml")
+	fmt.Println("cfg :", cfg)
+	InitLogs(cfg.Logs.AppLog, "info")
+}

+ 123 - 0
internal/global/logs.go

@@ -0,0 +1,123 @@
+package global
+
+import (
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"time"
+
+	"github.com/sirupsen/logrus"
+)
+
+var Logger *logrus.Logger
+
+// Hook 结构体定义了一个日志钩子,用于将日志条目输出到指定的 Writer,并使用指定的 Formatter 格式化日志条目。
+// Level 字段是一个包含日志级别的切片,用于指定该钩子应处理的日志级别。
+type Hook struct {
+	Writer    io.Writer
+	Formatter logrus.Formatter
+	Level     []logrus.Level
+}
+
+// Fire 方法是 logrus.Hook 接口的实现。当日志条目符合钩子的日志级别时,
+// 这个方法会被调用。它首先使用 Formatter 将日志条目格式化为字节切片,
+// 然后将其写入 Writer。此版本增强了日志条目,添加了错误发生的文件名和行号。
+func (h *Hook) Fire(entry *logrus.Entry) error {
+	// 获取错误发生的文件名和行号
+	if entry.HasCaller() {
+		entry.Data["file"] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
+	}
+
+	line, err := h.Formatter.Format(entry)
+	if err != nil {
+		return err
+	}
+	h.Writer.Write(line)
+	return nil
+}
+
+// Levels 方法返回该钩子支持的日志级别切片。
+// logrus 在写入日志时会调用这个方法来决定是否使用这个钩子。
+func (h *Hook) Levels() []logrus.Level {
+	return h.Level
+}
+
+// newHook 函数用于创建一个新的 Hook 实例。它接收一个 Writer,
+// 一个 Formatter 和一个最低的日志级别 level 作为参数。
+// 函数会为低于或等于指定级别的所有日志级别创建一个 Hook,
+// 并返回该 Hook 实例。
+func newHook(writer io.Writer, formatter logrus.Formatter, level logrus.Level) *Hook {
+	var levels []logrus.Level
+	for _, l := range logrus.AllLevels {
+		if l <= level {
+			levels = append(levels, l)
+		}
+	}
+	return &Hook{
+		Writer:    writer,
+		Formatter: formatter,
+		Level:     levels,
+	}
+}
+
+// InitLogs 函数负责初始化 logrus.Logger 对象。它首先检查是否存在指定的日志目录(默认为 ./logs/)。
+// 如果目录不存在,它会创建该目录。
+func InitLogs(logFilePath string, logLevelStr string) *logrus.Logger {
+	//dir := "./logs/"
+	// 检查目录是否存在
+	if _, err := os.Stat(logFilePath); os.IsNotExist(err) {
+		// 目录不存在,创建目录
+		err := os.MkdirAll(logFilePath, os.ModePerm)
+		if err != nil {
+			fmt.Println("Error creating directory:", err)
+			return nil
+		}
+		fmt.Println("Directory created:", logFilePath)
+	}
+
+	// 尝试将 logLevelStr 转换为 logrus.Level。如果转换失败,则默认使用 InfoLevel 级别。
+	logLevel, err := logrus.ParseLevel(logLevelStr)
+	if err != nil {
+		logLevel = logrus.InfoLevel
+		log.Printf("Invalid log level: %s. Defaulting to info", logLevelStr)
+	}
+
+	// 初始化 Logger 实例,并将其输出设置为 io.Discard,即默认情况下不输出任何日志。
+	// 这是为了强制所有日志输出都通过钩子来处理。
+	Logger = logrus.New()
+	Logger.SetOutput(io.Discard)
+
+	// 启用记录调用者信息,这样可以记录错误发生的位置(文件名和行号)。
+	Logger.SetReportCaller(true)
+
+	// 使用当前日期生成日志文件名,格式为 `log-YYYY-MM-DD.log`
+	currentDate := time.Now().Format("2006-01-02")
+	logFileName := fmt.Sprintf("%s/log-%s.log", logFilePath, currentDate)
+
+	// 打开或创建日志文件。日志文件的路径由 logFilePath 参数指定。
+	logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
+	if err != nil {
+		log.Printf("Failed to open log file: %s", logFileName)
+		panic(err)
+	}
+
+	// 添加一个新的 Hook,将日志输出到日志文件中,并使用 JSONFormatter 进行格式化。
+	Logger.AddHook(newHook(
+		logFile,
+		&logrus.JSONFormatter{},
+		logLevel,
+	))
+
+	// 添加另一个 Hook,将日志输出到标准错误输出(通常是控制台),
+	// 并使用 TextFormatter 格式化日志,显示完整时间戳并强制使用颜色。
+	Logger.AddHook(newHook(
+		os.Stderr,
+		&logrus.TextFormatter{
+			FullTimestamp: true,
+			ForceColors:   true,
+		},
+		logLevel,
+	))
+	return Logger
+}

+ 116 - 0
internal/middleware/cache.go

@@ -0,0 +1,116 @@
+package middleware
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"regexp"
+	"sort"
+	"xg_dba/internal/models"
+
+	"github.com/BurntSushi/toml"
+)
+
+func Cache() {
+
+	// 指定需要查找的根文件夹路径
+	folderPath := "C:\\Program_GT\\Code\\Go\\Work\\xugu\\xg_dba\\config"
+
+	packageModels := make(map[string]models.Cache)
+
+	err := filepath.Walk(folderPath, func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+
+		if info.IsDir() {
+			listenFilePath := filepath.Join(path, "listen.toml")
+
+			var connectInfo models.ConnectInfo
+			var systemMetaInfo models.SystemMetaInfo
+
+			if fileExists(listenFilePath) {
+				if _, err := parseTomlFile(listenFilePath, &connectInfo); err != nil {
+					return err
+				}
+			}
+
+			latestOsInfoFilePath, err := getLatestOsInfoFile(path)
+			if err != nil {
+				return err
+			}
+
+			if latestOsInfoFilePath != "" {
+				if _, err := parseTomlFile(latestOsInfoFilePath, &systemMetaInfo); err != nil {
+					return err
+				}
+			}
+
+			host := connectInfo.Ssh.Host
+			if host != "" {
+				packageModels[host] = models.Cache{
+					ConnectInfo:    connectInfo,
+					SystemMetaInfo: systemMetaInfo,
+				}
+			}
+		}
+		return nil
+	})
+
+	if err != nil {
+		fmt.Printf("Error walking the path %q: %v\n", folderPath, err)
+		return
+	}
+
+	for host, cache := range packageModels {
+		fmt.Printf("Host: %s, Cache: %+v\n", host, cache)
+	}
+}
+
+func fileExists(filename string) bool {
+	info, err := os.Stat(filename)
+	if os.IsNotExist(err) {
+		return false
+	}
+	return !info.IsDir()
+}
+
+func parseTomlFile(filePath string, v interface{}) (toml.MetaData, error) {
+	file, err := os.Open(filePath)
+	if err != nil {
+		return toml.MetaData{}, err
+	}
+	defer file.Close()
+
+	decoder := toml.NewDecoder(file)
+	metaData, err := decoder.Decode(v)
+	if err != nil {
+		return toml.MetaData{}, err
+	}
+	return metaData, nil
+}
+
+func getLatestOsInfoFile(dirPath string) (string, error) {
+	pattern := regexp.MustCompile(`^os_info(?:_\d{8}_\d{6})?\.toml$`)
+	files, err := os.ReadDir(dirPath)
+	if err != nil {
+		return "", err
+	}
+
+	var matchingFiles []string
+	for _, file := range files {
+		if !file.IsDir() && pattern.MatchString(file.Name()) {
+			matchingFiles = append(matchingFiles, filepath.Join(dirPath, file.Name()))
+		}
+	}
+
+	if len(matchingFiles) == 0 {
+		return "", nil
+	}
+
+	sort.Slice(matchingFiles, func(i, j int) bool {
+		return matchingFiles[i] > matchingFiles[j]
+	})
+
+	return matchingFiles[0], nil
+}

+ 10 - 0
internal/middleware/test/cache_test.go

@@ -0,0 +1,10 @@
+package test
+
+import (
+	"testing"
+	"xg_dba/internal/middleware"
+)
+
+func TestCache(t *testing.T) {
+	middleware.Cache()
+}

+ 27 - 0
internal/models/cache_models.go

@@ -0,0 +1,27 @@
+package models
+
+type Cache struct {
+	ConnectInfo
+	SystemMetaInfo
+}
+
+// 定义结构体
+type ConnectInfo struct {
+	Id  string  `json:"id" toml:"id"`
+	Ssh SshInfo `json:"ssh_info" toml:"server"`
+	Db  DbInfo  `json:"db_info" toml:"db"`
+}
+
+type SshInfo struct {
+	Username string `json:"username" toml:"ssh_username"`
+	Password string `json:"password" toml:"ssh_password"`
+	Host     string `json:"host" toml:"ssh_ip"`
+	Port     string `json:"port" toml:"ssh_port"`
+}
+
+type DbInfo struct {
+	User     string `json:"user" toml:"db_user"`
+	Password string `json:"password" toml:"db_password"`
+	Database string `json:"database" toml:"db_database"`
+	Port     string `json:"port" toml:"db_port"`
+}

+ 11 - 0
internal/models/system_models.go

@@ -0,0 +1,11 @@
+package models
+
+type SystemMetaInfo struct {
+	Os           string `toml:"os"`
+	Cpu          string `toml:"cpu"`
+	Memory       string `toml:"memory"`
+	Disk         string `toml:"disk"`
+	DiskSpeed    string `toml:"disk_speed"`
+	Network      string `toml:"network"`
+	NetworkSpeed string `toml:"network_speed"`
+}

+ 49 - 0
internal/services/connect/connect.go

@@ -0,0 +1,49 @@
+package services
+
+import (
+	"log"
+	"xg_dba/api"
+	"xg_dba/module/remote"
+	"xg_dba/module/toml"
+)
+
+// 设置连接信息
+func SetConnectInfo_service(connectInfo api.ConnectInfoRequest, saveFilePath string) error {
+	// 连接测试
+	sshClient, err := remote.NewSSHClient(connectInfo.Id, connectInfo.Ssh.Username, connectInfo.Ssh.Password, connectInfo.Ssh.Host, connectInfo.Ssh.Port)
+	if err != nil {
+		log.Println("连接失败", err)
+		return err
+	}
+	defer sshClient.Close()
+	// 将connectInfo存储到本地
+	//localPath := "./config/" + connectInfo.Ssh.Host + "/" + connectInfo.Ssh.Host + ".toml"
+	if err := toml.CreateFileIfNotExists(saveFilePath); err != nil {
+		log.Println("创建文件失败", err)
+		return err
+	}
+
+	// 定义组和默认值
+	groups := map[string]interface{}{
+		"server": map[string]interface{}{
+			"Ssh_Ip":       connectInfo.Ssh.Host,
+			"Ssh_Port":     connectInfo.Ssh.Port,
+			"Ssh_Username": connectInfo.Ssh.Username,
+			"Ssh_Password": connectInfo.Ssh.Password,
+		},
+		"db": map[string]interface{}{
+			"Db_Port":     connectInfo.Db.Port,
+			"Db_User":     connectInfo.Db.User,
+			"Db_Password": connectInfo.Db.Password,
+			"Db_Database": connectInfo.Db.Database,
+		},
+		"system": map[string]interface{}{},
+	}
+
+	if err := toml.CreateTOMLGoups(saveFilePath, groups); err != nil {
+		log.Println("创建文件失败", err)
+		return err
+	}
+
+	return nil
+}

+ 108 - 0
internal/services/system/system_services.go

@@ -0,0 +1,108 @@
+package services
+
+import (
+	"bytes"
+	"fmt"
+	"os"
+	"path/filepath"
+	"sync"
+	"time"
+	"xg_dba/api"
+	"xg_dba/internal/global"
+	"xg_dba/internal/models"
+	"xg_dba/module/remote"
+
+	"github.com/BurntSushi/toml"
+)
+
+func SetSystemInfo_service(connectInfo api.ConnectInfoRequest, saveFilePath string) error {
+	//ssh连接服务器
+	//执行命令
+	//返回结果并存储到本地
+	var wg sync.WaitGroup
+	var mu sync.Mutex
+
+	systemInfo := models.SystemMetaInfo{}
+
+	commands := map[string]string{
+		"OS Info":       "cat /etc/os-release",
+		"CPU Info":      "lscpu",
+		"Memory Info":   "free -h",
+		"Disk Info":     "df -h",
+		"Network Info":  "ip addr",
+		"Disk Speed":    "dd if=/dev/zero of=/tmp/testfile bs=8K count=102400 oflag=direct; rm -f /tmp/testfile",
+		"Network Speed": "ping -c 4 8.8.8.8",
+	}
+
+	for name, cmd := range commands {
+		wg.Add(1)
+
+		go func(name, cmd string) {
+			defer wg.Done()
+
+			// 每次执行命令都新建一个 SSH 客户端
+			sshClient, err := remote.NewSSHClient(connectInfo.Id, connectInfo.Ssh.Username, connectInfo.Ssh.Password, connectInfo.Ssh.Host, connectInfo.Ssh.Port)
+			if err != nil {
+				global.Logger.Errorf("NewSSHClient failed for %s: %v", name, err)
+				return
+			}
+			defer sshClient.Close()
+
+			output, err := sshClient.RunCommand(cmd)
+			if err != nil {
+				global.Logger.Errorf("%s command failed: %v", name, err)
+				return
+			}
+
+			mu.Lock()
+			// 根据命令名称将输出赋值到结构体字段
+			switch name {
+			case "OS Info":
+				systemInfo.Os = output
+			case "CPU Info":
+				systemInfo.Cpu = output
+			case "Memory Info":
+				systemInfo.Memory = output
+			case "Disk Info":
+				systemInfo.Disk = output
+			case "Network Info":
+				systemInfo.Network = output
+			case "Disk Speed":
+				systemInfo.DiskSpeed = output
+			case "Network Speed":
+				systemInfo.NetworkSpeed = output
+			}
+			mu.Unlock()
+
+			fmt.Printf("--%s:\n%s\n", name, output)
+		}(name, cmd)
+	}
+
+	wg.Wait()
+
+	timestamp := time.Now().Format("20060102_150405")
+	os.MkdirAll(filepath.Dir(saveFilePath), os.ModePerm)
+	filePath := fmt.Sprintf("%sos_info_%s.toml", saveFilePath, timestamp)
+	err := saveSystemMetaInfoToFile(systemInfo, filePath)
+	if err != nil {
+		fmt.Printf("Error: %v\n", err)
+	} else {
+		fmt.Println("System meta info saved successfully")
+	}
+	return nil
+}
+
+// 保存系统环境信息到文件
+func saveSystemMetaInfoToFile(info models.SystemMetaInfo, filePath string) error {
+	var buffer bytes.Buffer
+	encoder := toml.NewEncoder(&buffer)
+	if err := encoder.Encode(info); err != nil {
+		return fmt.Errorf("failed to encode system meta info to TOML: %v", err)
+	}
+
+	err := os.WriteFile(filePath, buffer.Bytes(), 0644)
+	if err != nil {
+		return fmt.Errorf("failed to write to file: %v", err)
+	}
+	return nil
+}

+ 48 - 0
internal/services/test/connect_test.go

@@ -0,0 +1,48 @@
+package test
+
+import (
+	"testing"
+	"xg_dba/api"
+	connect "xg_dba/internal/services/connect"
+	system "xg_dba/internal/services/system"
+)
+
+func TestConnectInfo(t *testing.T) {
+	connectInfo := api.ConnectInfoRequest{
+		Id: "1",
+		Ssh: api.SshInfo{
+			Username: "gtong",
+			Password: "845895",
+			Host:     "127.0.0.1",
+			Port:     "22",
+		},
+		Db: api.DbInfo{
+			User:     "SYSDBA",
+			Password: "SYSDBA",
+			Port:     "5236",
+			Database: "test",
+		},
+	}
+	localPath := "C:\\Program_GT\\Code\\Go\\Work\\xugu\\xg_dba\\config/" + connectInfo.Ssh.Host + "/" + connectInfo.Ssh.Host + ".toml"
+	if err := connect.SetConnectInfo_service(connectInfo, localPath); err != nil {
+		t.Errorf("SetConnectInfo_service failed: %v", err)
+	}
+
+}
+
+func TestGetServerInfo(t *testing.T) {
+	saveFilePath := "C:\\Program_GT\\Code\\Go\\Work\\xugu\\xg_dba\\config\\test\\"
+	connectInfo := api.ConnectInfoRequest{
+		Id: "1",
+		Ssh: api.SshInfo{
+			Username: "gtong",
+			Password: "845895",
+			Host:     "127.0.0.1",
+			Port:     "22",
+		},
+	}
+	if err := system.SetSystemInfo_service(connectInfo, saveFilePath); err != nil {
+		t.Errorf("SetConnectInfo_service failed: %v", err)
+	}
+
+}

+ 0 - 0
logs/log-2024-10-09.log


+ 6 - 0
main.go

@@ -1 +1,7 @@
 package main
+
+import "xg_dba/internal/global"
+
+func main() {
+	global.GlobalInit()
+}

+ 22 - 2
internal/module/remote/remote.go → module/remote/remote.go

@@ -1,6 +1,10 @@
 package remote
 
-import "golang.org/x/crypto/ssh"
+import (
+	"fmt"
+
+	"golang.org/x/crypto/ssh"
+)
 
 // SSHClient 封装SSH连接配置
 type SSHClient struct {
@@ -24,7 +28,7 @@ func NewSSHClient(Id, username, password, host, port string) (*SSHClient, error)
 
 	client, err := ssh.Dial("tcp", host+":"+port, config)
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("无法连接到服务器 %s: %v", host, err)
 	}
 
 	return &SSHClient{
@@ -43,3 +47,19 @@ func (c *SSHClient) Close() {
 		c.client.Close()
 	}
 }
+
+// RunCommand 在远程服务器上执行命令
+func (c *SSHClient) RunCommand(cmd string) (string, error) {
+	session, err := c.client.NewSession()
+	if err != nil {
+		return "", err
+	}
+	defer session.Close()
+
+	output, err := session.CombinedOutput(cmd)
+	if err != nil {
+		return "", fmt.Errorf("无法执行命令: %v", err)
+	}
+
+	return string(output), nil
+}

+ 56 - 0
module/remote/remote_test.go

@@ -0,0 +1,56 @@
+package remote
+
+import (
+	"fmt"
+	"testing"
+)
+
+func NewSSHClientTest() (*SSHClient, error) {
+	sshClient, err := NewSSHClient("1", "gtong", "845895", "127.0.0.1", "22")
+	if err != nil {
+		fmt.Errorf("NewSSHClient failed: %v", err)
+		return nil, err
+	}
+	//sshClient.Close()
+	return sshClient, nil
+}
+
+func TestRunCommand(t *testing.T) {
+	sshClient, err := NewSSHClientTest()
+	if err != nil {
+		t.Errorf("NewSSHClientTest failed: %v\n", err)
+		return
+	}
+	str, err := sshClient.RunCommand("ls -l")
+	if err != nil {
+		t.Errorf("RunCommand failed: %v\n", err)
+		return
+	}
+	fmt.Println("str: ", str)
+}
+
+func TestSystemInfo(t *testing.T) {
+	sshClient, err := NewSSHClientTest()
+	if err != nil {
+		t.Errorf("NewSSHClientTest failed: %v\n", err)
+		return
+	}
+	defer sshClient.Close()
+
+	commands := map[string]string{
+		"OS Info":      "cat /etc/os-release",
+		"CPU Info":     "lscpu",
+		"Memory Info":  "free -h",
+		"Disk Info":    "df -h",
+		"Network Info": "ip addr",
+	}
+
+	for name, cmd := range commands {
+		output, err := sshClient.RunCommand(cmd)
+		if err != nil {
+			t.Errorf("%s command failed: %v\n", name, err)
+			continue
+		}
+		fmt.Printf("%s:\n%s\n", name, output)
+	}
+}

+ 80 - 0
module/toml/toml.go

@@ -0,0 +1,80 @@
+package toml
+
+import (
+	"errors"
+	"fmt"
+	"os"
+	"path/filepath"
+
+	"github.com/spf13/viper"
+)
+
+// CreateFileIfNotExists 创建文件,如果文件已存在则返回错误
+func CreateFileIfNotExists(filename string) error {
+
+	// 获取当前工作目录
+	projectDir, err := os.Getwd()
+	if err != nil {
+		return errors.New("无法获取当前工作目录: " + err.Error())
+	}
+	fmt.Println("当前工作目录", projectDir)
+	// 检查文件是否存在
+	if _, err := os.Stat(filename); err == nil {
+		return errors.New("文件已存在")
+	} else if !os.IsNotExist(err) {
+		return err // 返回其他错误
+	}
+
+	// 确保目录存在
+	dir := filepath.Dir(filename)
+	if err := os.MkdirAll(dir, os.ModePerm); err != nil {
+		return errors.New("无法创建目录: " + err.Error())
+	}
+
+	// 创建文件
+	file, err := os.Create(filename)
+	if err != nil {
+		return errors.New("无法创建文件: " + err.Error())
+	}
+	defer file.Close()
+
+	return nil
+}
+
+// CreateTOMLGoups 在指定的 TOML 文件中创建组
+func CreateTOMLGoups(filename string, groups map[string]interface{}) error {
+	v := viper.New()
+	v.SetConfigFile(filename)
+	v.SetConfigType("toml")
+
+	// 检查文件是否存在
+	if _, err := os.Stat(filename); os.IsNotExist(err) {
+		return errors.New("文件不存在")
+	}
+
+	// 读取现有的配置文件
+	if err := v.ReadInConfig(); err != nil {
+		return errors.New("无法读取配置文件: " + err.Error())
+	}
+
+	// 打印读取的配置以进行调试
+	fmt.Println("现有配置:", v.AllSettings())
+
+	// 设置组和默认值
+	for group, defaultValue := range groups {
+		if !v.IsSet(group) { // 仅在组不存在时设置
+			fmt.Println("设置组:", group)
+			v.Set(group, defaultValue)
+		}
+	}
+
+	// 强制写入文件
+	if err := v.WriteConfigAs(filename); err != nil {
+		return errors.New("无法写入配置文件: " + err.Error())
+	}
+
+	// 打印写入后的配置以进行调试
+	fmt.Println("更新后的配置:", v.AllSettings())
+
+	return nil
+}

Some files were not shown because too many files changed in this diff