Skip to content

Commit

Permalink
Sync sqlite database to google drive
Browse files Browse the repository at this point in the history
Signed-off-by: Masudur Rahman <[email protected]>
  • Loading branch information
masudur-rahman committed Feb 23, 2024
1 parent fda0aa5 commit 9756a52
Show file tree
Hide file tree
Showing 276 changed files with 64,802 additions and 182 deletions.
30 changes: 30 additions & 0 deletions cmd/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package cmd

import (
"log"
"os"
"path/filepath"

"github.com/masudur-rahman/expense-tracker-bot/configs"
"github.com/masudur-rahman/expense-tracker-bot/pkg"

"gopkg.in/yaml.v3"
)

var cfgFile string

// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile == "" {
cfgFile = filepath.Join(pkg.ProjectDirectory, "configs", ".expense-tracker.yaml")
}

data, err := os.ReadFile(cfgFile)
if err != nil {
log.Fatalf("Reading config file %v, %v", cfgFile, err)
}

if err = yaml.Unmarshal(data, &configs.TrackerConfig); err != nil {
log.Fatalf("Unmarshaling PurrfectConfig, %v", err)
}
}
2 changes: 2 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ func Execute() {
}

func init() {
cobra.OnInitialize(initConfig)
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.

rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is ./configs/.expense-tracker.yaml)")
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.expense-tracker-bot.yaml)")

// Cobra also supports local flags, which will only run
Expand Down
154 changes: 11 additions & 143 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ limitations under the License.
package cmd

import (
"context"
"database/sql"
"io"
"log"
"net/http"
Expand All @@ -27,15 +25,9 @@ import (
"path"
"time"

isql "github.com/masudur-rahman/database/sql"
"github.com/masudur-rahman/database/sql/postgres"
"github.com/masudur-rahman/database/sql/postgres/lib"
"github.com/masudur-rahman/database/sql/sqlite"
sqlib "github.com/masudur-rahman/database/sql/sqlite/lib"
"github.com/masudur-rahman/expense-tracker-bot/api"
"github.com/masudur-rahman/expense-tracker-bot/configs"
"github.com/masudur-rahman/expense-tracker-bot/infra/logr"
"github.com/masudur-rahman/expense-tracker-bot/models"
"github.com/masudur-rahman/expense-tracker-bot/services/all"

"github.com/spf13/cobra"
)
Expand All @@ -51,9 +43,7 @@ Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
go startHealthz()

if err := getServicesForSqlite(cmd.Context()); err != nil {
if err := configs.InitiateDatabaseConnection(cmd.Context()); err != nil {
log.Fatalln(err)
}

Expand All @@ -62,6 +52,7 @@ to quickly create a Cobra application.`,
log.Fatalln(err)
}

go startHealthz()
go pingHealthzApiPeriodically()
log.Println("Expense Tracker Bot started")
bot.Start()
Expand All @@ -72,89 +63,6 @@ func init() {
rootCmd.AddCommand(serveCmd)
}

func startHealthz() {
mux := http.NewServeMux()
mux.HandleFunc("/healthz", func(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(http.StatusOK)
writer.Write([]byte("Running"))
})

logr.DefaultLogger.Infow("Health checker started at :8080/healthz")
log.Fatalln(http.ListenAndServe(":8080", mux))
}

//func getServicesForSupabase(ctx context.Context) *all.Services {
// supClient := supabase.InitializeSupabase(ctx)
//
// var db isql.Database
// db = supabase.NewSupabase(ctx, supClient)
// logger := logr.DefaultLogger
// return all.InitiateSQLServices(db, logger)
//}

func getServicesForPostgres(ctx context.Context) error {
cfg := parsePostgresConfig()

err := initiatePostgresQLServices(ctx, cfg)
if err != nil {
return err
}

return all.GetServices().Txn.UpdateTxnCategories()
}

func getServicesForSqlite(ctx context.Context) error {
conn, err := sqlib.GetSQLiteConnection("expense-tracker.db")
if err != nil {
return err
}

db := sqlite.NewSqlite(ctx, conn)
syncTables(db)

logger := logr.DefaultLogger
all.InitiateSQLServices(db, logger)

return all.GetServices().Txn.UpdateTxnCategories()
}

func initiatePostgresQLServices(ctx context.Context, cfg lib.PostgresConfig) error {
conn, err := lib.GetPostgresConnection(cfg)
if err != nil {
return err
}

db := postgres.NewPostgres(ctx, conn).ShowSQL(true)
syncTables(db)

logger := logr.DefaultLogger
all.InitiateSQLServices(db, logger)

go pingPostgresDatabasePeriodically(ctx, cfg, conn, logger)

return nil
}

func pingPostgresDatabasePeriodically(ctx context.Context, cfg lib.PostgresConfig, conn *sql.Conn, logger logr.Logger) {
t5 := time.NewTicker(5 * time.Minute)
for {
select {
case <-t5.C:
if err := conn.PingContext(ctx); err != nil {
logger.Errorw("Database connection closed", "error", err.Error())
conn, err = lib.GetPostgresConnection(cfg)
if err != nil {
logger.Errorw("couldn't create database connection", "error", err.Error())
}

db := postgres.NewPostgres(ctx, conn).ShowSQL(true)
all.InitiateSQLServices(db, logger)
logger.Infow("New connection established")
}
}
}
}

func pingHealthzApiPeriodically() {
logger := logr.DefaultLogger
baseURL, ok := os.LookupEnv("BASE_URL")
Expand Down Expand Up @@ -189,53 +97,13 @@ func pingHealthzApiPeriodically() {
}
}

func parsePostgresConfig() lib.PostgresConfig {
cfg := lib.PostgresConfig{
Name: "expense",
Host: "localhost",
Port: "5432",
User: "postgres",
Password: "postgres",
SSLMode: "disable",
}

user, ok := os.LookupEnv("POSTGRES_USER")
if ok {
cfg.User = user
}
pass, ok := os.LookupEnv("POSTGRES_PASSWORD")
if ok {
cfg.Password = pass
}
name, ok := os.LookupEnv("POSTGRES_DB")
if ok {
cfg.Name = name
}
host, ok := os.LookupEnv("POSTGRES_HOST")
if ok {
cfg.Host = host
}
port, ok := os.LookupEnv("POSTGRES_PORT")
if ok {
cfg.Port = port
}
ssl, ok := os.LookupEnv("POSTGRES_SSL_MODE")
if ok {
cfg.SSLMode = ssl
}
return cfg
}
func startHealthz() {
mux := http.NewServeMux()
mux.HandleFunc("/healthz", func(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(http.StatusOK)
writer.Write([]byte("Running"))
})

func syncTables(db isql.Database) {
err := db.Sync(
models.User{},
models.Account{},
models.Transaction{},
models.TxnCategory{},
models.TxnSubcategory{},
models.Event{},
)
if err != nil {
log.Fatalln(err)
}
logr.DefaultLogger.Infow("Health checker started at :8080/healthz")
log.Fatalln(http.ListenAndServe(":8080", mux))
}
11 changes: 11 additions & 0 deletions configs/.expense-tracker.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
database:
type: sqlite
sqlite:
syncToDrive: true
# postgres:
# name: expense
# host: localhost
# port: 5432
# user: postgres
# password: postgres
# sslmode: disable
52 changes: 22 additions & 30 deletions configs/config.go
Original file line number Diff line number Diff line change
@@ -1,39 +1,34 @@
package configs

import "fmt"
import (
"fmt"
"time"

var PurrfectConfig PawsitiveConfiguration
"github.com/masudur-rahman/database/sql/postgres/lib"
)

type PawsitiveConfiguration struct {
Server ServerConfig `json:"server" yaml:"server"`
GRPC GRPCConfig `json:"grpc" yaml:"grpc"`
Database DatabaseConfig `json:"database" yaml:"database"`
Session SessionConfig `json:"session" yaml:"session"`
}
var TrackerConfig ExpenseConfiguration

type ServerConfig struct {
Host string `json:"host" yaml:"host"`
Port int `json:"port" yaml:"port"`
Domain string `json:"domain" yaml:"domain"`
}

type GRPCConfig struct {
ServerHost string `json:"serverHost" yaml:"serverHost"`
ClientHost string `json:"clientHost" yaml:"clientHost"`
Port int `json:"port" yaml:"port"`
type ExpenseConfiguration struct {
TelegramSecret string `json:"telegramSecret" yaml:"telegramSecret"`
Database DatabaseConfig `json:"database" yaml:"database"`
}

type DatabaseConfig struct {
Type DatabaseType `json:"type" yaml:"type"`
ArangoDB DBConfigArangoDB `json:"arangodb" yaml:"arangodb"`
Postgres DBConfigPostgres `json:"postgres" yaml:"postgres"`
Type DatabaseType `json:"type" yaml:"type"`

//ArangoDB DBConfigArangoDB `json:"arangodb" yaml:"arangodb"`
Postgres lib.PostgresConfig `json:"postgres" yaml:"postgres"`
Sqlite DBConfigSqlite `json:"sqlite" yaml:"sqlite"`
}

type DatabaseType string

const (
DatabaseArangoDB DatabaseType = "arangodb"
DatabasePostgres DatabaseType = "postgres"
DatabaseSqlite DatabaseType = "sqlite"
DatabaseSupabase DatabaseType = "supabase"
)

type DBConfigArangoDB struct {
Expand All @@ -53,15 +48,12 @@ type DBConfigPostgres struct {
SSLMode string `json:"sslmode" yaml:"sslmode"`
}

func (cp DBConfigPostgres) String() string {
return fmt.Sprintf("user=%v password=%v dbname=%v host=%v port=%v sslmode=%v", cp.User, cp.Password, cp.Name, cp.Host, cp.Port, cp.SSLMode)
type DBConfigSqlite struct {
SyncToDrive bool `json:"syncToDrive" yaml:"syncToDrive"`
DisableSyncFromDrive bool `json:"disableSyncFromDrive" yaml:"disableSyncFromDrive"`
SyncInterval time.Duration `json:"syncInterval" yaml:"syncInterval"`
}

type SessionConfig struct {
Name string `json:"name" yaml:"name"`
HttpOnly bool `json:"httpOnly" yaml:"httpOnly"`
CSRFSecret string `json:"csrfSecret" yaml:"csrfSecret"`
CSRFHeader string `json:"csrfHeader" yaml:"csrfHeader"`
CSRFForm string `json:"csrfForm" yaml:"csrfForm"`
SessionKey string `json:"sessionKey" yaml:"sessionKey"`
func (cp DBConfigPostgres) String() string {
return fmt.Sprintf("user=%v password=%v dbname=%v host=%v port=%v sslmode=%v", cp.User, cp.Password, cp.Name, cp.Host, cp.Port, cp.SSLMode)
}
Loading

0 comments on commit 9756a52

Please sign in to comment.