Files
zhilv 8265df0dcd feat: 初始提交 - Code Server Bridge完整实现
- OAuth认证系统(Gitea + Lua扩展)
- Git自动化操作(本地/SSH远程)
- 实时进度WebSocket推送
- 现代化Tab界面UI
- Cobra CLI命令行(init/version/serve)
- 完整构建系统(Makefile + Taskfile)
- UPX压缩支持(体积减少70%)
2026-01-08 23:32:29 +08:00

150 lines
3.4 KiB
Go

package handlers
import (
"encoding/json"
"net/http"
"sync"
"time"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
// 允许所有来源(生产环境应该做更严格的检查)
return true
},
}
// ProgressMessage WebSocket进度消息结构
type ProgressMessage struct {
Status string `json:"status"` // 状态: checking, cloning, pulling, success, error
Message string `json:"message"` // 消息文本
Percent int `json:"percent"` // 进度百分比 (0-100)
}
// ProgressHub 进度广播中心
type ProgressHub struct {
clients map[string]*websocket.Conn
clientsMux sync.RWMutex
broadcast chan ProgressMessage
}
var (
hub *ProgressHub
hubOnce sync.Once
)
// GetProgressHub 获取进度广播中心单例
func GetProgressHub() *ProgressHub {
hubOnce.Do(func() {
hub = &ProgressHub{
clients: make(map[string]*websocket.Conn),
broadcast: make(chan ProgressMessage, 10),
}
go hub.run()
})
return hub
}
// run 运行广播循环
func (h *ProgressHub) run() {
for msg := range h.broadcast {
h.clientsMux.RLock()
for clientID, conn := range h.clients {
err := conn.WriteJSON(msg)
if err != nil {
// 写入失败,移除客户端
conn.Close()
h.clientsMux.RUnlock()
h.removeClient(clientID)
h.clientsMux.RLock()
}
}
h.clientsMux.RUnlock()
}
}
// addClient 添加客户端
func (h *ProgressHub) addClient(clientID string, conn *websocket.Conn) {
h.clientsMux.Lock()
defer h.clientsMux.Unlock()
h.clients[clientID] = conn
}
// removeClient 移除客户端
func (h *ProgressHub) removeClient(clientID string) {
h.clientsMux.Lock()
defer h.clientsMux.Unlock()
delete(h.clients, clientID)
}
// SendProgress 发送进度消息
func (h *ProgressHub) SendProgress(msg ProgressMessage) {
select {
case h.broadcast <- msg:
case <-time.After(1 * time.Second):
// 超时,丢弃消息
}
}
// GitProgressWS WebSocket处理器
func GitProgressWS() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// 升级HTTP连接到WebSocket
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
http.Error(w, "Failed to upgrade to WebSocket", http.StatusInternalServerError)
return
}
defer conn.Close()
// 生成客户端ID
clientID := r.RemoteAddr + "-" + time.Now().Format("20060102150405")
// 添加到hub
hub := GetProgressHub()
hub.addClient(clientID, conn)
defer hub.removeClient(clientID)
// 发送欢迎消息
welcomeMsg := ProgressMessage{
Status: "connected",
Message: "WebSocket连接已建立",
Percent: 0,
}
if err := conn.WriteJSON(welcomeMsg); err != nil {
return
}
// 保持连接,读取客户端消息(主要用于心跳)
for {
_, _, err := conn.ReadMessage()
if err != nil {
// 连接断开
break
}
}
}
}
// SendProgressToClients 辅助函数:向所有客户端发送进度
func SendProgressToClients(status, message string, percent int) {
hub := GetProgressHub()
hub.SendProgress(ProgressMessage{
Status: status,
Message: message,
Percent: percent,
})
}
// SendProgressJSON 辅助函数:发送JSON格式的进度消息
func SendProgressJSON(w http.ResponseWriter, status, message string, percent int) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(ProgressMessage{
Status: status,
Message: message,
Percent: percent,
})
}