1.地址:  

https://github.com/Jrohy/webssh.git

2.添加中文注释地址:

https://github.com/tonyimax/webssh_cn.git

main.go分析

主包名:main

package main //主包名

依赖包加载

//导入依赖包
import (
	"embed"                       //可执行文件资源嵌入
	"flag"                        //标志变量
	"fmt"                         //格式化
	"github.com/gin-contrib/gzip" //压缩库
	"github.com/gin-gonic/gin"    //网页框架
	"io/fs"                       //文件系统
	"net/http"                    //http通信
	"os"                          //系统信息
	"strconv"                     //字符串转换
	"strings"                     //字符串
	"time"                        //时间
	"webssh/controller"           //websocket通信
)
在可执行文件中嵌入文件夹dist
//go:embed web/dist/*

访问集成文件夹文件系统

var f embed.FS //集成文件集合,取go:embed中文件夹中文件与文件夹列表
变量声明
var (
	//整形标志声明,用于储存整形指针
	port = flag.Int("p", //标志名
		5032,     //标志值
		"服务运行端口") //标志描述
	v        = flag.Bool("v", false, "显示版本号")
	authInfo = flag.String("a", "", "开启账号密码登录验证, '-a user:pass'的格式传参")
	//普通变量声明
	timeout    int    //连接超时
	savePass   bool   //保存密码
	version    string //版本号
	buildDate  string //编译时间
	goVersion  string //go版本号
	gitVersion string //git版本号
	username   string //用户名
	password   string //密码
)

初始化函数分析

func init() {}

初始化变量为标志

//初始化timeout变量为标志
	flag.IntVar(&timeout, //标志指针
		"t",              //标志名
		120,              //标志值
		"ssh连接超时时间(min)") //标志描述
	//初始化savePass变量为标志
	flag.BoolVar(&savePass, //标志指针
		"s",       //标志名
		true,      //标志值
		"保存ssh密码") //标志描述
	flag.StringVar(&version,
		"ver",
		"v1.0.0",
		"程序版本号")
	flag.StringVar(&goVersion,
		"gover",
		"v1.22",
		"go版本号")
	flag.StringVar(&gitVersion,
		"gitver",
		"2.45.2",
		"git版本号")
	flag.StringVar(&buildDate,
		"d",
		time.Now().String(),
		"编译日期")

操作环境变量

//查找环境变量savePass
	if envVal, ok := os.LookupEnv("savePass"); ok {
		//转换环境变量值为Bool值
		if b, err := strconv.ParseBool(envVal); err == nil {
			savePass = b //如果环境变量有值保存到savePass
		}
	}
	//读取环境变量用户验证信息
	if envVal, ok := os.LookupEnv("authInfo"); ok {
		*authInfo = envVal
	}
	//读取环境变量通信端口信息
	if envVal, ok := os.LookupEnv("port"); ok {
		//转换为整数
		if b, err := strconv.Atoi(envVal); err == nil {
			*port = b
		}
	}
	//必须在标志定义之后及程序访问之前调用
	flag.Parse()

参数检测

//如果有-v参数,显示版本号信息
	if *v {
		fmt.Printf("Version: %s\n\n", version)
		fmt.Printf("BuildDate: %s\n\n", buildDate)
		fmt.Printf("GoVersion: %s\n\n", goVersion)
		fmt.Printf("GitVersion: %s\n\n", gitVersion)
		os.Exit(0)
	}

用户名与密码参数分割 (-a user:pass'的格式传参)

if *authInfo != "" {
		//分割用户名与密码
		accountInfo := strings.Split(*authInfo, ":")
		//非空判断
		if len(accountInfo) != 2 ||
			accountInfo[0] == "" ||
			accountInfo[1] == "" {
			fmt.Println("请按'user:pass'的格式来传参或设置环境变量, 且账号密码都不能为空!")
			os.Exit(0)
		}
		//保存用户名与密码
		username, password = accountInfo[0], accountInfo[1]
	}

静态路由函数分析

func staticRouter(router *gin.Engine) {}

创建用户键值对

//创建账户map
		accountList := map[string]string{
			username: password,
		}

授权并写页面

//授权路由
		//传入用户列表{用户:密码}
		authorized := router.Group("/", gin.BasicAuth(accountList))
		authorized.GET("", func(c *gin.Context) {
			//读取主页面
			indexHTML, _ := f.ReadFile("web/dist/" + "index.html")
			//向上下文写入主页面
			c.Writer.Write(indexHTML)
		})

http操作静态资源

staticFs, _ := fs.Sub(f, "web/dist/static")
router.StaticFS("/static", http.FS(staticFs))

main主函数分析

func main() {}

设置http服务参数并启用路由

//取web引擎实例
	server := gin.Default()
	//设置可信代理
	server.SetTrustedProxies(nil)
	//使用压缩中间件,支持资源压缩功能
	server.Use(gzip.Gzip(gzip.DefaultCompression))
	//启动路由
	staticRouter(server)

HTTP服务操作:

//HTTP服务操作
	//GET操作,连接终端websocket
	server.GET("/term", func(c *gin.Context) {
		//调用终端websocket
		controller.TermWs(c, time.Duration(timeout)*time.Minute)
	})
	//GET操作,SSH服务检测
	server.GET("/check", func(c *gin.Context) {
		//检测SSH服务
		responseBody := controller.CheckSSH(c)
		//保存连接密码
		responseBody.Data = map[string]interface{}{
			"savePass": savePass,
		}
		//渲染JSON数据及HTTP状态码给客户端
		c.JSON(200, responseBody)
	})

文件资源操作:

//文件资源操作
	file := server.Group("/file")
	{
		//请求文件列表
		file.GET("/list", func(c *gin.Context) {
			c.JSON(200, controller.FileList(c))
		})
		//下载文件
		file.GET("/download", func(c *gin.Context) {
			controller.DownloadFile(c)
		})
		//上传文件
		file.POST("/upload", func(c *gin.Context) {
			c.JSON(200, controller.UploadFile(c))
		})
		//上传/下载进度处理
		file.GET("/progress", func(c *gin.Context) {
			controller.UploadProgressWs(c)
		})
	}

启动HTTP服务

//启动HTTP服务
	server.Run(fmt.Sprintf(":%d", *port))

启动成功输出 如下日志:

[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:	export GIN_MODE=release
 - using code:	gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /                         --> main.staticRouter.func2 (4 handlers)
[GIN-debug] GET    /static/*filepath         --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (4 handlers)
[GIN-debug] HEAD   /static/*filepath         --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (4 handlers)
[GIN-debug] GET    /term                     --> main.main.func1 (4 handlers)
[GIN-debug] GET    /check                    --> main.main.func2 (4 handlers)
[GIN-debug] GET    /file/list                --> main.main.func3 (4 handlers)
[GIN-debug] GET    /file/download            --> main.main.func4 (4 handlers)
[GIN-debug] POST   /file/upload              --> main.main.func5 (4 handlers)
[GIN-debug] GET    /file/progress            --> main.main.func6 (4 handlers)
[GIN-debug] Listening and serving HTTP on :5032

main.go

package main //主包名
//导入依赖包
import (
	"embed"                       //可执行文件资源嵌入
	"flag"                        //标志变量
	"fmt"                         //格式化
	"github.com/gin-contrib/gzip" //压缩库
	"github.com/gin-gonic/gin"    //网页框架
	"io/fs"                       //文件系统
	"net/http"                    //http通信
	"os"                          //系统信息
	"strconv"                     //字符串转换
	"strings"                     //字符串
	"time"                        //时间
	"webssh/controller"           //websocket通信
)

// 在可执行文件中嵌入文件夹dist
//
//go:embed web/dist/*
var f embed.FS //集成文件集合,取go:embed中文件夹中文件与文件夹列表
// 变量声明
var (
	//整形标志声明,用于储存整形指针
	port = flag.Int("p", //标志名
		5032,     //标志值
		"服务运行端口") //标志描述
	v        = flag.Bool("v", false, "显示版本号")
	authInfo = flag.String("a", "", "开启账号密码登录验证, '-a user:pass'的格式传参")
	//普通变量声明
	timeout    int    //连接超时
	savePass   bool   //保存密码
	version    string //版本号
	buildDate  string //编译时间
	goVersion  string //go版本号
	gitVersion string //git版本号
	username   string //用户名
	password   string //密码
)

// 初始化
func init() {
	//初始化timeout变量为标志
	flag.IntVar(&timeout, //标志指针
		"t",              //标志名
		120,              //标志值
		"ssh连接超时时间(min)") //标志描述
	//初始化savePass变量为标志
	flag.BoolVar(&savePass, //标志指针
		"s",       //标志名
		true,      //标志值
		"保存ssh密码") //标志描述
	flag.StringVar(&version,
		"ver",
		"v1.0.0",
		"程序版本号")
	flag.StringVar(&goVersion,
		"gover",
		"v1.22",
		"go版本号")
	flag.StringVar(&gitVersion,
		"gitver",
		"2.45.2",
		"git版本号")
	flag.StringVar(&buildDate,
		"d",
		time.Now().String(),
		"编译日期")
	//查找环境变量savePass
	if envVal, ok := os.LookupEnv("savePass"); ok {
		//转换环境变量值为Bool值
		if b, err := strconv.ParseBool(envVal); err == nil {
			savePass = b //如果环境变量有值保存到savePass
		}
	}
	//读取环境变量用户验证信息
	if envVal, ok := os.LookupEnv("authInfo"); ok {
		*authInfo = envVal
	}
	//读取环境变量通信端口信息
	if envVal, ok := os.LookupEnv("port"); ok {
		//转换为整数
		if b, err := strconv.Atoi(envVal); err == nil {
			*port = b
		}
	}
	//必须在标志定义之后及程序访问之前调用
	flag.Parse()
	//如果有-v参数,显示版本号信息
	if *v {
		fmt.Printf("Version: %s\n\n", version)
		fmt.Printf("BuildDate: %s\n\n", buildDate)
		fmt.Printf("GoVersion: %s\n\n", goVersion)
		fmt.Printf("GitVersion: %s\n\n", gitVersion)
		os.Exit(0)
	}
	if *authInfo != "" {
		//分割用户名与密码
		accountInfo := strings.Split(*authInfo, ":")
		//非空判断
		if len(accountInfo) != 2 ||
			accountInfo[0] == "" ||
			accountInfo[1] == "" {
			fmt.Println("请按'user:pass'的格式来传参或设置环境变量, 且账号密码都不能为空!")
			os.Exit(0)
		}
		//保存用户名与密码
		username, password = accountInfo[0], accountInfo[1]
	}
}

// 启动静态路由
func staticRouter(router *gin.Engine) {
	//如果密码不为空
	if password != "" {
		//创建账户map
		accountList := map[string]string{
			username: password,
		}
		//授权路由
		//传入用户列表{用户:密码}
		authorized := router.Group("/", gin.BasicAuth(accountList))
		authorized.GET("", func(c *gin.Context) {
			//读取主页面
			indexHTML, _ := f.ReadFile("web/dist/" + "index.html")
			//向上下文写入主页面
			c.Writer.Write(indexHTML)
		})
	} else {
		router.GET("/", func(c *gin.Context) {
			indexHTML, _ := f.ReadFile("web/dist/" + "index.html")
			c.Writer.Write(indexHTML)
		})
	}
	//http操作静态资源
	staticFs, _ := fs.Sub(f, "web/dist/static")
	router.StaticFS("/static", http.FS(staticFs))
}

func main() {
	//取web引擎实例
	server := gin.Default()
	//设置可信代理
	server.SetTrustedProxies(nil)
	//使用压缩中间件,支持资源压缩功能
	server.Use(gzip.Gzip(gzip.DefaultCompression))
	//启动路由
	staticRouter(server)

	//HTTP服务操作
	//GET操作,连接终端websocket
	server.GET("/term", func(c *gin.Context) {
		//调用终端websocket
		controller.TermWs(c, time.Duration(timeout)*time.Minute)
	})
	//GET操作,SSH服务检测
	server.GET("/check", func(c *gin.Context) {
		//检测SSH服务
		responseBody := controller.CheckSSH(c)
		//保存连接密码
		responseBody.Data = map[string]interface{}{
			"savePass": savePass,
		}
		//渲染JSON数据及HTTP状态码给客户端
		c.JSON(200, responseBody)
	})
	//文件资源操作
	file := server.Group("/file")
	{
		//请求文件列表
		file.GET("/list", func(c *gin.Context) {
			c.JSON(200, controller.FileList(c))
		})
		//下载文件
		file.GET("/download", func(c *gin.Context) {
			controller.DownloadFile(c)
		})
		//上传文件
		file.POST("/upload", func(c *gin.Context) {
			c.JSON(200, controller.UploadFile(c))
		})
		//上传/下载进度处理
		file.GET("/progress", func(c *gin.Context) {
			controller.UploadProgressWs(c)
		})
	}
	//启动HTTP服务
	server.Run(fmt.Sprintf(":%d", *port))
}

 

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部