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

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.mfbz.cn/a/772882.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

密码学复习

目录 基础 欧拉函数 欧拉函数φ(n)定义 计算方法的技巧 当a=a_1*a_2*……*a_n时 欧拉定理 剩余系 一些超简单密码 维吉尼亚 密钥fox 凯撒(直接偏移) 凯特巴氏(颠倒字母表) 摩斯密码(字母对应电荷线) 希尔(hill)密码 一些攻击 RSA 求uf+vg=1 快速幂模m^…

苹果获得OpenAI董事会观察员职位、Runway最新估值40亿美元

ChatGPT狂飙160天,世界已经不是之前的样子。 更多资源欢迎关注 据知情人士透露,苹果应用商店(App Store)负责人、前营销主管Phil Schiller被选中担任这一职位。这位知情人士说,作为董事会观察员,他不会以正…

二次搭建无人车平台遇到的问题(mid360+joy游戏手柄操纵无人车)

joy节点启动 报错: ROS path [0]/opt/ros/noetic/share/ros ROS path [1]/home/jetson/yahboomcar_ws/src/yahboomcar_autodrive ROS path [2]/home/jetson/yahboomcar_ws/src/yahboomcar_bringup ROS path [3]/home/jetson/yahboomcar_ws/src/yahboomcar_ctrl ROS…

【2024版】Microsoft Azure 管理员培训课程招生简章(8月有开班)

课程介绍 本课程专为希望深入了解和精通Microsoft Azure管理的IT专业人员设计。在为期三天的培训中,学员将全面学习如何管理Azure订阅,保护标识,配置虚拟网络,以及实现存储解决方案和虚拟机。此外,课程还涵盖了实现We…

传感器标定(一)摄像头内参标定

一、使用ROS进行手动标定安装 1、安装 image-view &usb_cam ⽤于驱动相机 sudo apt-get install ros-melodic-image-view sudo apt-get install ros-melodic-usb-cam2、查看系统视频设备 v4l2- ctl -d /dev/video0 --all 查询所有相机具体的参数包括width和height ls /…

Excel数据截取及合并多行多列数据

公式一:RIGHT(A2,LEN(A2)-FINDB(")",A2)) 公式二:PHONETIC(C2:D19) 详情可以看附件。

JMeter--定时执行的方法

原文网址:JMeter--定时执行的方法_IT利刃出鞘的博客-CSDN博客 简介 本文介绍JMeter如何使用定时器定时执行测试任务。 Java技术星球:way2j.com 方法 第一步:新建定时器 右键测试任务> Add > Timer> Constant Timer 如下图所示…

【python数据处理】— “2020-01-01 05:20:15“日期格式数据

文章目录 一、数据说明及目标二、实现方式1.提取date2.提取hour3.提取weekday4.提取month 一、数据说明及目标 数据说明 数据表有一列名为"datetime"表示时间数据,该列的数据格式是"2020-01-01 05:20:15"。 import pandas as pd datapd.read_e…

云动态摘要 2024-07-04

给您带来云厂商的最新动态,最新产品资讯和最新优惠更新。 最新优惠与活动 数据库上云优选 阿里云 2024-07-04 RDS、PolarDB、Redis、MongoDB 全系产品新用户低至首年6折起! [免费体验]智能助手ChatBI上线 腾讯云 2024-07-02 基于混元大模型打造&…

搜维尔科技:【研究】Scalefit人体工程学测量系统为预防肌肉骨骼疾病提供生物力学分析

与工作相关的肌肉骨骼疾病(MSE)是工作生活中的一个持续的伴侣。总部位于科隆的Scaleit公司生产的移动生物力学测量系统Industrial Athlete有助于在工作场所立即发现疾病,伤害和损伤的原因。 Scalefit是一个跨学科网络的一部分,在德国科隆体育大学和职业…

【CT】LeetCode手撕—232. 用栈实现队列

目录 题目1- 思路2- 实现⭐232. 用栈实现队列——题解思路 3- ACM 实现 题目 原题连接:232. 用栈实现队列 1- 思路 思路 ① 用两个栈来实现队列,一个 in 入栈 和一个 out 出栈② push 入队:入栈逻辑:即将元素加入到 in 栈 里即…

spring6框架解析(by尚硅谷)

文章目录 spring61. 一些基本的概念、优势2. 入门案例实现maven聚合工程创建步骤分析实现过程 3. IoC(Inversion of Control)基于xml的bean环境搭建获取bean获取接口创建实现类依赖注入 setter注入 和 构造器注入原生方式的setter注入原生方式的构造器注…

Android studio开发入门教程详解(复习)

引言 本文为个人总结Android基础知识复习笔记。如有不妥之处,敬请指正。后续将持续更新更多知识点。 文章目录 引言UITextView文本基本用法实际应用常用属性和方法 Button按钮处理点击事件 EditText输入框基本属性高级特性 ImageView图片ImageView的缩放模式 Prog…

实战教程:如何用JavaScript构建一个功能强大的音乐播放器,兼容本地与在线资源

项目地址:Music Player App 作者:Reza Mehdikhanlou 视频地址:youtube 我将向您展示如何使用 javascript 编写音乐播放器。我们创建一个项目,您可以使用 javascript 从本地文件夹或任何 url 播放音频文件。 项目目录 assets 1…

图DFS遍历

DFS遍历图 伪代码 俩函数。 判断图有几个连通分支&#xff1f;就是图的遍历&#xff0c;dfs完了就给他 #include <iostream> #include <cstdlib> #include <bits/stdc.h> #include <vector> using namespace std; const int N102; int n,m,temp1,te…

Python学习笔记28:进阶篇(十七)常见标准库使用之质量控制中的代码质量与风格第二部分

前言 本文是根据python官方教程中标准库模块的介绍&#xff0c;自己查询资料并整理&#xff0c;编写代码示例做出的学习笔记。 根据模块知识&#xff0c;一次讲解单个或者多个模块的内容。 教程链接&#xff1a;https://docs.python.org/zh-cn/3/tutorial/index.html 质量控制…

面试篇-Redis-2+持久化+过期key删除+内存淘汰

文章目录 前言一、你知道Redis 数据是怎么持久化的1.1 Redis 持久化的方式Rdb&#xff1a;1.1.1 主动备份save 命令&#xff1a;1.1.2 Redis 中使用bgsave 进行Rdb 的持久化 &#xff1a; 1.2 Redis 持久化的方式Aof&#xff1a;1.2.1 使用AOF 模式进行数据存储&#xff1a;1.2…

数据库主从复制

目录 一.主从复制架构 二.主从复制原理 三.实现主从复制配置 1.新建主从复制 2.实战遇到问题 3.复制错误解决方法 4.级联 主从复制 5.半同步复制 MySQL数据库的主从复制&#xff08;Master-Slave Replication&#xff09;是一种常见的数据库复制架构&#xff0c;用于提…

越南宣称已成全球第二大手机出口国,富士康翻白眼,为啥限电?

日前越南媒体报道指越南今年前5个月的手机及零部件出口达到224亿美元&#xff0c;同比增长11%&#xff0c;超越印度&#xff0c;成为仅次于中国的全球第二大手机出口国&#xff0c;对此富士康、三星恐怕会有不同的意见。 为越南手机业务做出重要贡献的无疑是富士康、三星等企业…