go开源webssh终端源码main.go分析

news2024/10/5 18:04:33

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))
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1892400.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Qwen2部署实战】探索Qwen2-7B:通过FastApi框架实现API的部署与调用

系列篇章💥 No.文章1【Qwen部署实战】探索Qwen-7B-Chat:阿里云大型语言模型的对话实践2【Qwen2部署实战】Qwen2初体验:用Transformers打造智能聊天机器人3【Qwen2部署实战】探索Qwen2-7B:通过FastApi框架实现API的部署与调用4【Q…

springboot双学位招生管理系统-计算机毕业设计源码93054

摘 要 科技进步的飞速发展引起人们日常生活的巨大变化,电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流,人类发展的历史正进入一个新时代。在现实运用中,应用软件的工作…

松下Panasonic机器人维修故障原因

松下机器人伺服电机是许多工业自动化设备的关键组成部分。了解如何进行Panasonic工业机械臂电机维修,对于确保设备正常运行至关重要。 【松下焊接机器人维修案例】【松下机器人维修故障排查】 一、常见松下工业机械手伺服电机故障及原因 1. 过热:过热可…

Webpack: 并行构建

概述 受限于 Node.js 的单线程架构,原生 Webpack 对所有资源文件做的所有解析、转译、合并操作本质上都是在同一个线程内串行执行,CPU 利用率极低,因此,理所当然地,社区出现了一些以多进程方式运行 Webpack&#xff0…

铜排载流量计算

母线载流量的理论计算 有些设计规范给出了根据电流密度确定母线大小的标准,一般铜母线的要求是每平方毫米载流量1.55A,但只可以作为设计“自由空气中的单导体母线”的参考,不可以作为实际设备中选择母线截面积的方法。也有些设计手册里给出了…

无线领夹麦克风选什么价位,揭秘无线领夹麦克风哪个品牌音质最好

在自媒体的快速发展之下,越来越多人加入到短视频拍摄行业。当我们踏出户外,想要用声音记录美好生活时,一个优质的麦克风便成了不可或缺的装备。户外环境的喧嚣与手机麦克风的局限性常常让我们的声音淹没在背景噪音之中,使得同期录…

小白也能看懂的Python基础教程(8)

Python面向对象 目录 Python面向对象 一、面向对象的概念 1、常见的编程思想 2、面向过程是什么? 3、什么是面向对象? 4、封装 5、继承 6、多态 二、面向对象的概念 1、两个重要概念 2、类 3、对象 4、self关键字 三、对象属性 1、什么…

昇思25天学习打卡营第8天|MindSpore保存与加载(保存和加载MindIR)

在MindIR中,一个函数图(FuncGraph)表示一个普通函数的定义,函数图一般由ParameterNode、ValueNode和CNode组成有向无环图,可以清晰地表达出从参数到返回值的计算过程。在上图中可以看出,python代码中两个函…

Unity Scrollview的Scrollbar控制方法

备忘:碰到用scrollview自带的scrollbar去控制滑动,结果发现用代码控制scrollbar.value无效,搜了一下都是说用scrollRect.verticalNormalizedPosition和scrollRect.horizontalNormalizedPosition来控制的。我寻思着有关联的scrollbar为什么用不…

【TB作品】智能台灯控制器,ATMEGA128单片机,Proteus仿真

题目 8 :智能台灯控制器 基于单片机设计智能台灯控制器,要求可以调节 LED 灯的亮度,实现定时开启与关闭, 根据光照自动开启与关闭功能。 具体要求如下: (1)通过 PWM 功能调节 LED 灯亮度&#x…

Jenkins 使用 Publish over SSH进行远程访问

Publish over SSH 是 Jenkins 的一个插件,可以让你通过 SSH 将构建产物分发到远程服务器。以下是如何开启 Publish over SSH 的步骤: 一、安装 Publish over SSH 插件 在 Jenkins 中,进入 "Manage Jenkins" > "Manage Plugins"。选择 "Availab…

储能锂电池出货量持续增长 国家政策推动行业发展速度加快

储能锂电池出货量持续增长 国家政策推动行业发展速度加快 储能锂电池又称锂离子储能电池,指专为储存电能而设计的锂离子电池。储能锂电池具有转换效率高、能量密度高、维护成本低、环境适应性强、响应速度快等优势,在数据中心、通信基站以及电力系统等领…

香橙派AIpro如何赋能AI+边缘流媒体设备

文章目录 (一)前言(二)AI边缘流媒体设备展示(三)赋能AI边缘流媒体设备1、准备开发环境2、在板子中下载编译安装SRS3、基本推拉流测试4、多路推流性能测试 (四)一些注意事项1、开发板…

webSocket网页通信---使用js模拟多页面实时通信

webSocket是什么 WebSocket是一种先进的网络技术,它提供了一种在单个TCP连接上进行全双工通信的能力。传统的基于HTTP的通信是单向的,即客户端发起请求,服务器响应请求,然后连接关闭。但是,WebSocket允许服务器和客户端…

Nginx系列(二)---Mac上的快速使用

一、安装 前置软件&#xff1a;Homebrew 安装方法&#xff1a;终端输入/bin/bash -c "$(curl -fsSL <https://cdn.jsdelivr.net/gh/ineo6/homebrew-install/install.sh>)"更新&#xff1a; brew update 设置中科大镜像源&#xff1a;git -C "$(brew --r…

【串口通信】之TTL电平

1. 什么是串口 串口,全称为串行通信端口,是一种计算机硬件接口,用于实现数据的串行传输。与并行通信不同,串口通信一次只传输一个比特,数据通过串行线按顺序传输。串口通信在嵌入式系统、工业控制、计算机与外围设备通信等领域非常常见 2. 什么是串口通信 串口通信是指通过…

和闺蜜的泰国之旅

每当我回想起那次和闺蜜丽丽&#xff08;全名罗莉&#xff09;的泰国之旅&#xff0c;心中总是涌起复杂的情绪。那段经历仿佛一场噩梦&#xff0c;至今仍无法从脑海中挥去。 我们满怀期待地抵达曼谷&#xff0c;热带的阳光、繁忙的街道、美味的街头小吃&#xff0c;都让我们兴…

Redis 管道(Pipeline)是什么?有什么用?

目录 1. redis 客户端-服务端模型的不足之处 2. redis 管道是什么&#xff1f;有什么好处&#xff1f; 3. 管道的使用场景 4. 管道使用的注意事项 1. redis 客户端-服务端模型的不足之处 众所周知&#xff0c;redis 是一个客户端-服务端的模型设计&#xff0c;客户端向服务…

树莓派0 2W重启后突然没有声音

树莓派0 2W重启后突然没有声音。 最近在使用该板卡。重启后突然出现了显示器不能显示界面的情况&#xff0c;接着用putty的ssh方式连接该板卡&#xff0c;能连上。使用vnc方式连接该板卡&#xff0c;也能连上。后来通过修改/boot/config.txt文件&#xff0c;能在显示器上显示界…

WordPress付费进群V2主题,多种引流方法,引私域二次变现

全新前端UI界面&#xff0c;多种前端交互特效让页面不再单调&#xff0c;进群页面群成员数&#xff0c;群成员头像名称&#xff0c;每次刷新页面随机更新不重复&#xff0c;最下面评论和点赞也是如此随机刷新不重复 进群页面简介&#xff0c;群聊名称&#xff0c;群内展示&…