Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
eb6a01b
Add config model
akkahshh24 May 12, 2025
4f2f17f
Add config package to load config from file
akkahshh24 May 12, 2025
bd4716f
Clean key names in yaml file
akkahshh24 May 12, 2025
74f40b9
Set log level using config
akkahshh24 May 12, 2025
ce7e9da
Pass config to espress service to create storage adapters
akkahshh24 May 12, 2025
1b52e61
Move config package to service/internal/config
akkahshh24 May 13, 2025
11100ec
Add config constants
akkahshh24 May 13, 2025
07ae542
Take config options from env
akkahshh24 May 13, 2025
f876bad
Pass config to template storage adapter
akkahshh24 May 13, 2025
c435d17
Add few keys in config file
akkahshh24 May 13, 2025
4182e13
Change config model
akkahshh24 May 13, 2025
fdb494e
Add config model
akkahshh24 May 12, 2025
0ea8db3
Add config package to load config from file
akkahshh24 May 12, 2025
80e754e
Clean key names in yaml file
akkahshh24 May 12, 2025
f3e7e75
Set log level using config
akkahshh24 May 12, 2025
8ad2a6b
Pass config to espress service to create storage adapters
akkahshh24 May 12, 2025
d876833
Move config package to service/internal/config
akkahshh24 May 13, 2025
5e79330
Add config constants
akkahshh24 May 13, 2025
51eae0a
Take config options from env
akkahshh24 May 13, 2025
051b9ef
Pass config to template storage adapter
akkahshh24 May 13, 2025
6161ada
Add few keys in config file
akkahshh24 May 13, 2025
46e1260
Change config model
akkahshh24 May 13, 2025
8e521b2
Fix db host and port
akkahshh24 May 22, 2025
1368b7e
Delete unused viperpkg
akkahshh24 May 22, 2025
20c1ebd
Move config model to internal/pkg/config
akkahshh24 May 22, 2025
284445a
Move config logic to internal/pkg/config
akkahshh24 May 22, 2025
f18c11d
Rectify config package import path
akkahshh24 May 22, 2025
8685410
Merge branch 'feature/config_service_dev' of https://github.com/akkah…
akkahshh24 Jun 1, 2025
5b99095
use CertificateConfig struct from lib
akkahshh24 Jun 3, 2025
35cbf9a
Add credential store to load signing credentials at startup
akkahshh24 Jun 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 28 additions & 18 deletions service/configs/espressoconfig.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
app:
log_level: "debug"
server_port: 8081
enable_ui: true
rod_browser_bin: "/opt/homebrew/bin/chromium"

template_storage:
storage_type: "mysql"

Expand All @@ -9,37 +15,41 @@ browser:

workerpool:
worker_count: 6
worker_timeout: 310 # milliseconds
worker_timeout_ms: 310 # milliseconds

s3:
endpoint: "http://localstack:4566"
debug: false
region: "us-west-2"
forcePathStyle: true
uploaderConcurrency: 5
force_path_style: true
uploader_concurrency: 5
# 5MB chunks
uploaderPartSize: 5
downloaderConcurrency: 5
uploader_part_size_mb: 5
downloader_concurrency: 5
# 5MB chunks
downloaderPartSize: 5242880
retryMaxAttempts: 3
downloader_part_size_mb: 5242880
retry_max_attempts: 3
bucket: "local-bucket"
useCustomTransport: false
use_custom_transport: false

aws:
accessKeyID: "xxxxx-xxxxx-xxxxx-xxxxx-xxxxx"
secretAccessKey: "xxxxx-xxxxx-xxxxx-xxxxx-xxxxx"
sessionToken: ""
access_key_id: "xxxxx-xxxxx-xxxxx-xxxxx-xxxxx"
secret_access_key: "xxxxx-xxxxx-xxxxx-xxxxx-xxxxx"
session_token: ""

digital_certificates:
certificates:
cert1:
cert_filepath: "./inputfiles/certificates/cert.pem"
key_filepath: "./inputfiles/certificates/key_pkcs8_encrypted.pem"
cert_path: "./inputfiles/certificates/cert.pem"
key_path: "./inputfiles/certificates/key_pkcs8_encrypted.pem"
key_password: "test"
cert2:
cert_filepath: "./certificates/certificate2.pem"
key_filepath: "./certificates/pirvatekey2.key"
cert_path: "./certificates/certificate2.pem"
key_path: "./certificates/pirvatekey2.key"
key_password: "password2"

mysql:
dsn: "pdf_user:pdf_password@tcp(mysql:3306)/pdf_templates?parseTime=true"
db:
host: "localhost"
port: 3308
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3306? check dockercompose

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I was running Espresso service in my local machine (in debug mode) and not as a docker container, I had mapped the host as localhost and port as 3308 instead of 3306. I will resolve this error and push it.

username: "pdf_user"
password: "pdf_password"
database: "pdf_templates"
52 changes: 21 additions & 31 deletions service/controller/pdf_generation/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,52 @@ import (
"fmt"
"log"
"net/http"
"os"

"github.com/Zomato/espresso/lib/s3"
"github.com/Zomato/espresso/lib/templatestore"
"github.com/spf13/viper"
"github.com/Zomato/espresso/service/model"
)

type EspressoService struct {
TemplateStorageAdapter *templatestore.StorageAdapter
FileStorageAdapter *templatestore.StorageAdapter
}

func NewEspressoService() (*EspressoService, error) {
templateStorageType := viper.GetString("template_storage.storage_type")
if os.Getenv("ENABLE_UI") == "true" && templateStorageType != templatestore.StorageAdapterTypeMySQL {
func NewEspressoService(config model.Config) (*EspressoService, error) {
templateStorageType := config.TemplateStorageConfig.StorageType

if config.AppConfig.EnableUI && templateStorageType != templatestore.StorageAdapterTypeMySQL {
return nil, fmt.Errorf("UI requires MySQL as template storage adapter, got: %s", templateStorageType)
}

mySqlDsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?parseTime=true",
config.DBConfig.Username,
config.DBConfig.Password,
config.DBConfig.Host,
config.DBConfig.Port,
config.DBConfig.Database,
)

templateStorageAdapter, err := templatestore.TemplateStorageAdapterFactory(&templatestore.StorageConfig{
StorageType: templateStorageType,
// for s3 storage only
S3Config: &s3.Config{
Endpoint: viper.GetString("s3.endpoint"),
Region: viper.GetString("s3.region"),
Bucket: viper.GetString("s3.bucket"),
Debug: viper.GetBool("s3.debug"),
ForcePathStyle: viper.GetBool("s3.forcePathStyle"),
UploaderConcurrency: viper.GetInt("s3.uploaderConcurrency"),
UploaderPartSize: viper.GetInt64("s3.uploaderPartSize"),
DownloaderConcurrency: viper.GetInt("s3.downloaderConcurrency"),
DownloaderPartSize: viper.GetInt64("s3.downloaderPartSize"),
RetryMaxAttempts: viper.GetInt("s3.retryMaxAttempts"),
UseCustomTransport: viper.GetBool("s3.useCustomTransport"),
},
// for s3 storage only
AwsCredConfig: &s3.AwsCredConfig{
AccessKeyID: viper.GetString("aws.accessKeyID"),
SecretAccessKey: viper.GetString("aws.secretAccessKey"),
SessionToken: viper.GetString("aws.sessionToken"),
},
MysqlDSN: viper.GetString("mysql.dsn"), // for mysql adapter
StorageType: templateStorageType,
S3Config: &config.S3Config, // for s3 storage only
AwsCredConfig: &config.AWSConfig, // for s3 storage only
MysqlDSN: mySqlDsn, // for mysql adapter
})
if err != nil {
return nil, err
}

fileStorageAdapter, err := templatestore.TemplateStorageAdapterFactory(&templatestore.StorageConfig{
StorageType: viper.GetString("file_storage.storage_type"),
StorageType: config.FileStorageConfig.StorageType,
})
if err != nil {
return nil, err
}

return &EspressoService{TemplateStorageAdapter: &templateStorageAdapter, FileStorageAdapter: &fileStorageAdapter}, nil
}
func Register(mux *http.ServeMux) {
espressoService, err := NewEspressoService()
func Register(mux *http.ServeMux, config model.Config) {
espressoService, err := NewEspressoService(config)
if err != nil {
log.Fatalf("Failed to initialize PDF service: %v", err)
}
Expand Down
44 changes: 44 additions & 0 deletions service/internal/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package config

import (
"fmt"

"github.com/Zomato/espresso/service/model"
"github.com/spf13/viper"
)

func Load() (model.Config, error) {
viper.AutomaticEnv()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move to service/internal pkg

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

service/internal/pkg/config/config.go ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes


viper.SetDefault(CONFIG_FILE_NAME, "espressoconfig")
viper.SetDefault(CONFIG_FILE_TYPE, "yaml")
viper.SetDefault(CONFIG_FILE_PATH, "/app/espresso/configs")

viper.SetConfigName(viper.GetString(CONFIG_FILE_NAME)) // File name without extension
viper.SetConfigType(viper.GetString(CONFIG_FILE_TYPE)) // File type

// Search paths relative to where the binary runs in container
viper.AddConfigPath(CONFIG_FILE_PATH) // Main config path in container
viper.AddConfigPath("../../configs") // For local development
viper.AddConfigPath("./configs") // Fallback path for local development

err := viper.ReadInConfig()
if err != nil {
return model.Config{}, err
}

var config model.Config
err = viper.Unmarshal(&config)
if err != nil {
return model.Config{}, err
}

// TODO: Why are these fields set in the Dockerfile and not in the config.yaml file?
config.AppConfig.EnableUI = viper.GetBool(ENABLE_UI)
config.AppConfig.RodBrowserBin = viper.GetString(ROD_BROWSER_BIN)
if config.AppConfig.RodBrowserBin == "" {
return model.Config{}, fmt.Errorf("environment variable %s not set", ROD_BROWSER_BIN)
}

return config, nil
}
10 changes: 10 additions & 0 deletions service/internal/config/constant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package config

const (
CONFIG_FILE_NAME = "CONFIG_FILE_NAME"
CONFIG_FILE_TYPE = "CONFIG_FILE_TYPE"
CONFIG_FILE_PATH = "CONFIG_FILE_PATH"

ENABLE_UI = "ENABLE_UI"
ROD_BROWSER_BIN = "ROD_BROWSER_BIN"
)
32 changes: 19 additions & 13 deletions service/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,42 +12,48 @@ import (
logger "github.com/Zomato/espresso/lib/logger"
"github.com/Zomato/espresso/lib/workerpool"
"github.com/Zomato/espresso/service/controller/pdf_generation"
"github.com/Zomato/espresso/service/internal/pkg/viperpkg"
"github.com/Zomato/espresso/service/internal/config"
"github.com/Zomato/espresso/service/utils"
"github.com/spf13/viper"
)

func main() {
ctx := context.Background()

viperpkg.InitConfig()
config, err := config.Load()
if err != nil {
log.Fatalf("Error loading config: %v", err)
}

// Replace ZeroLog with any logging library by implementing ILogger interface.
zeroLog := utils.NewZeroLogger()
zeroLog := utils.NewZeroLogger(config.AppConfig.LogLevel)
logger.Initialize(zeroLog)

log.Printf("Template storage type: %s", viper.GetString("template_storage.storage_type"))
log.Printf("File storage type: %s", viper.GetString("file_storage.storage_type"))
log.Printf("Template storage type: %s", config.TemplateStorageConfig.StorageType)
log.Printf("File storage type: %s", config.FileStorageConfig.StorageType)

tabpool := config.BrowserConfig.TabPool
browserPath := config.AppConfig.RodBrowserBin

tabpool := viper.GetInt("browser.tab_pool")
if err := browser_manager.Init(ctx, tabpool); err != nil {
if err := browser_manager.Init(ctx, tabpool, browserPath); err != nil {
log.Fatalf("Failed to initialize browser: %v", err)
}
workerCount := viper.GetInt("workerpool.worker_count")
workerTimeout := viper.GetInt("workerpool.worker_timeout")

workerCount := config.WorkerPoolConfig.WorkerCount
workerTimeout := config.WorkerPoolConfig.WorkerTimeoutMs

initializeWorkerPool(workerCount, workerTimeout)

// register server for example v2
// Create a new ServeMux
mux := http.NewServeMux()

pdf_generation.Register(mux)
pdf_generation.Register(mux, config)
// Wrap the entire mux with the CORS middleware
corsHandler := enableCORS(mux)

log.Println("Starting PDF client server on :8081")
if err := http.ListenAndServe(":8081", corsHandler); err != nil {
port := fmt.Sprintf(":%d", config.AppConfig.ServerPort)
log.Printf("Starting PDF client server on: %s\n", port)
if err := http.ListenAndServe(port, corsHandler); err != nil {
log.Fatal(err)
}

Expand Down
51 changes: 51 additions & 0 deletions service/model/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package model

import (
"github.com/Zomato/espresso/lib/s3"
)

type Config struct {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this to service/internal pkg

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

service/internal/pkg/config/model/config.go ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

..pkg/config/model.go for models and pkg/config/config.go for logic

AppConfig AppConfig `mapstructure:"app"`
TemplateStorageConfig StorageConfig `mapstructure:"template_storage"`
FileStorageConfig StorageConfig `mapstructure:"file_storage"`
BrowserConfig BrowserConfig `mapstructure:"browser"`
WorkerPoolConfig WorkerPoolConfig `mapstructure:"workerpool"`
S3Config s3.Config `mapstructure:"s3"`
AWSConfig s3.AwsCredConfig `mapstructure:"aws"`
CertConfig map[string]CertConfig `mapstructure:"certificates"`
DBConfig DBConfig `mapstructure:"db"`
}

type AppConfig struct {
LogLevel string `mapstructure:"log_level"`
ServerPort int `mapstructure:"server_port"`
EnableUI bool `mapstructure:"enable_ui"`
RodBrowserBin string `mapstructure:"rod_browser_bin"`
}

type StorageConfig struct {
StorageType string `mapstructure:"storage_type"`
}

type BrowserConfig struct {
TabPool int `mapstructure:"tab_pool"`
}

type WorkerPoolConfig struct {
WorkerCount int `mapstructure:"worker_count"`
WorkerTimeoutMs int `mapstructure:"worker_timeout_ms"`
}

type CertConfig struct {
CertPath string `mapstructure:"cert_path"`
KeyPath string `mapstructure:"key_path"`
KeyPassword string `mapstructure:"key_password"`
}

type DBConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
Database string `mapstructure:"database"`
}
17 changes: 15 additions & 2 deletions service/utils/zerolog.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,22 @@ type ZeroLog struct {
logger zerolog.Logger
}

func NewZeroLogger() ZeroLog {
func NewZeroLogger(level string) ZeroLog {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339})
zerolog.SetGlobalLevel(zerolog.DebugLevel)
// zerolog.SetGlobalLevel(zerolog.DebugLevel)

switch level {
case "debug":
zerolog.SetGlobalLevel(zerolog.DebugLevel)
case "info":
zerolog.SetGlobalLevel(zerolog.InfoLevel)
case "warn":
zerolog.SetGlobalLevel(zerolog.WarnLevel)
case "error":
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
default:
zerolog.SetGlobalLevel(zerolog.InfoLevel)
}

return ZeroLog{
logger: log.Logger,
Expand Down