Start 启动扫描
(w http.ResponseWriter, r *http.Request)
| 92 | |
| 93 | // Start 启动扫描 |
| 94 | func (h *ScanHandler) Start(w http.ResponseWriter, r *http.Request) { |
| 95 | if r.Method != http.MethodPost { |
| 96 | http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) |
| 97 | return |
| 98 | } |
| 99 | |
| 100 | // 检查是否已在扫描 |
| 101 | if !atomic.CompareAndSwapInt32(&h.state, int32(ScanStateIdle), int32(ScanStateRunning)) { |
| 102 | writeJSON(w, http.StatusConflict, map[string]string{ |
| 103 | "error": "scan already running", |
| 104 | }) |
| 105 | return |
| 106 | } |
| 107 | |
| 108 | // 解析请求 |
| 109 | var req ScanRequest |
| 110 | if err := json.NewDecoder(r.Body).Decode(&req); err != nil { |
| 111 | atomic.StoreInt32(&h.state, int32(ScanStateIdle)) |
| 112 | writeJSON(w, http.StatusBadRequest, map[string]string{ |
| 113 | "error": "invalid request: " + err.Error(), |
| 114 | }) |
| 115 | return |
| 116 | } |
| 117 | |
| 118 | // 验证必填参数 |
| 119 | if req.Host == "" { |
| 120 | atomic.StoreInt32(&h.state, int32(ScanStateIdle)) |
| 121 | writeJSON(w, http.StatusBadRequest, map[string]string{ |
| 122 | "error": "host is required", |
| 123 | }) |
| 124 | return |
| 125 | } |
| 126 | |
| 127 | h.mu.Lock() |
| 128 | h.startTime = time.Now() |
| 129 | h.mu.Unlock() |
| 130 | |
| 131 | // 清空旧结果 |
| 132 | h.results.Clear() |
| 133 | |
| 134 | // 广播扫描开始 |
| 135 | h.hub.Broadcast(ws.MsgScanStarted, map[string]interface{}{ |
| 136 | "host": req.Host, |
| 137 | "start_time": h.startTime, |
| 138 | }) |
| 139 | |
| 140 | // 异步执行扫描 |
| 141 | go h.runScan(req) |
| 142 | |
| 143 | writeJSON(w, http.StatusOK, map[string]interface{}{ |
| 144 | "status": "started", |
| 145 | "start_time": h.startTime, |
| 146 | }) |
| 147 | } |
| 148 | |
| 149 | // runScan 执行扫描 |
| 150 | func (h *ScanHandler) runScan(req ScanRequest) { |