Skip to content

Commit

Permalink
add support for db
Browse files Browse the repository at this point in the history
  • Loading branch information
Eslam-Nawara committed May 8, 2024
1 parent 5c1b55b commit b27622d
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 16 deletions.
31 changes: 21 additions & 10 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package cmd

import (
"os"
"path/filepath"

"github.com/codescalers/statusbot/internal"
"github.com/codescalers/statusbot/internal/bot"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
Expand All @@ -20,26 +21,35 @@ var rootCmd = &cobra.Command{

token, err := cmd.Flags().GetString("bot-token")
if err != nil || token == "" {
log.Error().Err(err).Msg("error in token")
return
log.Fatal().Err(err).Msg("error in token")
}

time, err := cmd.Flags().GetString("time")
if err != nil || time == "" {
log.Error().Err(err).Msg("error in time")
return
log.Fatal().Err(err).Msg("error in time")
}

timezone, err := cmd.Flags().GetString("timezone")
if err != nil || timezone == "" {
log.Error().Err(err).Msg("error in timezone")
return
log.Fatal().Err(err).Msg("error in timezone")
}

bot, err := internal.NewBot(token, time, timezone)
db, err := cmd.Flags().GetString("database")
if err != nil {
log.Error().Err(err).Msg("failed to create bot")
return
log.Fatal().Err(err).Msg("error in database")
}

if db == "" {
defaultPath, err := os.Getwd()
if err != nil {
log.Fatal().Err(err).Send()
}
db = filepath.Join(defaultPath, "db")
}

bot, err := internal.NewBot(token, time, timezone, db)
if err != nil {
log.Fatal().Err(err).Msg("failed to create bot")
}

bot.Start()
Expand All @@ -57,4 +67,5 @@ func init() {
rootCmd.Flags().StringP("bot-token", "b", "", "Enter a valid telegram bot token")
rootCmd.Flags().StringP("time", "t", "17:00", "Enter a valid time")
rootCmd.Flags().StringP("timezone", "z", "Africa/Cairo", "Enter a valid timezone")
rootCmd.Flags().StringP("database", "d", "", "Enter path to store chats info")
}
26 changes: 20 additions & 6 deletions internal/bot.go → internal/bot/bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"
_ "time/tzdata"

database "github.com/codescalers/statusbot/internal/db"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"github.com/rs/zerolog/log"
)
Expand All @@ -18,10 +19,11 @@ type Bot struct {
removeChan chan int64
time time.Time
location *time.Location
db database.DB
}

// NewBot creates new bot with a valid bot api and communication channels
func NewBot(token string, inputTime string, timezone string) (Bot, error) {
func NewBot(token, inputTime, timezone, dbPath string) (Bot, error) {
bot := Bot{}

botAPI, err := tgbotapi.NewBotAPI(token)
Expand All @@ -44,11 +46,17 @@ func NewBot(token string, inputTime string, timezone string) (Bot, error) {

log.Printf("notfications is set to %s", parsedTime)

db, err := database.NewDB(dbPath)
if err != nil {
return bot, err
}

bot.location = loc
bot.botAPI = *botAPI
bot.time = parsedTime
bot.addChan = make(chan int64)
bot.removeChan = make(chan int64)
bot.db = db

return bot, nil
}
Expand Down Expand Up @@ -88,7 +96,6 @@ func (bot Bot) Start() {
}

func (bot Bot) runBot() {
chatIDs := make(map[int64]bool)
weekends := []time.Weekday{time.Friday, time.Saturday}

// set ticker every day at 12:00 to update time with location in case of new changes in timezone.
Expand All @@ -98,10 +105,10 @@ func (bot Bot) runBot() {
for {
select {
case chatID := <-bot.addChan:
chatIDs[chatID] = true
bot.db.Update(chatID, database.ChatInfo{ChatID: chatID})

case chatID := <-bot.removeChan:
delete(chatIDs, chatID)
bot.db.Delete(chatID)

case <-updateTicker.C:
// parse the time with location again to make sure the timezone is always up to date
Expand All @@ -114,16 +121,23 @@ func (bot Bot) runBot() {
updateTicker.Reset(24 * time.Hour)

case <-reminderTicker.C:
chats := bot.db.List()

// skip weekends
if !slices.Contains(weekends, bot.time.Weekday()) {
for chatID := range chatIDs {
bot.sendReminder(chatID)
for _, chat := range chats {
bot.sendReminder(chat.ChatID)
}
}

bot.time = bot.time.AddDate(0, 0, 1)
reminderTicker.Reset(24 * time.Hour)
log.Printf("next notfications is set to %s", bot.time)
}

if err := bot.db.Save(); err != nil {
log.Fatal().Err(err).Msg("failed to save updates to db")
}
}
}

Expand Down
84 changes: 84 additions & 0 deletions internal/db/db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package db

import (
"encoding/json"
"os"
"path/filepath"
)

type ChatInfo struct {
ChatID int64
}

type DB struct {
path string
chatsIDs map[int64]ChatInfo
}

// NewDB open and load db if exist, or create new one if not exist
func NewDB(path string) (DB, error) {
if err := os.MkdirAll(path, 0777); err != nil {
return DB{}, err
}

chatsIDs := make(map[int64]ChatInfo)
path = filepath.Join(path, "db.json")

data, err := os.ReadFile(path)
if os.IsNotExist(err) || len(data) == 0 {
return DB{
path: path,
chatsIDs: chatsIDs,
}, nil
}
if err != nil {
return DB{}, err
}

if err := json.Unmarshal(data, &chatsIDs); err != nil {
return DB{}, err
}

return DB{
path: path,
chatsIDs: chatsIDs,
}, nil
}

func (db *DB) Save() error {
file, err := json.MarshalIndent(db.chatsIDs, "", " ")
if err != nil {
return err
}

err = os.WriteFile(db.path, file, 0777)
if err != nil {
return err
}

return nil
}

func (db *DB) Get(key int64) ChatInfo {
val, ok := db.chatsIDs[key]
if !ok {
return ChatInfo{}
}
return val
}

func (db *DB) Update(key int64, value ChatInfo) {
db.chatsIDs[key] = value
}

func (db *DB) Delete(key int64) {
delete(db.chatsIDs, key)
}

func (db *DB) List() []ChatInfo {
chatsInfo := make([]ChatInfo, 0, len(db.chatsIDs))
for _, val := range db.chatsIDs {
chatsInfo = append(chatsInfo, val)
}
return chatsInfo
}

0 comments on commit b27622d

Please sign in to comment.