diff --git a/pkg/server/handlers.go b/pkg/server/handlers.go index 13b855a..3a33a8f 100644 --- a/pkg/server/handlers.go +++ b/pkg/server/handlers.go @@ -6,6 +6,7 @@ import ( "llamactl/pkg/config" "llamactl/pkg/instance" "llamactl/pkg/manager" + "llamactl/pkg/validation" "log" "net/http" "time" @@ -56,6 +57,21 @@ func NewHandler(im manager.InstanceManager, cfg config.AppConfig) *Handler { } } +func (h *Handler) getInstance(r *http.Request) (*instance.Instance, error) { + name := r.URL.Query().Get("name") + validatedName, err := validation.ValidateInstanceName(name) + if err != nil { + return nil, fmt.Errorf("invalid instance name: %w", err) + } + + inst, err := h.InstanceManager.GetInstance(validatedName) + if err != nil { + return nil, fmt.Errorf("failed to get instance by name: %w", err) + } + + return inst, nil +} + func (h *Handler) ensureInstanceRunning(inst *instance.Instance) error { options := inst.GetOptions() allowOnDemand := options != nil && options.OnDemandStart != nil && *options.OnDemandStart diff --git a/pkg/server/handlers_backends.go b/pkg/server/handlers_backends.go index 80d6bb1..45eecd9 100644 --- a/pkg/server/handlers_backends.go +++ b/pkg/server/handlers_backends.go @@ -5,12 +5,9 @@ import ( "fmt" "llamactl/pkg/backends" "llamactl/pkg/instance" - "llamactl/pkg/validation" "net/http" "os/exec" "strings" - - "github.com/go-chi/chi/v5" ) // ParseCommandRequest represents the request body for command parsing @@ -21,18 +18,7 @@ type ParseCommandRequest struct { func (h *Handler) LlamaCppProxy(onDemandStart bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // Get the instance name from the URL parameter - name := chi.URLParam(r, "name") - - // Validate instance name at the entry point - validatedName, err := validation.ValidateInstanceName(name) - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_instance_name", err.Error()) - return - } - - // Route to the appropriate inst based on instance name - inst, err := h.InstanceManager.GetInstance(validatedName) + inst, err := h.getInstance(r) if err != nil { writeError(w, http.StatusBadRequest, "invalid_instance", err.Error()) return @@ -65,7 +51,7 @@ func (h *Handler) LlamaCppProxy(onDemandStart bool) http.HandlerFunc { if !inst.IsRemote() { // Strip the "/llama-cpp/" prefix from the request URL - prefix := fmt.Sprintf("/llama-cpp/%s", validatedName) + prefix := fmt.Sprintf("/llama-cpp/%s", inst.Name) r.URL.Path = strings.TrimPrefix(r.URL.Path, prefix) } diff --git a/pkg/server/handlers_instances.go b/pkg/server/handlers_instances.go index 61a7ef6..05191b1 100644 --- a/pkg/server/handlers_instances.go +++ b/pkg/server/handlers_instances.go @@ -9,8 +9,6 @@ import ( "net/http" "strconv" "strings" - - "github.com/go-chi/chi/v5" ) // ListInstances godoc @@ -49,8 +47,7 @@ func (h *Handler) ListInstances() http.HandlerFunc { // @Router /instances/{name} [post] func (h *Handler) CreateInstance() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - name := chi.URLParam(r, "name") - + name := r.URL.Query().Get("name") validatedName, err := validation.ValidateInstanceName(name) if err != nil { writeError(w, http.StatusBadRequest, "invalid_instance_name", err.Error()) @@ -86,8 +83,7 @@ func (h *Handler) CreateInstance() http.HandlerFunc { // @Router /instances/{name} [get] func (h *Handler) GetInstance() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - name := chi.URLParam(r, "name") - + name := r.URL.Query().Get("name") validatedName, err := validation.ValidateInstanceName(name) if err != nil { writeError(w, http.StatusBadRequest, "invalid_instance_name", err.Error()) @@ -119,8 +115,7 @@ func (h *Handler) GetInstance() http.HandlerFunc { // @Router /instances/{name} [put] func (h *Handler) UpdateInstance() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - name := chi.URLParam(r, "name") - + name := r.URL.Query().Get("name") validatedName, err := validation.ValidateInstanceName(name) if err != nil { writeError(w, http.StatusBadRequest, "invalid_instance_name", err.Error()) @@ -156,8 +151,7 @@ func (h *Handler) UpdateInstance() http.HandlerFunc { // @Router /instances/{name}/start [post] func (h *Handler) StartInstance() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - name := chi.URLParam(r, "name") - + name := r.URL.Query().Get("name") validatedName, err := validation.ValidateInstanceName(name) if err != nil { writeError(w, http.StatusBadRequest, "invalid_instance_name", err.Error()) @@ -193,8 +187,7 @@ func (h *Handler) StartInstance() http.HandlerFunc { // @Router /instances/{name}/stop [post] func (h *Handler) StopInstance() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - name := chi.URLParam(r, "name") - + name := r.URL.Query().Get("name") validatedName, err := validation.ValidateInstanceName(name) if err != nil { writeError(w, http.StatusBadRequest, "invalid_instance_name", err.Error()) @@ -224,8 +217,7 @@ func (h *Handler) StopInstance() http.HandlerFunc { // @Router /instances/{name}/restart [post] func (h *Handler) RestartInstance() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - name := chi.URLParam(r, "name") - + name := r.URL.Query().Get("name") validatedName, err := validation.ValidateInstanceName(name) if err != nil { writeError(w, http.StatusBadRequest, "invalid_instance_name", err.Error()) @@ -254,8 +246,7 @@ func (h *Handler) RestartInstance() http.HandlerFunc { // @Router /instances/{name} [delete] func (h *Handler) DeleteInstance() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - name := chi.URLParam(r, "name") - + name := r.URL.Query().Get("name") validatedName, err := validation.ValidateInstanceName(name) if err != nil { writeError(w, http.StatusBadRequest, "invalid_instance_name", err.Error()) @@ -285,8 +276,7 @@ func (h *Handler) DeleteInstance() http.HandlerFunc { // @Router /instances/{name}/logs [get] func (h *Handler) GetInstanceLogs() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - name := chi.URLParam(r, "name") - + name := r.URL.Query().Get("name") validatedName, err := validation.ValidateInstanceName(name) if err != nil { writeError(w, http.StatusBadRequest, "invalid_instance_name", err.Error()) @@ -316,7 +306,7 @@ func (h *Handler) GetInstanceLogs() http.HandlerFunc { } // ProxyToInstance godoc -// @Summary Proxy requests to a specific instance +// @Summary Proxy requests to a specific instance, does not autostart instance if stopped // @Description Forwards HTTP requests to the llama-server instance running on a specific port // @Tags instances // @Security ApiKeyAuth @@ -329,17 +319,9 @@ func (h *Handler) GetInstanceLogs() http.HandlerFunc { // @Router /instances/{name}/proxy [post] func (h *Handler) ProxyToInstance() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - name := chi.URLParam(r, "name") - - validatedName, err := validation.ValidateInstanceName(name) + inst, err := h.getInstance(r) if err != nil { - writeError(w, http.StatusBadRequest, "invalid_instance_name", err.Error()) - return - } - - inst, err := h.InstanceManager.GetInstance(validatedName) - if err != nil { - writeError(w, http.StatusInternalServerError, "instance_failed", "Failed to get instance: "+err.Error()) + writeError(w, http.StatusBadRequest, "invalid_instance", err.Error()) return } @@ -358,7 +340,7 @@ func (h *Handler) ProxyToInstance() http.HandlerFunc { // Check if this is a remote instance if !inst.IsRemote() { // Strip the "/api/v1/instances//proxy" prefix from the request URL - prefix := fmt.Sprintf("/api/v1/instances/%s/proxy", validatedName) + prefix := fmt.Sprintf("/api/v1/instances/%s/proxy", inst.Name) r.URL.Path = strings.TrimPrefix(r.URL.Path, prefix) }