You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
star/httpserver/cmd.go

162 lines
5.4 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package httpserver
import (
"b612.me/starlog"
"b612.me/staros"
"context"
"encoding/json"
"fmt"
"github.com/spf13/cobra"
"os"
"os/signal"
"regexp"
"strconv"
"strings"
)
var s HttpServer
var daemon bool
var hooks string
var speedlimit string
func init() {
Cmd.Flags().StringVarP(&hooks, "hook", "H", "", "fileget hook for modify")
Cmd.Flags().StringVarP(&s.port, "port", "p", "80", "监听端口")
Cmd.Flags().StringVarP(&s.addr, "ip", "i", "0.0.0.0", "监听ip")
Cmd.Flags().StringVarP(&s.envPath, "folder", "f", "./", "本地文件地址")
Cmd.Flags().StringVarP(&s.uploadFolder, "upload", "u", "", "文件上传文件夹路径")
Cmd.Flags().BoolVarP(&daemon, "daemon", "d", false, "以后台进程运行")
Cmd.Flags().StringVarP(&s.basicAuthUser, "auth", "a", "", "HTTP BASIC AUTH认证(用户名:密码)")
Cmd.Flags().StringVarP(&s.indexFile, "index", "n", "", "Index文件名如index.html")
Cmd.Flags().StringVarP(&s.logpath, "log", "l", "", "log地址")
Cmd.Flags().StringVarP(&s.cert, "ssl-cert", "c", "", "TLS证书路径")
Cmd.Flags().StringVarP(&s.key, "ssl-key", "k", "", "TLS密钥路径")
Cmd.Flags().BoolVarP(&s.disableMIME, "disablemime", "m", false, "停止解析MIME全部按下载文件处理")
Cmd.Flags().StringSliceVarP(&s.protectAuthPage, "protect-page", "P", []string{}, "Basic Auth 开启白名单")
Cmd.Flags().StringVar(&s.page401, "401", "", "自定义401页面地址")
Cmd.Flags().StringVar(&s.page403, "403", "", "自定义403页面地址")
Cmd.Flags().StringVar(&s.page404, "404", "", "自定义404页面地址")
Cmd.Flags().BoolVarP(&s.httpDebug, "debug", "D", false, "开启调试模式")
Cmd.Flags().StringSliceVarP(&s.noListPath, "nolist", "N", []string{}, "禁止列出文件的路径,如/")
Cmd.Flags().StringToStringVarP(&s.listPwd, "listpwd", "L", map[string]string{}, "列出文件的路径的密码,如/=/password")
Cmd.Flags().BoolVarP(&s.listSameForFile, "list-same", "S", false, "如开启,文件的获取权限将与文件夹保持一致")
Cmd.Flags().StringVarP(&speedlimit, "speedlimit", "s", "", "限速如1M意思是1MB/s")
Cmd.Flags().Bool("daeapplied", false, "")
Cmd.Flags().StringVar(&s.background, "background", "", "背景图片地址")
Cmd.Flags().StringVar(&s.mobildBackground, "mbackground", "", "移动端背景图片地址")
Cmd.Flags().MarkHidden("daeapplied")
}
func parseSpeedString(speedString string) (uint64, error) {
// 定义单位及其对应的字节值
unitMultipliers := map[string]int{
"b": 1, "": 1,
"k": 1024, "kb": 1024, "kib": 1024,
"m": 1024 * 1024, "mb": 1024 * 1024, "mib": 1024 * 1024,
"g": 1024 * 1024 * 1024, "gb": 1024 * 1024 * 1024, "gib": 1024 * 1024 * 1024,
"t": 1024 * 1024 * 1024 * 1024, "tb": 1024 * 1024 * 1024 * 1024, "tib": 1024 * 1024 * 1024 * 1024,
}
// 正则表达式匹配速度的格式
re := regexp.MustCompile(`(?i)^\s*([\d.]+)\s*(b|k|m|g|t|kb|mb|gb|tb|kib|mib|gib|tib)?\s*/?\s*s?\s*$`)
matches := re.FindStringSubmatch(strings.ToLower(speedString))
if matches == nil {
return 0, fmt.Errorf("invalid speed string format")
}
// 解析数值部分
value, err := strconv.ParseFloat(matches[1], 64)
if err != nil {
return 0, fmt.Errorf("invalid numeric value")
}
// 获取单位部分
unit := matches[2]
if unit == "" {
unit = "b"
}
// 根据单位计算最终的字节每秒值
multiplier, ok := unitMultipliers[unit]
if !ok {
return 0, fmt.Errorf("invalid unit in speed string")
}
return uint64(value * float64(multiplier)), nil
}
var Cmd = &cobra.Command{
Use: "http",
Short: "HTTP文件服务器(HTTP File Browser Server)",
Long: `HTTP文件服务器(HTTP File Browser Server)`,
Run: func(cmd *cobra.Command, args []string) {
if s.logpath != "" && starlog.GetWriter() == nil {
starlog.SetLogFile(s.logpath, starlog.Std, true)
}
if speedlimit != "" {
speed, err := parseSpeedString(speedlimit)
if err != nil {
starlog.Criticalln("Speed Limit Error:", err)
os.Exit(1)
}
s.speedlimit = speed
starlog.Infoln("Speed Limit:(user in):\t", speedlimit)
starlog.Infoln("Speed Limit (bytes/s):\t", speed)
}
if hooks != "" {
if !staros.Exists(hooks) {
starlog.Criticalln("hook file not exists")
os.Exit(2)
}
data, err := os.ReadFile(hooks)
if err != nil {
starlog.Criticalln("read hook file error", err)
os.Exit(3)
}
var hk []ServerHook
err = json.Unmarshal(data, &hk)
if err != nil {
starlog.Errorln("Unmarshal hook Json Failed", err)
os.Exit(4)
}
s.hooks = hk
}
apply, _ := cmd.Flags().GetBool("daeapplied")
if daemon && !apply {
nArgs := append(os.Args[1:], "--daeapplied")
pid, err := staros.Daemon(os.Args[0], nArgs...)
if err != nil {
starlog.Criticalln("Daemon Error:", err)
os.Exit(1)
}
starlog.StdPrintf([]starlog.Attr{starlog.FgGreen}, "Success,PID=%v\n", pid)
return
}
sig := make(chan os.Signal)
signal.Notify(sig, os.Kill, os.Interrupt)
ctx, fn := context.WithCancel(context.Background())
go func() {
starlog.Infoln("Recv Signal", <-sig)
fn()
}()
if s.basicAuthUser != "" {
tmp := strings.SplitN(s.basicAuthUser, ":", 2)
if len(tmp) != 2 {
starlog.Errorln("basic Auth should have user and password")
os.Exit(2)
}
s.basicAuthUser = strings.TrimSpace(tmp[0])
s.basicAuthPwd = tmp[1]
}
err := s.Run(ctx)
if err != nil {
starlog.Errorln("Http Server Closed by Errors", err)
os.Exit(1)
}
starlog.Infoln("Http Server Closed Normally")
},
}