Files
Memoh/cmd/mcp/main.go
T

90 lines
2.0 KiB
Go

package main
import (
"context"
"io/fs"
"log/slog"
"net"
"os"
"os/signal"
"path/filepath"
"syscall"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"github.com/memohai/memoh/internal/logger"
pb "github.com/memohai/memoh/internal/mcp/mcpcontainer"
)
const (
defaultListenAddr = ":9090"
templateDir = "/opt/mcp-template"
)
// initDataDir ensures /data exists and seeds template files on first boot.
func initDataDir() {
if err := os.MkdirAll(defaultWorkDir, 0o750); err != nil {
logger.Warn("failed to create data dir", slog.Any("error", err))
return
}
entries, err := os.ReadDir(templateDir)
if err != nil {
if !os.IsNotExist(err) {
logger.Warn("failed to read template dir", slog.String("dir", templateDir), slog.Any("error", err))
}
return
}
for _, e := range entries {
if e.IsDir() {
continue
}
dst := filepath.Join(defaultWorkDir, e.Name())
if _, err := os.Stat(dst); err == nil {
continue
}
data, err := os.ReadFile(filepath.Join(templateDir, e.Name()))
if err != nil {
continue
}
if err := os.WriteFile(dst, data, fs.FileMode(0o644)); err != nil {
logger.Warn("failed to seed template", slog.String("file", e.Name()), slog.Any("error", err))
}
}
}
func main() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
initDataDir()
addr := os.Getenv("MCP_LISTEN_ADDR")
if addr == "" {
addr = defaultListenAddr
}
lis, err := (&net.ListenConfig{}).Listen(ctx, "tcp", addr)
if err != nil {
logger.Error("failed to listen", slog.String("addr", addr), slog.Any("error", err))
return
}
srv := grpc.NewServer()
pb.RegisterContainerServiceServer(srv, &containerServer{})
reflection.Register(srv)
go func() {
<-ctx.Done()
logger.FromContext(ctx).Info("shutting down gRPC server")
srv.GracefulStop()
}()
logger.Info("mcp gRPC server listening", slog.String("addr", addr))
if err := srv.Serve(lis); err != nil {
logger.Error("gRPC server failed", slog.Any("error", err))
return
}
}