Files
satusehat-service/internal/infrastructure/transport/http/servers/server.go
T
2026-04-14 01:23:34 +00:00

267 lines
9.9 KiB
Go

// internal/infrastructure/transport/http/servers/server.go
package servers
import (
"context" // PERBAIKAN: Tambahkan import untuk graceful shutdown
"fmt"
"log"
"net/http"
"time"
"service/internal/infrastructure/cache" // PERBAIKAN: Tambahkan import cache
"service/internal/infrastructure/config"
"service/internal/infrastructure/transport/http/middleware"
"service/internal/infrastructure/transport/http/routes"
antrolHttp "service/internal/infrastructure/transport/http/handlers/bpjs/antrol"
aplicareHttp "service/internal/infrastructure/transport/http/handlers/bpjs/aplicare"
apotekHttp "service/internal/infrastructure/transport/http/handlers/bpjs/apotek"
vclaimHttp "service/internal/infrastructure/transport/http/handlers/bpjs/vclaim"
authHttp "service/internal/infrastructure/transport/http/handlers/main/auth"
healthHttp "service/internal/infrastructure/transport/http/handlers/main/health"
roleHttp "service/internal/infrastructure/transport/http/handlers/main/master/roles"
satuSehatRefHttp "service/internal/infrastructure/transport/http/handlers/satusehat/reference"
satuSehatUsecaseHttp "service/internal/infrastructure/transport/http/handlers/satusehat/usecase"
// Inisialisasi pkg
"service/pkg/errors"
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
)
type Server struct {
engine *gin.Engine
config *config.ServerRESTConfig
cacheConfig cache.CacheConfig // PERBAIKAN: Tambahkan cacheConfig
httpServer *http.Server // PERBAIKAN: Simpan instance http.Server untuk graceful shutdown
}
// NewHTTPServer membuat instance server HTTP baru
func NewHTTPServer(
restConfig *config.ServerRESTConfig,
registry *ServiceRegistry,
) *Server {
if !restConfig.Enabled {
log.Println("HTTP server is disabled in configuration.")
return &Server{
config: restConfig,
}
}
// Set mode Gin berdasarkan konfigurasi global
if registry.Config.Server.Mode == "release" {
gin.SetMode(gin.ReleaseMode)
}
engine := gin.New()
// Middleware untuk recovery dan penanganan error konsisten.
// Diletakkan paling awal untuk menangkap panic dari middleware/handler lain.
engine.Use(errors.CombinedMiddleware())
// Middleware lainnya
engine.Use(middleware.LoggingMiddleware())
engine.Use(middleware.SecurityMiddleware())
engine.Use(middleware.CORSMiddleware())
// PERBAIKAN: Berikan cacheManager ke RateLimitMiddleware
engine.Use(middleware.RateLimitMiddleware(registry.CacheManager))
// Inisialisasi ModuleHandlers secara dinamis berdasarkan fitur yang aktif
appHandlers := &routes.ModuleHandlers{}
if registry.AuthService != nil {
appHandlers.Auth = authHttp.NewAuthHandler(registry.AuthService)
}
// Inisialisasi Handlers Modul Master
if registry.Master != nil {
if registry.Master.RolePages != nil {
appHandlers.RolePages = roleHttp.NewRolPagesHandler(registry.Master.RolePages)
}
if registry.Master.RolePermission != nil {
appHandlers.RolePermission = roleHttp.NewRolPermissionHandler(registry.Master.RolePermission)
}
if registry.Master.RoleMaster != nil {
appHandlers.RoleMaster = roleHttp.NewRoleMasterHandler(registry.Master.RoleMaster)
}
}
// Inisialisasi Handlers Modul VClaim
if registry.VClaim != nil {
if registry.VClaim.Sep != nil {
appHandlers.Sep = vclaimHttp.NewSepHandler(registry.VClaim.Sep)
}
if registry.VClaim.Peserta != nil {
appHandlers.Peserta = vclaimHttp.NewPesertaHandler(registry.VClaim.Peserta)
}
}
// Inisialisasi Handlers Modul Antrol
if registry.Antrol != nil {
if registry.Antrol.Reference != nil {
appHandlers.Antrol = antrolHttp.NewAntrolHandler(registry.Antrol.Reference)
}
}
// Inisialisasi Handlers Modul Aplicares
if registry.Aplicare != nil {
if registry.Aplicare.Bed != nil {
appHandlers.AplicareBed = aplicareHttp.NewBedHandler(registry.Aplicare.Bed)
}
}
// Inisialisasi Handlers Modul Apotek
if registry.Apotek != nil {
if registry.Apotek.DPHO != nil && registry.Apotek.Poli != nil {
appHandlers.ApotekReference = apotekHttp.NewReferenceHandler(registry.Apotek.DPHO, registry.Apotek.Poli)
}
}
// Inisialisasi Handlers Modul Satu Sehat
if registry.SatuSehat != nil {
if registry.SatuSehat.Auth != nil {
appHandlers.SatuSehatAuth = satuSehatRefHttp.NewAuthHandler(registry.SatuSehat.Auth)
}
if registry.SatuSehat.Patient != nil {
appHandlers.SatuSehatPatient = satuSehatRefHttp.NewPatientHandler(registry.SatuSehat.Patient)
}
if registry.SatuSehat.Practitioner != nil {
appHandlers.SatuSehatPractitioner = satuSehatRefHttp.NewPractitionerHandler(registry.SatuSehat.Practitioner)
}
if registry.SatuSehat.Organization != nil {
appHandlers.SatuSehatOrganization = satuSehatRefHttp.NewOrganizationHandler(registry.SatuSehat.Organization)
}
if registry.SatuSehat.Location != nil {
appHandlers.SatuSehatLocation = satuSehatRefHttp.NewLocationHandler(registry.SatuSehat.Location)
}
if registry.SatuSehat.KFA != nil {
appHandlers.SatuSehatKFA = satuSehatRefHttp.NewKFAHandler(registry.SatuSehat.KFA)
}
// Inisialisasi Handlers Modul Satu Sehat Usecase
if registry.SatuSehat.AllergyIntolerance != nil {
appHandlers.SSAllergyIntolerance = satuSehatUsecaseHttp.NewAllergyIntoleranceHandler(registry.SatuSehat.AllergyIntolerance)
}
if registry.SatuSehat.CarePlan != nil {
appHandlers.SSCarePlan = satuSehatUsecaseHttp.NewCarePlanHandler(registry.SatuSehat.CarePlan)
}
if registry.SatuSehat.ClinicalImpression != nil {
appHandlers.SSClinicalImpression = satuSehatUsecaseHttp.NewClinicalImpressionHandler(registry.SatuSehat.ClinicalImpression)
}
if registry.SatuSehat.Composition != nil {
appHandlers.SSComposition = satuSehatUsecaseHttp.NewCompositionHandler(registry.SatuSehat.Composition)
}
if registry.SatuSehat.Condition != nil {
appHandlers.SSCondition = satuSehatUsecaseHttp.NewConditionHandler(registry.SatuSehat.Condition)
}
if registry.SatuSehat.DiagnosticReport != nil {
appHandlers.SSDiagnosticReport = satuSehatUsecaseHttp.NewDiagnosticReportHandler(registry.SatuSehat.DiagnosticReport)
}
if registry.SatuSehat.Encounter != nil {
appHandlers.SSEncounter = satuSehatUsecaseHttp.NewEncounterHandler(registry.SatuSehat.Encounter)
}
if registry.SatuSehat.EpisodeOfCare != nil {
appHandlers.SSEpisodeOfCare = satuSehatUsecaseHttp.NewEpisodeOfCareHandler(registry.SatuSehat.EpisodeOfCare)
}
if registry.SatuSehat.ImagingStudy != nil {
appHandlers.SSImagingStudy = satuSehatUsecaseHttp.NewImagingStudyHandler(registry.SatuSehat.ImagingStudy)
}
if registry.SatuSehat.Immunization != nil {
appHandlers.SSImmunization = satuSehatUsecaseHttp.NewImmunizationHandler(registry.SatuSehat.Immunization)
}
if registry.SatuSehat.Medication != nil {
appHandlers.SSMedication = satuSehatUsecaseHttp.NewMedicationHandler(registry.SatuSehat.Medication)
}
if registry.SatuSehat.MedicationDispense != nil {
appHandlers.SSMedicationDispense = satuSehatUsecaseHttp.NewMedicationDispenseHandler(registry.SatuSehat.MedicationDispense)
}
if registry.SatuSehat.MedicationRequest != nil {
appHandlers.SSMedicationRequest = satuSehatUsecaseHttp.NewMedicationRequestHandler(registry.SatuSehat.MedicationRequest)
}
if registry.SatuSehat.MedicationStatement != nil {
appHandlers.SSMedicationStatement = satuSehatUsecaseHttp.NewMedicationStatementHandler(registry.SatuSehat.MedicationStatement)
}
if registry.SatuSehat.Observation != nil {
appHandlers.SSObservation = satuSehatUsecaseHttp.NewObservationHandler(registry.SatuSehat.Observation)
}
if registry.SatuSehat.Procedure != nil {
appHandlers.SSProcedure = satuSehatUsecaseHttp.NewProcedureHandler(registry.SatuSehat.Procedure)
}
if registry.SatuSehat.QuestionnaireResponse != nil {
appHandlers.SSQuestionnaireResponse = satuSehatUsecaseHttp.NewQuestionnaireResponseHandler(registry.SatuSehat.QuestionnaireResponse)
}
if registry.SatuSehat.ServiceRequest != nil {
appHandlers.SSServiceRequest = satuSehatUsecaseHttp.NewServiceRequestHandler(registry.SatuSehat.ServiceRequest)
}
if registry.SatuSehat.Specimen != nil {
appHandlers.SSSpecimen = satuSehatUsecaseHttp.NewSpecimenHandler(registry.SatuSehat.Specimen)
}
}
// Inisialisasi Health Handler dengan dependensi yang benar
// Gunakan constructor baru yang menerima cache manager
healthHandler := healthHttp.NewHealthHandlerWithCache(registry.PrimaryDB, registry.CacheManager, registry.Config, registry.DBManager)
// Setup routes menggunakan handler yang sudah diinisialisasi
routes.SetupRoutes(
engine,
registry.Config,
registry.CacheManager,
healthHandler,
appHandlers,
)
return &Server{
engine: engine,
config: restConfig,
}
}
// RegisterSwagger mendaftarkan dokumentasi Swagger UI
func (s *Server) RegisterSwagger() {
if s.engine == nil {
log.Println("Cannot register Swagger: engine is nil (server disabled)")
return
}
s.engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
}
// Start menjalankan server HTTP
func (s *Server) Start(globalConfig *config.ServerConfig) error {
if !s.config.Enabled {
log.Println("HTTP server is disabled, not starting.")
return nil
}
addr := fmt.Sprintf(":%d", s.config.Port)
log.Printf("Starting HTTP server on %s", addr)
// PERBAIKAN: Simpan instance server ke struct
s.httpServer = &http.Server{
Addr: addr,
Handler: s.engine,
ReadTimeout: time.Duration(globalConfig.ReadTimeout) * time.Second,
WriteTimeout: time.Duration(globalConfig.WriteTimeout) * time.Second,
IdleTimeout: 60 * time.Second, // Good practice to have an idle timeout
}
return s.httpServer.ListenAndServe()
}
// PERBAIKAN: Tambahkan method untuk graceful shutdown
// Shutdown memberhentikan server HTTP dengan graceful shutdown
func (s *Server) Shutdown(ctx context.Context) error {
if s.httpServer == nil {
return nil
}
log.Println("Shutting down HTTP server...")
return s.httpServer.Shutdown(ctx)
}
// GetEngine mengembalikan instance Gin engine (terutama untuk testing)
func (s *Server) GetEngine() *gin.Engine {
return s.engine
}