663 lines
19 KiB
Go
663 lines
19 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/godbus/dbus/v5"
|
|
)
|
|
|
|
const (
|
|
dbusService = "org.ollie.SessionManager"
|
|
dbusPath = "/org/ollie/SessionManager"
|
|
dbusIface = "org.ollie.SessionManager"
|
|
)
|
|
|
|
func dbusConn() (*dbus.Conn, error) {
|
|
return dbus.ConnectSessionBus()
|
|
}
|
|
|
|
func dbusCall(method string, args ...interface{}) (*dbus.Call, error) {
|
|
conn, err := dbusConn()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("dbus connect: %w", err)
|
|
}
|
|
defer conn.Close()
|
|
|
|
obj := conn.Object(dbusService, dbusPath)
|
|
call := obj.Call(dbusIface+"."+method, 0, args...)
|
|
if call.Err != nil {
|
|
return nil, call.Err
|
|
}
|
|
return call, nil
|
|
}
|
|
|
|
// dbusHandler routes HTTP requests to D-Bus method calls.
|
|
//
|
|
// API:
|
|
//
|
|
// GET /sessions - ListSessions
|
|
// POST /sessions - CreateSession
|
|
// DELETE /sessions/{id} - KillSession
|
|
// PATCH /sessions/{id} - RenameSession
|
|
//
|
|
// POST /sessions/{id}/submit - Submit prompt
|
|
// POST /sessions/{id}/interrupt - Interrupt
|
|
//
|
|
// GET /sessions/{id}/state - GetState
|
|
// GET /sessions/{id}/chat - GetChat (query: offset)
|
|
// GET /sessions/{id}/usage - GetUsage
|
|
// GET /sessions/{id}/cost - GetCost
|
|
// GET /sessions/{id}/config - GetConfig
|
|
// POST /sessions/{id}/config - SetConfig
|
|
// GET /sessions/{id}/context - GetContext
|
|
//
|
|
// GET /backends - ListBackends
|
|
// GET /sessions/{id}/models - ListModels
|
|
// GET /agents - ListAgents
|
|
//
|
|
// GET /sessions/{id}/peers - PeerList
|
|
// POST /sessions/{id}/peers - PeerAdd
|
|
// DELETE /sessions/{id}/peers/{peer_id} - PeerRemove
|
|
// POST /sessions/{id}/peers/{peer_id}/submit - PeerSubmit
|
|
func dbusHandler(w http.ResponseWriter, r *http.Request) {
|
|
p := strings.TrimPrefix(r.URL.Path, "/")
|
|
p = strings.TrimSuffix(p, "/")
|
|
|
|
parts := strings.Split(p, "/")
|
|
|
|
switch {
|
|
// GET/POST /sessions
|
|
case len(parts) == 1 && parts[0] == "sessions":
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
dbusListSessions(w)
|
|
case http.MethodPost:
|
|
dbusCreateSession(w, r)
|
|
default:
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "method not allowed"})
|
|
}
|
|
|
|
// /sessions/{id}
|
|
case len(parts) == 2 && parts[0] == "sessions":
|
|
sessionID := parts[1]
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
dbusGetSession(w, sessionID)
|
|
case http.MethodDelete:
|
|
dbusKillSession(w, sessionID)
|
|
case http.MethodPatch:
|
|
dbusRenameSession(w, r, sessionID)
|
|
default:
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "method not allowed"})
|
|
}
|
|
|
|
// /sessions/{id}/{action}
|
|
case len(parts) == 3 && parts[0] == "sessions":
|
|
sessionID := parts[1]
|
|
action := parts[2]
|
|
switch action {
|
|
case "submit":
|
|
if r.Method != http.MethodPost {
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "POST only"})
|
|
return
|
|
}
|
|
dbusSubmit(w, r, sessionID)
|
|
case "interrupt":
|
|
if r.Method != http.MethodPost {
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "POST only"})
|
|
return
|
|
}
|
|
dbusInterrupt(w, sessionID)
|
|
case "state":
|
|
if r.Method != http.MethodGet {
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "GET only"})
|
|
return
|
|
}
|
|
dbusGetState(w, sessionID)
|
|
case "chat":
|
|
if r.Method != http.MethodGet {
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "GET only"})
|
|
return
|
|
}
|
|
dbusGetChat(w, r, sessionID)
|
|
case "usage":
|
|
if r.Method != http.MethodGet {
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "GET only"})
|
|
return
|
|
}
|
|
dbusGetUsage(w, sessionID)
|
|
case "cost":
|
|
if r.Method != http.MethodGet {
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "GET only"})
|
|
return
|
|
}
|
|
dbusGetCost(w, sessionID)
|
|
case "config":
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
dbusGetConfig(w, sessionID)
|
|
case http.MethodPost:
|
|
dbusSetConfig(w, r, sessionID)
|
|
default:
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "GET or POST"})
|
|
}
|
|
case "context":
|
|
if r.Method != http.MethodGet {
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "GET only"})
|
|
return
|
|
}
|
|
dbusGetContext(w, sessionID)
|
|
case "models":
|
|
if r.Method != http.MethodGet {
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "GET only"})
|
|
return
|
|
}
|
|
dbusListModels(w, sessionID)
|
|
case "peers":
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
dbusPeerList(w, sessionID)
|
|
case http.MethodPost:
|
|
dbusPeerAdd(w, r, sessionID)
|
|
default:
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "GET or POST"})
|
|
}
|
|
default:
|
|
writeJSON(w, http.StatusNotFound, map[string]string{"error": "not found"})
|
|
}
|
|
|
|
// /sessions/{id}/peers/{peer_id}
|
|
case len(parts) == 4 && parts[0] == "sessions" && parts[2] == "peers":
|
|
sessionID := parts[1]
|
|
peerID := parts[3]
|
|
switch r.Method {
|
|
case http.MethodDelete:
|
|
dbusPeerRemove(w, sessionID, peerID)
|
|
default:
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "DELETE only"})
|
|
}
|
|
|
|
// /sessions/{id}/peers/{peer_id}/submit
|
|
case len(parts) == 5 && parts[0] == "sessions" && parts[2] == "peers" && parts[4] == "submit":
|
|
sessionID := parts[1]
|
|
peerID := parts[3]
|
|
if r.Method != http.MethodPost {
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "POST only"})
|
|
return
|
|
}
|
|
dbusPeerSubmit(w, r, sessionID, peerID)
|
|
|
|
// GET /backends
|
|
case len(parts) == 1 && parts[0] == "backends":
|
|
if r.Method != http.MethodGet {
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "GET only"})
|
|
return
|
|
}
|
|
dbusListBackends(w)
|
|
|
|
// GET /agents
|
|
case len(parts) == 1 && parts[0] == "agents":
|
|
if r.Method != http.MethodGet {
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "GET only"})
|
|
return
|
|
}
|
|
dbusListAgents(w)
|
|
|
|
default:
|
|
writeJSON(w, http.StatusNotFound, map[string]string{"error": "not found"})
|
|
}
|
|
}
|
|
|
|
// --- Sessions ---
|
|
|
|
func dbusListSessions(w http.ResponseWriter) {
|
|
call, err := dbusCall("ListSessions")
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var sessions []string
|
|
if err := call.Store(&sessions); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
var result []map[string]string
|
|
for _, entry := range sessions {
|
|
parts := strings.SplitN(entry, "\t", 4)
|
|
if len(parts) >= 4 {
|
|
result = append(result, map[string]string{
|
|
"id": parts[0],
|
|
"state": parts[1],
|
|
"model": parts[2],
|
|
"agent": parts[3],
|
|
})
|
|
}
|
|
}
|
|
if result == nil {
|
|
result = []map[string]string{}
|
|
}
|
|
sort.Slice(result, func(i, j int) bool {
|
|
return result[i]["id"] < result[j]["id"]
|
|
})
|
|
writeJSON(w, http.StatusOK, result)
|
|
}
|
|
|
|
func dbusCreateSession(w http.ResponseWriter, r *http.Request) {
|
|
var req struct {
|
|
Name string `json:"name"`
|
|
CWD string `json:"cwd"`
|
|
Backend string `json:"backend"`
|
|
Model string `json:"model"`
|
|
Agent string `json:"agent"`
|
|
Remote string `json:"remote"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil && err != io.EOF {
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
call, err := dbusCall("CreateSession", req.CWD, req.Backend, req.Model, req.Agent, "", req.Remote)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var sessionID string
|
|
if err := call.Store(&sessionID); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
if sessionID == "" {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "session creation failed"})
|
|
return
|
|
}
|
|
|
|
// Rename if a name was provided
|
|
if req.Name != "" {
|
|
if call, err := dbusCall("RenameSession", sessionID, req.Name); err == nil {
|
|
var success bool
|
|
if call.Store(&success) == nil && success {
|
|
sessionID = req.Name
|
|
}
|
|
}
|
|
}
|
|
|
|
writeJSON(w, http.StatusCreated, map[string]string{"id": sessionID})
|
|
}
|
|
|
|
func dbusGetSession(w http.ResponseWriter, sessionID string) {
|
|
// Return config as the session detail view
|
|
dbusGetConfig(w, sessionID)
|
|
}
|
|
|
|
func dbusKillSession(w http.ResponseWriter, sessionID string) {
|
|
call, err := dbusCall("KillSession", sessionID)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var success bool
|
|
if err := call.Store(&success); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
if !success {
|
|
writeJSON(w, http.StatusNotFound, map[string]string{"error": "session not found"})
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
func dbusRenameSession(w http.ResponseWriter, r *http.Request, sessionID string) {
|
|
var req struct {
|
|
Name string `json:"name"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
call, err := dbusCall("RenameSession", sessionID, req.Name)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var success bool
|
|
if err := call.Store(&success); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
if !success {
|
|
writeJSON(w, http.StatusNotFound, map[string]string{"error": "rename failed"})
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
// --- Interaction ---
|
|
|
|
func dbusSubmit(w http.ResponseWriter, r *http.Request, sessionID string) {
|
|
var req struct {
|
|
Prompt string `json:"prompt"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
call, err := dbusCall("Submit", sessionID, req.Prompt)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var success bool
|
|
if err := call.Store(&success); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
if !success {
|
|
writeJSON(w, http.StatusNotFound, map[string]string{"error": "session not found"})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]bool{"submitted": true})
|
|
}
|
|
|
|
func dbusInterrupt(w http.ResponseWriter, sessionID string) {
|
|
call, err := dbusCall("Interrupt", sessionID)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var success bool
|
|
if err := call.Store(&success); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
if !success {
|
|
writeJSON(w, http.StatusNotFound, map[string]string{"error": "session not found"})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]bool{"interrupted": true})
|
|
}
|
|
|
|
// --- State queries ---
|
|
|
|
func dbusGetState(w http.ResponseWriter, sessionID string) {
|
|
call, err := dbusCall("GetState", sessionID)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var state string
|
|
if err := call.Store(&state); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]string{"state": state})
|
|
}
|
|
|
|
func dbusGetChat(w http.ResponseWriter, r *http.Request, sessionID string) {
|
|
offsetStr := r.URL.Query().Get("offset")
|
|
var offset int64
|
|
if offsetStr != "" {
|
|
offset, _ = strconv.ParseInt(offsetStr, 10, 64)
|
|
}
|
|
|
|
conn, err := dbusConn()
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
defer conn.Close()
|
|
|
|
obj := conn.Object(dbusService, dbusPath)
|
|
call := obj.Call(dbusIface+".GetChat", 0, sessionID, offset)
|
|
if call.Err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": call.Err.Error()})
|
|
return
|
|
}
|
|
|
|
var text string
|
|
var newOffset int64
|
|
if err := call.Store(&text, &newOffset); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
|
w.Header().Set("X-Chat-Offset", strconv.FormatInt(newOffset, 10))
|
|
w.Write([]byte(text))
|
|
}
|
|
|
|
func dbusGetUsage(w http.ResponseWriter, sessionID string) {
|
|
call, err := dbusCall("GetUsage", sessionID)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var usage string
|
|
if err := call.Store(&usage); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]string{"usage": usage})
|
|
}
|
|
|
|
func dbusGetCost(w http.ResponseWriter, sessionID string) {
|
|
call, err := dbusCall("GetCost", sessionID)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var cost string
|
|
if err := call.Store(&cost); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]string{"cost": cost})
|
|
}
|
|
|
|
// --- Config ---
|
|
|
|
func dbusGetConfig(w http.ResponseWriter, sessionID string) {
|
|
call, err := dbusCall("GetConfig", sessionID)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var config string
|
|
if err := call.Store(&config); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
// Parse key=value\n into JSON object
|
|
m := make(map[string]string)
|
|
for _, line := range strings.Split(strings.TrimRight(config, "\n"), "\n") {
|
|
if line == "" {
|
|
continue
|
|
}
|
|
k, v, _ := strings.Cut(line, "=")
|
|
m[k] = v
|
|
}
|
|
writeJSON(w, http.StatusOK, m)
|
|
}
|
|
|
|
func dbusSetConfig(w http.ResponseWriter, r *http.Request, sessionID string) {
|
|
var req struct {
|
|
Key string `json:"key"`
|
|
Value string `json:"value"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
call, err := dbusCall("SetConfig", sessionID, req.Key, req.Value)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var success bool
|
|
if err := call.Store(&success); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
if !success {
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "set config failed"})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]bool{"success": true})
|
|
}
|
|
|
|
// --- Context ---
|
|
|
|
func dbusGetContext(w http.ResponseWriter, sessionID string) {
|
|
call, err := dbusCall("GetContext", sessionID)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var context string
|
|
if err := call.Store(&context); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
// Already JSONL — return as-is with appropriate content type
|
|
w.Header().Set("Content-Type", "application/x-ndjson")
|
|
w.Write([]byte(context))
|
|
}
|
|
|
|
// --- Backends/Models/Agents ---
|
|
|
|
func dbusListBackends(w http.ResponseWriter) {
|
|
call, err := dbusCall("ListBackends")
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var backends []string
|
|
if err := call.Store(&backends); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, backends)
|
|
}
|
|
|
|
func dbusListModels(w http.ResponseWriter, sessionID string) {
|
|
call, err := dbusCall("ListModels", sessionID)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var models []string
|
|
if err := call.Store(&models); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, models)
|
|
}
|
|
|
|
func dbusListAgents(w http.ResponseWriter) {
|
|
call, err := dbusCall("ListAgents")
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var agents []string
|
|
if err := call.Store(&agents); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, agents)
|
|
}
|
|
|
|
// --- Peers ---
|
|
|
|
func dbusPeerList(w http.ResponseWriter, sessionID string) {
|
|
call, err := dbusCall("PeerList", sessionID)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var peers []string
|
|
if err := call.Store(&peers); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
if peers == nil {
|
|
peers = []string{}
|
|
}
|
|
writeJSON(w, http.StatusOK, peers)
|
|
}
|
|
|
|
func dbusPeerAdd(w http.ResponseWriter, r *http.Request, sessionID string) {
|
|
var req struct {
|
|
PeerID string `json:"peer_id"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
call, err := dbusCall("PeerAdd", sessionID, req.PeerID)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var success bool
|
|
if err := call.Store(&success); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
if !success {
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "peer add failed"})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusCreated, map[string]bool{"added": true})
|
|
}
|
|
|
|
func dbusPeerRemove(w http.ResponseWriter, sessionID, peerID string) {
|
|
call, err := dbusCall("PeerRemove", sessionID, peerID)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var success bool
|
|
if err := call.Store(&success); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
if !success {
|
|
writeJSON(w, http.StatusNotFound, map[string]string{"error": "peer not found"})
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
func dbusPeerSubmit(w http.ResponseWriter, r *http.Request, sessionID, peerID string) {
|
|
var req struct {
|
|
Prompt string `json:"prompt"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
call, err := dbusCall("PeerSubmit", sessionID, peerID, req.Prompt)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
var success bool
|
|
if err := call.Store(&success); err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
if !success {
|
|
writeJSON(w, http.StatusNotFound, map[string]string{"error": "peer submit failed"})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]bool{"submitted": true})
|
|
}
|