2022-08-30 02:30:36 +00:00
package main
import (
"context"
2022-10-25 02:24:18 +00:00
"net/http"
2022-09-14 05:15:01 +00:00
"os"
2022-09-28 04:26:44 +00:00
"path/filepath"
2022-08-30 02:30:36 +00:00
"time"
2022-09-28 04:26:44 +00:00
atlas "ariga.io/atlas/sql/migrate"
"entgo.io/ent/dialect/sql/schema"
2022-10-25 02:24:18 +00:00
"github.com/hay-kot/homebox/backend/app/api/static/docs"
2022-09-24 19:33:38 +00:00
"github.com/hay-kot/homebox/backend/ent"
"github.com/hay-kot/homebox/backend/internal/config"
2022-09-28 04:26:44 +00:00
"github.com/hay-kot/homebox/backend/internal/migrations"
2022-09-24 19:33:38 +00:00
"github.com/hay-kot/homebox/backend/internal/repo"
"github.com/hay-kot/homebox/backend/internal/services"
"github.com/hay-kot/homebox/backend/pkgs/server"
2022-08-30 02:30:36 +00:00
_ "github.com/mattn/go-sqlite3"
2022-09-03 18:38:35 +00:00
"github.com/rs/zerolog/log"
2022-08-30 02:30:36 +00:00
)
2022-09-14 04:06:07 +00:00
var (
2022-10-14 01:01:01 +00:00
version = "nightly"
commit = "HEAD"
buildTime = "now"
2022-09-14 04:06:07 +00:00
)
2022-10-13 05:13:07 +00:00
// @title Go API Templates
// @version 1.0
// @description This is a simple Rest API Server Template that implements some basic User and Authentication patterns to help you get started and bootstrap your next project!.
// @contact.name Don't
// @license.name MIT
// @BasePath /api
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @description "Type 'Bearer TOKEN' to correctly set the API Key"
2022-08-30 02:30:36 +00:00
func main ( ) {
2022-10-12 21:03:42 +00:00
cfg , err := config . New ( )
2022-08-30 02:30:36 +00:00
if err != nil {
panic ( err )
}
docs . SwaggerInfo . Host = cfg . Swagger . Host
if err := run ( cfg ) ; err != nil {
panic ( err )
}
}
func run ( cfg * config . Config ) error {
2022-09-04 03:27:02 +00:00
app := new ( cfg )
app . setupLogger ( )
2022-09-24 19:33:38 +00:00
2022-08-30 02:30:36 +00:00
// =========================================================================
// Initialize Database & Repos
2022-09-24 19:33:38 +00:00
err := os . MkdirAll ( cfg . Storage . Data , 0755 )
if err != nil {
log . Fatal ( ) . Err ( err ) . Msg ( "failed to create data directory" )
}
c , err := ent . Open ( "sqlite3" , cfg . Storage . SqliteUrl )
2022-08-30 02:30:36 +00:00
if err != nil {
2022-09-03 18:38:35 +00:00
log . Fatal ( ) .
Err ( err ) .
2022-09-24 19:33:38 +00:00
Str ( "driver" , "sqlite" ) .
Str ( "url" , cfg . Storage . SqliteUrl ) .
2022-09-03 18:38:35 +00:00
Msg ( "failed opening connection to sqlite" )
2022-08-30 02:30:36 +00:00
}
defer func ( c * ent . Client ) {
2022-09-28 04:26:44 +00:00
err := c . Close ( )
if err != nil {
log . Fatal ( ) . Err ( err ) . Msg ( "failed to close database connection" )
}
2022-08-30 02:30:36 +00:00
} ( c )
2022-09-28 04:26:44 +00:00
temp := filepath . Join ( os . TempDir ( ) , "migrations" )
err = migrations . Write ( temp )
if err != nil {
return err
}
dir , err := atlas . NewLocalDir ( temp )
if err != nil {
return err
}
options := [ ] schema . MigrateOption {
schema . WithDir ( dir ) ,
schema . WithDropColumn ( true ) ,
schema . WithDropIndex ( true ) ,
}
err = c . Schema . Create ( context . Background ( ) , options ... )
if err != nil {
2022-09-03 18:38:35 +00:00
log . Fatal ( ) .
Err ( err ) .
2022-09-24 19:33:38 +00:00
Str ( "driver" , "sqlite" ) .
Str ( "url" , cfg . Storage . SqliteUrl ) .
2022-09-03 18:38:35 +00:00
Msg ( "failed creating schema resources" )
2022-08-30 02:30:36 +00:00
}
2022-09-28 04:26:44 +00:00
err = os . RemoveAll ( temp )
if err != nil {
log . Fatal ( ) . Err ( err ) . Msg ( "failed to remove temporary directory for database migrations" )
return err
}
2022-08-30 02:30:36 +00:00
app . db = c
2022-10-07 02:54:09 +00:00
app . repos = repo . New ( c , cfg . Storage . Data )
2022-10-15 20:15:55 +00:00
app . services = services . New ( app . repos )
2022-08-30 02:30:36 +00:00
// =========================================================================
// Start Server
2022-10-07 02:54:09 +00:00
app . server = server . NewServer (
server . WithHost ( app . conf . Web . Host ) ,
server . WithPort ( app . conf . Web . Port ) ,
)
2022-08-30 02:30:36 +00:00
routes := app . newRouter ( app . repos )
2022-09-04 03:27:02 +00:00
if app . conf . Mode != config . ModeDevelopment {
app . logRoutes ( routes )
}
2022-08-30 02:30:36 +00:00
2022-09-03 18:38:35 +00:00
log . Info ( ) . Msgf ( "Starting HTTP Server on %s:%s" , app . server . Host , app . server . Port )
2022-08-30 02:30:36 +00:00
// =========================================================================
// Start Reoccurring Tasks
2022-09-04 03:27:02 +00:00
go app . startBgTask ( time . Duration ( 24 ) * time . Hour , func ( ) {
2022-09-03 09:24:28 +00:00
_ , err := app . repos . AuthTokens . PurgeExpiredTokens ( context . Background ( ) )
if err != nil {
2022-09-03 18:38:35 +00:00
log . Error ( ) .
Err ( err ) .
Msg ( "failed to purge expired tokens" )
2022-09-03 09:24:28 +00:00
}
2022-08-30 02:30:36 +00:00
} )
2022-10-15 20:15:55 +00:00
go app . startBgTask ( time . Duration ( 24 ) * time . Hour , func ( ) {
_ , err := app . repos . Groups . InvitationPurge ( context . Background ( ) )
if err != nil {
log . Error ( ) .
Err ( err ) .
Msg ( "failed to purge expired invitations" )
}
} )
2022-08-30 02:30:36 +00:00
2022-10-12 20:53:22 +00:00
// TODO: Remove through external API that does setup
if cfg . Demo {
log . Info ( ) . Msg ( "Running in demo mode, creating demo data" )
app . SetupDemo ( )
}
2022-10-25 02:24:18 +00:00
if cfg . Debug . Enabled {
debugrouter := app . debugRouter ( )
go func ( ) {
if err := http . ListenAndServe ( ":" + cfg . Debug . Port , debugrouter ) ; err != nil {
log . Fatal ( ) . Err ( err ) . Msg ( "failed to start debug server" )
}
} ( )
}
2022-08-30 02:30:36 +00:00
return app . server . Start ( routes )
}