package main import ( "context" "database/sql" "fmt" "kemendagri/sipd/services/transaksi-belanja-sipd/controllers" hdl "kemendagri/sipd/services/transaksi-belanja-sipd/handler" "kemendagri/sipd/services/transaksi-belanja-sipd/handler/configs" "kemendagri/sipd/services/transaksi-belanja-sipd/handler/http_util" _deliveryMiddleware "kemendagri/sipd/services/transaksi-belanja-sipd/handler/middleware" "kemendagri/sipd/services/transaksi-belanja-sipd/utils" "log" "os" "strconv" "strings" "time" swagDoc "kemendagri/sipd/services/transaksi-belanja-sipd/docs" swagger "github.com/arsmn/fiber-swagger/v2" "github.com/go-playground/validator/v10" "github.com/gofiber/fiber/v2" "github.com/golang-migrate/migrate/v4" "github.com/golang-migrate/migrate/v4/database" "github.com/golang-migrate/migrate/v4/database/postgres" _ "github.com/golang-migrate/migrate/v4/source/file" "github.com/jackc/pgx/v5/pgxpool" _ "github.com/lib/pq" ) var db *sql.DB var pgxConn *pgxpool.Pool var driver database.Driver var migration *migrate.Migrate var vld *validator.Validate var err error var serverName, serverUrl, serverReadTimeout, alwOrg, dbConn, urlScheme, baseUrl, basePath string func init() { serverName = os.Getenv("SERVER_NAME") if serverName == "" { exitf("SERVER_NAME env is required") } serverUrl = os.Getenv("SERVER_URL") if serverUrl == "" { exitf("SERVER_URL env is required") } serverReadTimeout = os.Getenv("SERVER_READ_TIMEOUT") if serverReadTimeout == "" { exitf("SERVER_READ_TIMEOUT env is required") } alwOrg = os.Getenv("SIPD_CORS_WHITELISTS") if alwOrg == "" { exitf("SIPD_CORS_WHITELISTS config is required") } // Databse Env dbConn = os.Getenv("DB_CONN") if dbConn == "" { exitf("DB_CONN config is required") } urlScheme = os.Getenv("URL_SCHEME") if urlScheme == "" { exitf("URL_SCHEME config is required") } baseUrl = os.Getenv("BASE_URL") if baseUrl == "" { exitf("BASE_URL config is required") } basePath = os.Getenv("BASE_PATH") if basePath == "" { exitf("BASE_PATH config is required") } } func databaseMigration() { db, err = sql.Open("postgres", dbConn) //sesuaikan saat migrasi if err != nil { exitf("Db open error: %v\n", err) } driver, err = postgres.WithInstance(db, &postgres.Config{}) if err != nil { _ = db.Close() exitf("Db postgres driven error: %v\n", err) } migration, err = migrate.NewWithDatabaseInstance("file://migrations", "postgres", driver) if err != nil { _ = db.Close() exitf("Unable to initiate migration: %v\n", err) } err = migration.Up() // or m.Step(2) if you want to explicitly set the number of migrations to run if err != nil { log.Println(fmt.Sprintf("Migration error: %s", err.Error())) } err = db.Close() if err != nil { log.Println(fmt.Sprintf("Db close error: %s", err.Error())) } } func dbConnection() { var maxConnLifetime, maxConnIdleTime time.Duration maxConnLifetime = 5 * time.Minute maxConnIdleTime = 2 * time.Minute var cfg *pgxpool.Config cfg, err = pgxpool.ParseConfig(dbConn) if err != nil { exitf("Unable to create db pool config sipd_anggaran %v\n", err) } // cfg.MaxConns = 1000 // Maximum total connections in the pool cfg.MaxConnLifetime = maxConnLifetime // Maximum lifetime of a connection cfg.MaxConnIdleTime = maxConnIdleTime // Maximum time a connection can be idle pgxConn, err = pgxpool.NewWithConfig(context.Background(), cfg) if err != nil { exitf("Unable to connect to database sipd_anggaran %v\n", err) } } // @title SIPD Service Transaksi Belanja // @version 1.0 // @description SIPD Service Transaksi Belanja Rest API. // @termsOfService http://swagger.io/terms/ // @contact.name API Support // @contact.email lifelinejar@mail.com // @license.name Apache 2.0 // @license.url http://www.apache.org/licenses/LICENSE-2.0.html // @securityDefinitions.apikey ApiKeyAuth // @in header // @name Authorization // @BasePath / func main() { // migrasi database // databaseMigration() // Pgx Pool Connection dbConnection() defer func() { pgxConn.Close() }() // End Pgx Pool Connection // Define a validator vld = utils.NewValidator() // Define Fiber config. config := configs.FiberConfig() app := fiber.New(config) middL := _deliveryMiddleware.InitMiddleware(app) //app.Use(middL.RateLimiter()) app.Use(middL.CORS()) app.Use(middL.LOGGER()) app.Use(func(c *fiber.Ctx) error { // Middleware to check for whitelisted domains if alwOrg == "*" { // Continue to the next middleware/handler return c.Next() } // Use "X-Forwarded-Host" to simulate the Host header in Postman origin := c.Get("Origin") // log.Println("Origin: ", origin) alwOrgArr := strings.Split(alwOrg, ",") // log.Println("alwOrgArr: ", alwOrgArr) var originMatch bool for _, alo := range alwOrgArr { if origin == alo { originMatch = true break } else { /*host := c.Hostname() // log.Println("Host: ", host) if "https://"+host == alo || "http://"+host == alo { originMatch = true break }*/ } } if !originMatch { log.Println("alwOrgArr: ", alwOrgArr) log.Println("Origin: ", origin) return c.Status(fiber.StatusForbidden).SendString("403 - MSTDT: origin not allowed") } // Continue to the next middleware/handler return c.Next() }) // Swagger handler // app.Get("/swagger/*", swagger.HandlerDefault) swagDoc.SwaggerInfo.Host = baseUrl swagDoc.SwaggerInfo.BasePath = basePath app.Get("/swagger/*", swagger.New(swagger.Config{ URL: urlScheme + baseUrl + basePath + "swagger/doc.json", // default search box })) serverReadTimeoutInt, err := strconv.Atoi(serverReadTimeout) if err != nil { exitf("Failed casting timeout context: ", err) } timeoutContext := time.Duration(serverReadTimeoutInt) * time.Second // welcome router welcomeController := controllers.NewWelcomeController(pgxConn, timeoutContext) hdl.NewWelcomeHandler(app, vld, welcomeController) // end welcome router // kecamatan router // kecamatanController := controllers.NewKecamatanController(pgxConn, timeoutContext) // hdl.NewKecamatanHandler(app, vld, kecamatanController) // end kecamatan router http_util.StartServer(app) } func exitf(s string, args ...interface{}) { errorf(s, args...) os.Exit(1) } func errorf(s string, args ...interface{}) { fmt.Fprintf(os.Stderr, s+"\n", args...) }