Generated Go code from proto. Server implements CoreService with FileRead/FileWrite/FileList/FileDelete/StoreGet/StoreSet — every request checked against the calling module's manifest permissions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
131 lines
4 KiB
Go
131 lines
4 KiB
Go
package coredeno
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
pb "forge.lthn.ai/core/go/pkg/coredeno/proto"
|
|
"forge.lthn.ai/core/go/pkg/io"
|
|
"forge.lthn.ai/core/go/pkg/manifest"
|
|
"forge.lthn.ai/core/go/pkg/store"
|
|
)
|
|
|
|
// Server implements the CoreService gRPC interface with permission gating.
|
|
// Every I/O request is checked against the calling module's declared permissions.
|
|
type Server struct {
|
|
pb.UnimplementedCoreServiceServer
|
|
medium io.Medium
|
|
store *store.Store
|
|
manifests map[string]*manifest.Manifest
|
|
}
|
|
|
|
// NewServer creates a CoreService server backed by the given Medium and Store.
|
|
func NewServer(medium io.Medium, st *store.Store) *Server {
|
|
return &Server{
|
|
medium: medium,
|
|
store: st,
|
|
manifests: make(map[string]*manifest.Manifest),
|
|
}
|
|
}
|
|
|
|
// RegisterModule adds a module's manifest to the permission registry.
|
|
func (s *Server) RegisterModule(m *manifest.Manifest) {
|
|
s.manifests[m.Code] = m
|
|
}
|
|
|
|
// getManifest looks up a module and returns an error if unknown.
|
|
func (s *Server) getManifest(code string) (*manifest.Manifest, error) {
|
|
m, ok := s.manifests[code]
|
|
if !ok {
|
|
return nil, fmt.Errorf("unknown module: %s", code)
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
// FileRead implements CoreService.FileRead with permission gating.
|
|
func (s *Server) FileRead(_ context.Context, req *pb.FileReadRequest) (*pb.FileReadResponse, error) {
|
|
m, err := s.getManifest(req.ModuleCode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !CheckPath(req.Path, m.Permissions.Read) {
|
|
return nil, fmt.Errorf("permission denied: %s cannot read %s", req.ModuleCode, req.Path)
|
|
}
|
|
content, err := s.medium.Read(req.Path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &pb.FileReadResponse{Content: content}, nil
|
|
}
|
|
|
|
// FileWrite implements CoreService.FileWrite with permission gating.
|
|
func (s *Server) FileWrite(_ context.Context, req *pb.FileWriteRequest) (*pb.FileWriteResponse, error) {
|
|
m, err := s.getManifest(req.ModuleCode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !CheckPath(req.Path, m.Permissions.Write) {
|
|
return nil, fmt.Errorf("permission denied: %s cannot write %s", req.ModuleCode, req.Path)
|
|
}
|
|
if err := s.medium.Write(req.Path, req.Content); err != nil {
|
|
return nil, err
|
|
}
|
|
return &pb.FileWriteResponse{Ok: true}, nil
|
|
}
|
|
|
|
// FileList implements CoreService.FileList with permission gating.
|
|
func (s *Server) FileList(_ context.Context, req *pb.FileListRequest) (*pb.FileListResponse, error) {
|
|
m, err := s.getManifest(req.ModuleCode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !CheckPath(req.Path, m.Permissions.Read) {
|
|
return nil, fmt.Errorf("permission denied: %s cannot list %s", req.ModuleCode, req.Path)
|
|
}
|
|
entries, err := s.medium.List(req.Path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var pbEntries []*pb.FileEntry
|
|
for _, e := range entries {
|
|
info, _ := e.Info()
|
|
pbEntries = append(pbEntries, &pb.FileEntry{
|
|
Name: e.Name(),
|
|
IsDir: e.IsDir(),
|
|
Size: info.Size(),
|
|
})
|
|
}
|
|
return &pb.FileListResponse{Entries: pbEntries}, nil
|
|
}
|
|
|
|
// FileDelete implements CoreService.FileDelete with permission gating.
|
|
func (s *Server) FileDelete(_ context.Context, req *pb.FileDeleteRequest) (*pb.FileDeleteResponse, error) {
|
|
m, err := s.getManifest(req.ModuleCode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !CheckPath(req.Path, m.Permissions.Write) {
|
|
return nil, fmt.Errorf("permission denied: %s cannot delete %s", req.ModuleCode, req.Path)
|
|
}
|
|
if err := s.medium.Delete(req.Path); err != nil {
|
|
return nil, err
|
|
}
|
|
return &pb.FileDeleteResponse{Ok: true}, nil
|
|
}
|
|
|
|
// StoreGet implements CoreService.StoreGet.
|
|
func (s *Server) StoreGet(_ context.Context, req *pb.StoreGetRequest) (*pb.StoreGetResponse, error) {
|
|
val, err := s.store.Get(req.Group, req.Key)
|
|
if err != nil {
|
|
return &pb.StoreGetResponse{Found: false}, nil
|
|
}
|
|
return &pb.StoreGetResponse{Value: val, Found: true}, nil
|
|
}
|
|
|
|
// StoreSet implements CoreService.StoreSet.
|
|
func (s *Server) StoreSet(_ context.Context, req *pb.StoreSetRequest) (*pb.StoreSetResponse, error) {
|
|
if err := s.store.Set(req.Group, req.Key, req.Value); err != nil {
|
|
return nil, err
|
|
}
|
|
return &pb.StoreSetResponse{Ok: true}, nil
|
|
}
|