feat(ctx): basic ctx setup

This commit is contained in:
Kristian Borgwarth 2026-03-30 00:03:48 +02:00
parent 2181e82f62
commit 53b779b801
7 changed files with 105 additions and 89 deletions

View file

@ -3,18 +3,19 @@ package main
import ( import (
"log/slog" "log/slog"
"os" "os"
"github.com/KristianJBorgwarth/dendrite.daemon/core/rpc"
"github.com/KristianJBorgwarth/dendrite.daemon/core/handlers" "github.com/KristianJBorgwarth/dendrite.daemon/core/handlers"
"github.com/KristianJBorgwarth/dendrite.daemon/core/server"
_ "modernc.org/sqlite" _ "modernc.org/sqlite"
) )
func main() { func main() {
server := rpc.NewServer() server := server.NewServer()
server.Register("initialize", handlers.InitializeHandler{}) server.Register("initialize", handlers.InitializeHandler{})
if err := server.Serve(os.Stdin, os.Stdout); err != nil { if err := server.Run(os.Stdin, os.Stdout); err != nil {
slog.Error("server error", "error", err) slog.Error("server error", "error", err)
} }
} }

View file

@ -46,12 +46,12 @@ func (h CreateNoteHandler) Handle(ctx context.Context, params []byte) (*rpc.Resp
return nil, h.ReturnError(err) return nil, h.ReturnError(err)
} }
err = h.tagRepo.Upsert(tags) err = h.tagRepo.Upsert(ctx, tags)
if err != nil { if err != nil {
return nil, h.ReturnError(err) return nil, h.ReturnError(err)
} }
err = h.noteRepo.Upsert(cmd.Title, cmd.Path, frontmatter.Slugify(cmd.Title)) err = h.noteRepo.Upsert(ctx, cmd.Title, cmd.Path, frontmatter.Slugify(cmd.Title))
if err != nil { if err != nil {
return nil, h.ReturnError(err) return nil, h.ReturnError(err)
} }

12
core/handlers/handler.go Normal file
View file

@ -0,0 +1,12 @@
package handlers
import (
"context"
"encoding/json"
"github.com/KristianJBorgwarth/dendrite.daemon/core/rpc"
)
type Handler interface {
Handle(ctx context.Context, raw json.RawMessage) (any, *rpc.Error)
}

View file

@ -1,7 +1,9 @@
package handlers package handlers
import ( import (
"context"
"encoding/json" "encoding/json"
"github.com/KristianJBorgwarth/dendrite.daemon/core/rpc" "github.com/KristianJBorgwarth/dendrite.daemon/core/rpc"
"github.com/KristianJBorgwarth/dendrite.daemon/persistence" "github.com/KristianJBorgwarth/dendrite.daemon/persistence"
) )
@ -12,7 +14,7 @@ type initializeCommand struct {
type InitializeHandler struct{} type InitializeHandler struct{}
func (h InitializeHandler) Handle(raw json.RawMessage) (any, *rpc.Error) { func (h InitializeHandler) Handle(ctx context.Context, raw json.RawMessage) (any, *rpc.Error) {
var params initializeCommand var params initializeCommand
if err := json.Unmarshal(raw, &params); err != nil { if err := json.Unmarshal(raw, &params); err != nil {

View file

@ -1,83 +0,0 @@
package rpc
import (
"bufio"
"encoding/json"
"fmt"
"io"
)
type Handler interface {
Handle(json.RawMessage) (any, *Error)
}
type Server struct {
handlers map[string]Handler
}
func NewServer() *Server {
return &Server{
handlers: make(map[string]Handler),
}
}
func (s *Server) Register(method string, handler Handler) {
s.handlers[method] = handler
}
func (s *Server) Serve(r io.Reader, w io.Writer) error {
scanner := bufio.NewScanner(r)
for scanner.Scan() {
line := scanner.Bytes()
var req Request
if err := json.Unmarshal(line, &req); err != nil {
s.write(w, Response{
Jsonrpc: "2.0",
Error: &Error{Code: -32700, Message: "parse error"},
})
continue
}
s.handle(w, req)
}
return scanner.Err()
}
func (s *Server) handle(w io.Writer, req Request) {
handler, ok := s.handlers[req.Method]
if !ok {
s.respond(w, req.ID, nil, &Error{
Code: -32601,
Message: "method not found",
})
return
}
result, err := handler.Handle(req.Params)
if req.ID == nil {
return
}
s.respond(w, req.ID, result, err)
}
func (s *Server) respond(w io.Writer, id *int, result any, err *Error) {
resp := Response{
Jsonrpc: "2.0",
ID: id,
Result: result,
Error: err,
}
s.write(w, resp)
}
func (s *Server) write(w io.Writer, resp Response) {
data, _ := json.Marshal(resp)
fmt.Fprintln(w, string(data))
}

84
core/server/server.go Normal file
View file

@ -0,0 +1,84 @@
// Package server contains the server running the JSON-RPC 2.0 Protocol.
package server
import (
"bufio"
"context"
"encoding/json"
"fmt"
"io"
"github.com/KristianJBorgwarth/dendrite.daemon/core/handlers"
"github.com/KristianJBorgwarth/dendrite.daemon/core/rpc"
)
type Server struct {
handlers map[string]handlers.Handler
}
func NewServer() *Server {
return &Server{
handlers: make(map[string]handlers.Handler),
}
}
func (s *Server) Register(method string, handler handlers.Handler) {
s.handlers[method] = handler
}
func (s *Server) Run(r io.Reader, w io.Writer) error {
scanner := bufio.NewScanner(r)
for scanner.Scan() {
line := scanner.Bytes()
var req rpc.Request
if err := json.Unmarshal(line, &req); err != nil {
s.write(w, rpc.Response{
Jsonrpc: "2.0",
Error: &rpc.Error{Code: -32700, Message: "parse error"},
})
continue
}
s.handle(w, req)
}
return scanner.Err()
}
func (s *Server) handle(w io.Writer, req rpc.Request) {
ctx := context.Background()
handler, ok := s.handlers[req.Method]
if !ok {
s.respond(w, req.ID, nil, &rpc.Error{
Code: -32601,
Message: "method not found",
})
return
}
result, err := handler.Handle(ctx, req.Params)
if req.ID == nil {
return
}
s.respond(w, req.ID, result, err)
}
func (s *Server) respond(w io.Writer, id *int, result any, err *rpc.Error) {
resp := rpc.Response{
Jsonrpc: "2.0",
ID: id,
Result: result,
Error: err,
}
s.write(w, resp)
}
func (s *Server) write(w io.Writer, resp rpc.Response) {
data, _ := json.Marshal(resp)
fmt.Fprintln(w, string(data))
}