package services import ( "encoding/json" "fmt" "os" "path/filepath" "sync" ) // WatchlistItem 관심종목 항목 type WatchlistItem struct { Code string `json:"code"` Name string `json:"name"` } // WatchlistService 관심종목 JSON 파일 CRUD type WatchlistService struct { mu sync.RWMutex path string list []WatchlistItem } var watchlistServiceInstance *WatchlistService var watchlistServiceOnce sync.Once // GetWatchlistService 관심종목 서비스 싱글톤 반환 func GetWatchlistService() *WatchlistService { watchlistServiceOnce.Do(func() { watchlistServiceInstance = NewWatchlistService("data/watchlist.json") }) return watchlistServiceInstance } // NewWatchlistService 관심종목 서비스 초기화 (파일 로드) func NewWatchlistService(path string) *WatchlistService { svc := &WatchlistService{path: path} svc.load() return svc } // GetAll 전체 관심종목 반환 func (s *WatchlistService) GetAll() []WatchlistItem { s.mu.RLock() defer s.mu.RUnlock() result := make([]WatchlistItem, len(s.list)) copy(result, s.list) return result } // Add 관심종목 추가 (중복 방지) func (s *WatchlistService) Add(code, name string) error { s.mu.Lock() defer s.mu.Unlock() for _, item := range s.list { if item.Code == code { return fmt.Errorf("이미 추가된 종목입니다: %s", code) } } s.list = append(s.list, WatchlistItem{Code: code, Name: name}) return s.save() } // Remove 관심종목 삭제 func (s *WatchlistService) Remove(code string) error { s.mu.Lock() defer s.mu.Unlock() newList := make([]WatchlistItem, 0, len(s.list)) for _, item := range s.list { if item.Code != code { newList = append(newList, item) } } s.list = newList return s.save() } // load 파일에서 관심종목 로드 (파일 없으면 빈 배열 초기화) func (s *WatchlistService) load() { data, err := os.ReadFile(s.path) if err != nil { s.list = []WatchlistItem{} return } if err := json.Unmarshal(data, &s.list); err != nil { s.list = []WatchlistItem{} } } // save 관심종목을 JSON 파일에 저장 (내부용) func (s *WatchlistService) save() error { // data/ 디렉토리 자동 생성 if err := os.MkdirAll(filepath.Dir(s.path), 0o755); err != nil { return err } data, err := json.MarshalIndent(s.list, "", " ") if err != nil { return err } return os.WriteFile(s.path, data, 0o644) }