[ci skip] Flatten module wrappers into stack roots
Remove the module "xxx" { source = "./module" } indirection layer
from all 66 service stacks. Resources are now defined directly in
each stack's main.tf instead of through a wrapper module.
- Merge module/main.tf contents into stack main.tf
- Apply variable replacements (var.tier -> local.tiers.X, renamed vars)
- Fix shared module paths (one fewer ../ at each level)
- Move extra files/dirs (factory/, chart_values, subdirs) to stack root
- Update state files to strip module.<name>. prefix
- Update CLAUDE.md to reflect flat structure
Verified: terragrunt plan shows 0 add, 0 destroy across all stacks.
This commit is contained in:
parent
b0499a7f31
commit
c7c7047f1c
245 changed files with 11733 additions and 12432 deletions
176
stacks/f1-stream/files/internal/store/streams.go
Normal file
176
stacks/f1-stream/files/internal/store/streams.go
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"f1-stream/internal/models"
|
||||
)
|
||||
|
||||
func (s *Store) LoadStreams() ([]models.Stream, error) {
|
||||
s.streamsMu.RLock()
|
||||
defer s.streamsMu.RUnlock()
|
||||
var streams []models.Stream
|
||||
if err := readJSON(s.filePath("streams.json"), &streams); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return streams, nil
|
||||
}
|
||||
|
||||
func (s *Store) PublicStreams() ([]models.Stream, error) {
|
||||
s.streamsMu.RLock()
|
||||
defer s.streamsMu.RUnlock()
|
||||
var streams []models.Stream
|
||||
if err := readJSON(s.filePath("streams.json"), &streams); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
healthMap := s.HealthMap()
|
||||
var pub []models.Stream
|
||||
for _, st := range streams {
|
||||
if !st.Published {
|
||||
continue
|
||||
}
|
||||
// Filter unhealthy streams. URLs not in healthMap are assumed healthy (new/unchecked).
|
||||
if healthy, exists := healthMap[st.URL]; exists && !healthy {
|
||||
continue
|
||||
}
|
||||
pub = append(pub, st)
|
||||
}
|
||||
return pub, nil
|
||||
}
|
||||
|
||||
func (s *Store) UserStreams(userID string) ([]models.Stream, error) {
|
||||
s.streamsMu.RLock()
|
||||
defer s.streamsMu.RUnlock()
|
||||
var streams []models.Stream
|
||||
if err := readJSON(s.filePath("streams.json"), &streams); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result []models.Stream
|
||||
for _, st := range streams {
|
||||
if st.SubmittedBy == userID {
|
||||
result = append(result, st)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Store) AddStream(url, title, submittedBy string, published bool, source string) (models.Stream, error) {
|
||||
s.streamsMu.Lock()
|
||||
defer s.streamsMu.Unlock()
|
||||
var streams []models.Stream
|
||||
if err := readJSON(s.filePath("streams.json"), &streams); err != nil {
|
||||
return models.Stream{}, err
|
||||
}
|
||||
id, err := randomID()
|
||||
if err != nil {
|
||||
return models.Stream{}, err
|
||||
}
|
||||
st := models.Stream{
|
||||
ID: id,
|
||||
URL: url,
|
||||
Title: title,
|
||||
SubmittedBy: submittedBy,
|
||||
Published: published,
|
||||
Source: source,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
streams = append(streams, st)
|
||||
if err := writeJSON(s.filePath("streams.json"), streams); err != nil {
|
||||
return models.Stream{}, err
|
||||
}
|
||||
return st, nil
|
||||
}
|
||||
|
||||
func (s *Store) PublishScrapedStream(url, title string) error {
|
||||
s.streamsMu.Lock()
|
||||
defer s.streamsMu.Unlock()
|
||||
var streams []models.Stream
|
||||
if err := readJSON(s.filePath("streams.json"), &streams); err != nil {
|
||||
return err
|
||||
}
|
||||
// Deduplicate: skip if URL already exists in streams
|
||||
for _, st := range streams {
|
||||
if st.URL == url {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
id, err := randomID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
streams = append(streams, models.Stream{
|
||||
ID: id,
|
||||
URL: url,
|
||||
Title: title,
|
||||
SubmittedBy: "scraper",
|
||||
Published: true,
|
||||
Source: "scraped",
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
return writeJSON(s.filePath("streams.json"), streams)
|
||||
}
|
||||
|
||||
func (s *Store) DeleteStream(id, userID string, isAdmin bool) error {
|
||||
s.streamsMu.Lock()
|
||||
defer s.streamsMu.Unlock()
|
||||
var streams []models.Stream
|
||||
if err := readJSON(s.filePath("streams.json"), &streams); err != nil {
|
||||
return err
|
||||
}
|
||||
var updated []models.Stream
|
||||
found := false
|
||||
for _, st := range streams {
|
||||
if st.ID == id {
|
||||
if userID != "" && !isAdmin && st.SubmittedBy != userID {
|
||||
return fmt.Errorf("not authorized")
|
||||
}
|
||||
found = true
|
||||
continue
|
||||
}
|
||||
updated = append(updated, st)
|
||||
}
|
||||
if !found {
|
||||
return fmt.Errorf("stream not found")
|
||||
}
|
||||
return writeJSON(s.filePath("streams.json"), updated)
|
||||
}
|
||||
|
||||
func (s *Store) TogglePublish(id string) error {
|
||||
s.streamsMu.Lock()
|
||||
defer s.streamsMu.Unlock()
|
||||
var streams []models.Stream
|
||||
if err := readJSON(s.filePath("streams.json"), &streams); err != nil {
|
||||
return err
|
||||
}
|
||||
for i, st := range streams {
|
||||
if st.ID == id {
|
||||
streams[i].Published = !st.Published
|
||||
return writeJSON(s.filePath("streams.json"), streams)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("stream not found")
|
||||
}
|
||||
|
||||
func (s *Store) SeedStreams(defaults []models.Stream) error {
|
||||
s.streamsMu.Lock()
|
||||
defer s.streamsMu.Unlock()
|
||||
var existing []models.Stream
|
||||
if err := readJSON(s.filePath("streams.json"), &existing); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(existing) > 0 {
|
||||
return nil
|
||||
}
|
||||
return writeJSON(s.filePath("streams.json"), defaults)
|
||||
}
|
||||
|
||||
func randomID() (string, error) {
|
||||
b := make([]byte, 16)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(b), nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue