Files
evening_detective/cmd/evening_detective/main.go
T
2026-05-17 11:56:46 +07:00

196 lines
5.0 KiB
Go

package main
import (
"context"
"embed"
"evening_detective/internal/app"
"evening_detective/internal/config"
"evening_detective/internal/modules/cleaner"
"evening_detective/internal/modules/formatter"
"evening_detective/internal/modules/password"
"evening_detective/internal/services"
"evening_detective/internal/services/db"
"evening_detective/internal/services/link"
"evening_detective/internal/services/pdf"
"evening_detective/internal/services/story_service"
"evening_detective/internal/services/story_storage"
proto "evening_detective/proto"
"io/fs"
"log"
"net"
"net/http"
"time"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/metadata"
)
//go:embed static/user/*
var userFS embed.FS
//go:embed static/admin/*
var adminFS embed.FS
func main() {
grpcGatewayHost := config.GetGrpcGatewayHost()
userClientHost := config.GetUserClientHost()
adminClientHost := config.GetAdminClientHost()
fileHost := config.GetFileHost()
// Create a gRPC server object
s := grpc.NewServer()
// Attach the Greeter service to the server
dbFilepath := config.GetDBFilepath()
dbService, err := db.NewDBService(dbFilepath)
if err != nil {
log.Fatalln(err)
}
cleaner := cleaner.NewCleaner()
formatter := formatter.NewFormatter()
storyFilepath := config.GetStoryFilepath()
storyStorage := story_storage.NewFileStoryStorage(storyFilepath)
storyService, err := story_service.NewStoryService(
cleaner,
formatter,
storyStorage,
link.NewLinkService(fileHost),
)
if err != nil {
log.Fatalln(err)
}
linkService := link.NewLinkService(userClientHost)
passwordGenerator := password.NewPasswordGenerator()
pdfGenerator := pdf.NewPDFGenerator()
proto.RegisterEveningDetectiveServer(
s,
app.NewServer(
services.NewServices(
dbService,
storyService,
linkService,
passwordGenerator,
pdfGenerator,
),
),
)
// Server gRPC
lis, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalln("Failed to listen:", err)
}
go func() {
log.Fatalln(s.Serve(lis))
}()
// Client gRPC
// Create a client connection to the gRPC server we just started
// This is where the gRPC-Gateway proxies the requests
conn, err := grpc.NewClient(
"0.0.0.0:8080",
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
log.Fatalln("Failed to dial server:", err)
}
gwmux := runtime.NewServeMux(
runtime.WithMetadata(func(ctx context.Context, request *http.Request) metadata.MD {
teamId := request.Header.Get("X-Id")
return metadata.Pairs("team-id", teamId)
}),
runtime.WithMetadata(func(ctx context.Context, request *http.Request) metadata.MD {
password := request.Header.Get("X-Password")
return metadata.Pairs("password", password)
}),
)
// Register Greeter
err = proto.RegisterEveningDetectiveHandler(context.Background(), gwmux, conn)
if err != nil {
log.Fatalln("Failed to register gateway:", err)
}
// Server gRPC-Gateway
gwServer := &http.Server{
Addr: config.GrpcGatewayPort,
Handler: cors(gwmux),
}
log.Printf("Serving %s for gRPC-Gateway\n", grpcGatewayHost)
go func() {
log.Fatalln(gwServer.ListenAndServe())
}()
muxUser := http.NewServeMux()
subUserFS, err := fs.Sub(userFS, "static/user")
if err != nil {
log.Fatalln(err)
}
fileServerUser := http.FileServer(http.FS(subUserFS))
muxUser.Handle("/", fileServerUser)
// Server user web
log.Printf("Serving %s for user web\n", userClientHost)
go func() {
log.Fatalln(http.ListenAndServe(config.UserClientPort, muxUser))
}()
go func() {
dir := "./data/story/images"
fs := http.FileServer(http.Dir(dir))
http.Handle("/", loggingMiddleware(fs))
log.Printf("Serving %s for file server, directory: %s\n", fileHost, dir)
log.Fatal(http.ListenAndServe(config.FilePort, nil))
}()
muxAdmin := http.NewServeMux()
subAdminFS, err := fs.Sub(adminFS, "static/admin")
if err != nil {
log.Fatalln(err)
}
fileServerAdmin := http.FileServer(http.FS(subAdminFS))
muxAdmin.Handle("/", fileServerAdmin)
// Server admin web
adminWebServer := &http.Server{
Addr: config.AdminClientPort,
Handler: muxAdmin,
}
log.Printf("Serving %s for admin web \n", adminClientHost)
log.Fatalln(adminWebServer.ListenAndServe())
}
func cors(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, Authorization, ResponseType, X-Id, X-Password")
if r.Method == "OPTIONS" {
return
}
h.ServeHTTP(w, r)
})
}
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// Логируем запрос
log.Printf("[%s] %s %s", r.Method, r.URL.Path, time.Since(start))
next.ServeHTTP(w, r)
})
}