/ journalist.go
journalist.go
  1  package main
  2  
  3  import (
  4  	"context"
  5  	"embed"
  6  	"fmt"
  7  	"net/http"
  8  	"os"
  9  
 10  	"github.com/aws/aws-lambda-go/events"
 11  	"github.com/aws/aws-lambda-go/lambda"
 12  	fiberadapter "github.com/awslabs/aws-lambda-go-api-proxy/fiber"
 13  
 14  	"go.uber.org/zap"
 15  
 16  	"github.com/gofiber/fiber/v2"
 17  
 18  	"github.com/mrusme/journalist/ent"
 19  	"github.com/mrusme/journalist/journalistd"
 20  	"github.com/mrusme/journalist/lib"
 21  
 22  	"github.com/mrusme/journalist/api"
 23  	"github.com/mrusme/journalist/middlewares/fiberzap"
 24  	"github.com/mrusme/journalist/web"
 25  
 26  	_ "github.com/go-sql-driver/mysql"
 27  	_ "github.com/lib/pq"
 28  	_ "github.com/mattn/go-sqlite3"
 29  )
 30  
 31  //go:embed views/*
 32  var viewsfs embed.FS
 33  
 34  //go:embed favicon.ico
 35  var favicon embed.FS
 36  
 37  var fiberApp *fiber.App
 38  var fiberLambda *fiberadapter.FiberLambda
 39  
 40  var config lib.Config
 41  var logger *zap.Logger
 42  
 43  func init() {
 44  	var err error
 45  
 46  	fiberLambda = fiberadapter.New(fiberApp)
 47  	config, err = lib.Cfg()
 48  	if err != nil {
 49  		panic(err)
 50  	}
 51  
 52  	if config.Debug == "true" {
 53  		logger, _ = zap.NewDevelopment()
 54  	} else {
 55  		logger, _ = zap.NewProduction()
 56  	}
 57  	defer logger.Sync()
 58  	// TODO: Use sugarLogger
 59  	// sugar := logger.Sugar()
 60  }
 61  
 62  func AWSLambdaHandler(
 63  	ctx context.Context,
 64  	req events.APIGatewayProxyRequest,
 65  ) (events.APIGatewayProxyResponse, error) {
 66  	return fiberLambda.ProxyWithContext(ctx, req)
 67  }
 68  
 69  func GCFHandler(
 70  	w http.ResponseWriter,
 71  	r *http.Request,
 72  ) {
 73  	err := CloudFunctionRouteToFiber(fiberApp, w, r)
 74  	if err != nil {
 75  		logger.Error(
 76  			"Handler error",
 77  			zap.Error(err),
 78  		)
 79  		return
 80  	}
 81  }
 82  
 83  func main() {
 84  	var err error
 85  	var jctx lib.JournalistContext
 86  	var entClient *ent.Client
 87  
 88  	entClient, err = ent.Open(config.Database.Type, config.Database.Connection)
 89  	if err != nil {
 90  		logger.Error(
 91  			"Failed initializing database",
 92  			zap.Error(err),
 93  		)
 94  	}
 95  	defer entClient.Close()
 96  	if err := entClient.Schema.Create(context.Background()); err != nil {
 97  		logger.Error(
 98  			"Failed initializing schema",
 99  			zap.Error(err),
100  		)
101  	}
102  
103  	jctx = lib.JournalistContext{
104  		Config:    &config,
105  		EntClient: entClient,
106  		Logger:    logger,
107  	}
108  
109  	jd, err := journalistd.New(
110  		&jctx,
111  	)
112  	if err != nil {
113  		panic(err)
114  	}
115  
116  	engine := web.NewFileSystem(http.FS(viewsfs), ".html")
117  	fiberApp = fiber.New(fiber.Config{
118  		Prefork:                 false, // TODO: Make configurable
119  		ServerHeader:            "",    // TODO: Make configurable
120  		StrictRouting:           false,
121  		CaseSensitive:           false,
122  		ETag:                    false,      // TODO: Make configurable
123  		Concurrency:             256 * 1024, // TODO: Make configurable
124  		Views:                   engine,
125  		ProxyHeader:             "",         // TODO: Make configurable
126  		EnableTrustedProxyCheck: false,      // TODO: Make configurable
127  		TrustedProxies:          []string{}, // TODO: Make configurable
128  		DisableStartupMessage:   true,
129  		AppName:                 "journalist",
130  		ReduceMemoryUsage:       false,            // TODO: Make configurable
131  		Network:                 fiber.NetworkTCP, // TODO: Make configurable
132  		EnablePrintRoutes:       false,
133  	})
134  	fiberApp.Use(fiberzap.New(fiberzap.Config{
135  		Logger: logger,
136  	}))
137  
138  	api.Register(
139  		&jctx,
140  		fiberApp,
141  	)
142  
143  	web.Register(
144  		&jctx,
145  		fiberApp,
146  	)
147  
148  	fiberApp.Get("/favicon.ico", func(ctx *fiber.Ctx) error {
149  		fi, err := favicon.Open("favicon.ico")
150  		if err != nil {
151  			return ctx.SendStatus(fiber.StatusInternalServerError)
152  		}
153  		return ctx.SendStream(fi)
154  	})
155  
156  	fiberApp.Get("/health", func(ctx *fiber.Ctx) error {
157  		// TODO: Check for issues
158  		return ctx.SendStatus(fiber.StatusNoContent)
159  	})
160  
161  	functionName := os.Getenv("AWS_LAMBDA_FUNCTION_NAME")
162  
163  	if config.Feeds.AutoRefresh != "" {
164  
165  		if functionName == "" {
166  			jd.Start()
167  		} else {
168  			logger.Warn(
169  				"Journalist won't start the feed auto refresh thread " +
170  					"while it is running as a Lambda function",
171  			)
172  		}
173  	}
174  
175  	if functionName == "" {
176  		listenAddr := fmt.Sprintf(
177  			"%s:%s",
178  			config.Server.BindIP,
179  			config.Server.Port,
180  		)
181  		logger.Fatal(
182  			"Server failed",
183  			zap.Error(fiberApp.Listen(listenAddr)),
184  		)
185  	} else {
186  		lambda.Start(AWSLambdaHandler)
187  	}
188  }