Files
ogame-vue-ts/main.go
2026-01-06 03:00:02 +08:00

197 lines
5.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"bufio"
"embed"
"flag"
"fmt"
"io/fs"
"net"
"net/http"
"os"
"os/exec"
"runtime"
"strconv"
"strings"
"time"
)
// 使用 go:embed 强制将 docs 文件夹及其所有内容打包进二进制文件
//go:embed docs/*
var content embed.FS
func main() {
// --- 1. 命令行参数配置 ---
// 定义 -port 参数,默认为 -1表示未指定需要交互选择
portPtr := flag.Int("port", -1, "指定运行端口 (例如: 8080),不指定则显示交互菜单")
flag.Parse()
// 如果没有通过命令行指定端口,显示交互式菜单
port := *portPtr
if port == -1 {
port = showPortMenu()
}
// --- 2. 静态资源处理 ---
// 获取 docs 子目录的文件系统句柄
distFS, err := fs.Sub(content, "docs")
if err != nil {
fmt.Printf("错误: 无法访问嵌入的 docs 目录: %v\n", err)
return
}
fileServer := http.FileServer(http.FS(distFS))
// 自定义路由处理:支持静态文件和 SPA (单页应用) 回退
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// 移除路径前缀的斜杠
path := strings.TrimPrefix(r.URL.Path, "/")
// 尝试打开文件
f, err := distFS.Open(path)
if err != nil {
// 如果文件不存在(或者是访问根目录),则回退到 index.html
// 这是为了支持 Vue Router 的 History 模式
indexData, err := fs.ReadFile(distFS, "index.html")
if err != nil {
http.Error(w, "Index.html not found in embedded docs", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
http.ServeContent(w, r, "index.html", time.Now(), strings.NewReader(string(indexData)))
return
}
f.Close()
// 如果文件存在,使用标准文件服务器响应
fileServer.ServeHTTP(w, r)
})
// --- 3. 端口监听逻辑 ---
addr := fmt.Sprintf("0.0.0.0:%d", port)
listener, err := net.Listen("tcp", addr)
if err != nil {
fmt.Printf("错误: 端口 %d 已被占用或监听失败: %v\n", port, err)
// 停留 5 秒让用户看到错误信息
time.Sleep(5 * time.Second)
os.Exit(1)
}
actualPort := listener.Addr().(*net.TCPAddr).Port
localUrl := fmt.Sprintf("http://localhost:%d", actualPort)
lanUrl := fmt.Sprintf("http://%s:%d", getLocalIp(), actualPort)
// --- 4. 控制台信息展示 ---
fmt.Println("=======================================")
fmt.Printf("OGame Vue Ts 服务启动成功!\n")
fmt.Printf("启动时间: %s\n", time.Now().Format("2006-01-02 15:04:05"))
fmt.Printf("本地访问: %s\n", localUrl)
fmt.Printf("局域网访问: %s\n", lanUrl)
if port != 0 {
fmt.Printf("运行模式: 固定端口 (%d)\n", port)
} else {
fmt.Printf("运行模式: 自动分配端口\n")
}
fmt.Println("=======================================")
fmt.Println("提示: 请勿关闭此控制台窗口,否则服务将停止。")
fmt.Println("--- 实时访问日志 ---")
// --- 5. 自动打开浏览器并启动服务 ---
go openBrowser(localUrl)
err = http.Serve(listener, nil)
if err != nil {
fmt.Printf("服务运行异常: %v\n", err)
}
}
// 获取本机局域网 IP
func getLocalIp() string {
addrs, err := net.InterfaceAddrs()
if err != nil {
return "localhost"
}
for _, address := range addrs {
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
return ipnet.IP.String()
}
}
}
return "localhost"
}
// 根据不同操作系统自动打开默认浏览器
func openBrowser(url string) {
var cmd string
var args []string
switch runtime.GOOS {
case "windows":
cmd = "cmd"
args = []string{"/c", "start", url}
case "darwin":
cmd = "open"
args = []string{url}
default: // linux
cmd = "xdg-open"
args = []string{url}
}
_ = exec.Command(cmd, args...).Start()
}
// 显示端口选择菜单
func showPortMenu() int {
reader := bufio.NewReader(os.Stdin)
fmt.Println("=======================================")
fmt.Println(" OGame Vue Ts 服务器启动")
fmt.Println("=======================================")
fmt.Println()
fmt.Println("请选择端口模式:")
fmt.Println(" [1] 随机端口 (自动分配可用端口)")
fmt.Println(" [2] 自定义端口 (指定固定端口)")
fmt.Println()
fmt.Print("请输入选项 (1/2): ")
for {
input, _ := reader.ReadString('\n')
input = strings.TrimSpace(input)
switch input {
case "1", "":
fmt.Println("\n已选择: 随机端口模式")
return 0
case "2":
return inputCustomPort(reader)
default:
fmt.Print("无效输入,请输入 1 或 2: ")
}
}
}
// 输入自定义端口
func inputCustomPort(reader *bufio.Reader) int {
fmt.Print("请输入端口号 (1-65535推荐: 8080): ")
for {
input, _ := reader.ReadString('\n')
input = strings.TrimSpace(input)
// 如果直接回车,使用默认端口 8080
if input == "" {
fmt.Println("\n已选择: 固定端口 8080")
return 8080
}
port, err := strconv.Atoi(input)
if err != nil || port < 1 || port > 65535 {
fmt.Print("无效端口号,请输入 1-65535 之间的数字: ")
continue
}
fmt.Printf("\n已选择: 固定端口 %d\n", port)
return port
}
}