Skip to main content
Glama
emicklei

melrōse musical expression player

by emicklei
statements.go3.93 kB
package server import ( "bytes" "encoding/json" "fmt" "io" "net/http" "strconv" "strings" "github.com/emicklei/melrose/core" "github.com/emicklei/melrose/notify" ) func (l *LanguageServer) statementHandler(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { notify.Console.Warnf("HTTP method not allowed:%s", r.Method) w.WriteHeader(http.StatusMethodNotAllowed) return } query := r.URL.Query() file := query.Get("file") debug := query.Get("debug") == "true" || notify.IsDebug() if debug { notify.Debugf("service.http: %s", r.URL.String()) } // get line line := 1 lineString := query.Get("line") if len(lineString) > 0 { if i, err := strconv.Atoi(lineString); err == nil { line = i } } // get expression source data, err := io.ReadAll(r.Body) if err != nil { w.WriteHeader(http.StatusBadRequest) return } source, line := removeTrailingWhitespace(string(data), line) if debug { notify.Debugf("http.request.body %s", source) } defer r.Body.Close() var evalResult any action := query.Get("action") switch action { case "kill": evalResult = l.service.CommandKill() case "inspect": if ret, err := l.service.CommandInspect(file, line, source); err != nil { evalResult = err } else { evalResult = ret } case "play": if ret, err := l.service.CommandPlay(file, line, source); err != nil { evalResult = err } else { evalResult = ret.ExpressionResult } case "stop": if ret, err := l.service.CommandStop(file, line, source); err != nil { evalResult = err } else { evalResult = ret } case "eval": if ret, err := l.service.CommandEvaluate(file, line, source); err != nil { evalResult = err } else { evalResult = ret } default: evalResult = fmt.Errorf("unknown command:%s", query.Get("action")) } if _, ok := evalResult.(error); ok { // evaluation failed. w.WriteHeader(http.StatusBadRequest) } response := resultFrom(file, line, evalResult) w.Header().Set("content-type", "application/json") w.Header().Set("access-control-allow-origin", "*") w.Header().Set("Access-Control-Allow-Methods", "POST") w.Header().Set("Access-Control-Allow-Headers", "Content-Type") enc := json.NewEncoder(w) enc.SetIndent("", "\t") err = enc.Encode(response) if err != nil { notify.NewErrorf("error:%v\n", err) return } if response.IsError { notify.Print(notify.NewError(response.Object.(error))) } else { core.PrintValue(l.context, response.Object) } if debug { // doit again buf := bytes.Buffer{} enc := json.NewEncoder(&buf) enc.SetIndent("", "\t") err = enc.Encode(response) notify.Debugf("http.response: %s error=%v", buf.String(), err) } } type evaluationResult struct { Type string `json:"type"` IsError bool `json:"is-error"` IsStoppeable bool `json:"stoppable"` Message string `json:"message"` Filename string `json:"file"` Line int `json:"line"` Column int `json:"column"` Object any `json:"object"` } func resultFrom(filename string, line int, val any) evaluationResult { t := fmt.Sprintf("%T", val) _, isStoppable := val.(core.Stoppable) if err, ok := val.(error); ok { return evaluationResult{ Type: t, IsError: true, IsStoppeable: isStoppable, Filename: filename, Message: err.Error(), Line: line, Object: val, } } // no error var msg string if stor, ok := val.(core.Storable); ok { msg = stor.Storex() } else { msg = fmt.Sprintf("%v", val) } // no Object if ok return evaluationResult{ Type: t, IsError: false, IsStoppeable: isStoppable, Filename: filename, Line: line, Message: msg} } func removeTrailingWhitespace(source string, lineEnd int) (string, int) { for strings.HasSuffix(source, "\n") { source = strings.TrimSuffix(source, "\n") lineEnd -= 1 } return source, lineEnd }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/emicklei/melrose'

If you have feedback or need assistance with the MCP directory API, please join our Discord server