diff --git a/main.go b/main.go index 0217d46..45c9e9c 100644 --- a/main.go +++ b/main.go @@ -2,10 +2,12 @@ package main import ( "log" + "os" "strings" "time" "go-nostrss/nostr" + "go-nostrss/types" "go-nostrss/utils" "github.com/mmcdole/gofeed" @@ -22,23 +24,33 @@ func FetchRSSFeed(url string) ([]*gofeed.Item, error) { } func main() { - // Load configuration - config, err := utils.LoadConfig("config.yml") - if err != nil { - log.Fatalf("Error loading configuration: %v", err) + const configFileName = "config.yml" + + var config *types.Config + if _, err := os.Stat(configFileName); os.IsNotExist(err) { + log.Println("Configuration file not found. Starting setup wizard...") + var setupErr error + config, setupErr = utils.SetupConfig(configFileName) + if setupErr != nil { + log.Fatalf("Error setting up configuration: %v", setupErr) + } + } else { + var loadErr error + config, loadErr = utils.LoadConfig(configFileName) + if loadErr != nil { + log.Fatalf("Error loading configuration: %v", loadErr) + } } - // Load cache cache, err := utils.LoadCache(config.CacheFile) if err != nil { log.Fatalf("Error loading cache: %v", err) } - // Main loop ticker := time.NewTicker(time.Duration(config.FetchIntervalMins) * time.Minute) defer ticker.Stop() - for { + for range ticker.C { items, err := FetchRSSFeed(config.RSSFeed) if err != nil { log.Printf("Error fetching RSS feed: %v", err) @@ -47,25 +59,21 @@ func main() { for _, item := range items { cache.Mu.Lock() - alreadyPosted := cache.PostedLinks[item.Link] - cache.Mu.Unlock() - - if alreadyPosted { + if cache.PostedLinks[item.Link] { + cache.Mu.Unlock() continue } + cache.Mu.Unlock() - // Prepare event content content := strings.TrimSpace(item.Title) + "\n" + item.Link - // Use the article's publish time for the event's created_at field var createdAt int64 if item.PublishedParsed != nil { createdAt = item.PublishedParsed.Unix() } else { - createdAt = time.Now().Unix() // Fallback to current time if not available + createdAt = time.Now().Unix() } - // Create Nostr event with the article's publish time and content event, err := nostr.CreateNostrEvent(content, config.NostrPublicKey, createdAt) if err != nil { log.Printf("Error creating Nostr event: %v", err) @@ -89,7 +97,6 @@ func main() { if err != nil { log.Printf("Error saving cache: %v", err) } - - <-ticker.C } + } diff --git a/utils/cache.go b/utils/cache.go index d393d4f..8ef5912 100644 --- a/utils/cache.go +++ b/utils/cache.go @@ -40,10 +40,10 @@ func SaveCache(filename string, cache *types.Cache) error { log.Printf("Saving cache to file: %s", filename) cache.Mu.Lock() - log.Println("Cache lock acquired for saving") + //log.Println("Cache lock acquired for saving") defer func() { cache.Mu.Unlock() - log.Println("Cache lock released after saving") + //log.Println("Cache lock released after saving") }() data, err := json.Marshal(cache) @@ -52,9 +52,6 @@ func SaveCache(filename string, cache *types.Cache) error { return fmt.Errorf("failed to serialize cache: %w", err) } - _ = os.Rename(filename, filename+".bak") // Optional backup - log.Println("Backup created for cache file") - err = os.WriteFile(filename, data, 0644) if err != nil { log.Printf("Error writing cache to file: %v", err) @@ -63,4 +60,4 @@ func SaveCache(filename string, cache *types.Cache) error { log.Println("Cache saved successfully") return nil -} \ No newline at end of file +} diff --git a/utils/wizard.go b/utils/wizard.go new file mode 100644 index 0000000..ce167dc --- /dev/null +++ b/utils/wizard.go @@ -0,0 +1,57 @@ +package utils + +import ( + "bufio" + "fmt" + "log" + "os" + "strconv" + "strings" + + "go-nostrss/types" + + "gopkg.in/yaml.v3" +) + +// PromptForInput prompts the user for input and returns the response +func PromptForInput(prompt string) string { + fmt.Print(prompt) + reader := bufio.NewReader(os.Stdin) + response, err := reader.ReadString('\n') + if err != nil { + log.Fatalf("Error reading input: %v", err) + } + return strings.TrimSpace(response) +} + +// PromptForInt prompts the user for an integer input with validation +func PromptForInt(prompt string) int { + for { + input := PromptForInput(prompt) + value, err := strconv.Atoi(input) + if err != nil || value <= 0 { + fmt.Println("Invalid input. Please enter a positive integer.") + continue + } + return value + } +} + +// SetupConfig initializes the configuration through user input +func SetupConfig(filename string) (*types.Config, error) { + var config types.Config + + config.RSSFeed = PromptForInput("Enter the URL of the RSS Feed: ") + config.NostrPrivateKey = PromptForInput("Enter your Private Key in Hex Format: ") + config.NostrPublicKey = PromptForInput("Enter your Public Key in Hex Format: ") + config.RelayURL = PromptForInput("Enter the Relay URL (e.g., wss://relay.example.com): ") + config.FetchIntervalMins = PromptForInt("Enter the Fetch Interval in minutes: ") + config.CacheFile = "posted_articles.json" // Default value + + data, err := yaml.Marshal(&config) + if err != nil { + return nil, err + } + err = os.WriteFile(filename, data, 0644) + return &config, err +}