@@ -12,6 +12,7 @@ import (
1212 unary "github.com/achannarasappa/ticker/v4/internal/monitor/yahoo/unary"
1313)
1414
15+ // MonitorYahoo represents a Yahoo Finance monitor
1516type MonitorYahoo struct {
1617 unaryAPI * unary.UnaryAPI
1718 poller * poller.Poller
@@ -31,6 +32,7 @@ type MonitorYahoo struct {
3132 onUpdateAssetQuotes func (assetQuotes []c.AssetQuote )
3233}
3334
35+ // input represents user input for the Yahoo monitor with any transformation
3436type input struct {
3537 productIds []string
3638 productIdsLookup map [string ]bool
@@ -84,16 +86,20 @@ func WithRefreshInterval(interval time.Duration) Option {
8486 }
8587}
8688
87- // SetOnUpdate sets the onUpdate function for the monitor
89+ // SetOnUpdate sets the callback function for when a single asset quote is updated
8890func (m * MonitorYahoo ) SetOnUpdateAssetQuote (onUpdate func (symbol string , assetQuote c.AssetQuote )) {
8991 m .onUpdateAssetQuote = onUpdate
9092}
9193
94+ // SetOnUpdateAssetQuotes sets the callback function for when all asset quotes are updated i.e. when monitored symbols are replaced with new symbols
9295func (m * MonitorYahoo ) SetOnUpdateAssetQuotes (onUpdate func (assetQuotes []c.AssetQuote )) {
9396 m .onUpdateAssetQuotes = onUpdate
9497}
9598
99+ // GetAssetQuotes returns the asset quotes either from the cache or from the unary API if ignoreCache is set
96100func (m * MonitorYahoo ) GetAssetQuotes (ignoreCache ... bool ) ([]c.AssetQuote , error ) {
101+
102+ // If ignoreCache is set, get the asset quotes from the unary API and update the cache
97103 if len (ignoreCache ) > 0 && ignoreCache [0 ] {
98104 assetQuotes , err := m .getAssetQuotesAndReplaceCache ()
99105 if err != nil {
@@ -102,12 +108,14 @@ func (m *MonitorYahoo) GetAssetQuotes(ignoreCache ...bool) ([]c.AssetQuote, erro
102108 return assetQuotes , nil
103109 }
104110
111+ // If ignoreCache is not set, return the asset quotes from the cache without making a HTTP request
105112 m .mu .RLock ()
106113 defer m .mu .RUnlock ()
107114
108115 return m .assetQuotesCache , nil
109116}
110117
118+ // SetSymbols sets the symbols to monitor
111119func (m * MonitorYahoo ) SetSymbols (productIds []string ) error {
112120
113121 var err error
@@ -126,13 +134,16 @@ func (m *MonitorYahoo) SetSymbols(productIds []string) error {
126134
127135 m .mu .Unlock ()
128136
137+ // Since the symbols have changed, make a synchronous call to get price quotes for the new symbols
129138 _ , err = m .getAssetQuotesAndReplaceCache ()
130139 if err != nil {
131140 return err
132141 }
133142
143+ // Set the symbols to monitor on the poller
134144 m .poller .SetSymbols (m .productIdsPolling )
135145
146+ // Call the callback function for when all asset quotes are updated
136147 m .onUpdateAssetQuotes (m .assetQuotesCache )
137148
138149 return nil
@@ -154,18 +165,21 @@ func (m *MonitorYahoo) Start() error {
154165 return err
155166 }
156167
168+ // Start polling for price quotes
157169 err = m .poller .Start ()
158170 if err != nil {
159171 return err
160172 }
161173
174+ // Start listening for price quote updates
162175 go m .handleUpdates ()
163176
164177 m .isStarted = true
165178
166179 return nil
167180}
168181
182+ // Stop the monitor
169183func (m * MonitorYahoo ) Stop () error {
170184
171185 if ! m .isStarted {
@@ -176,6 +190,7 @@ func (m *MonitorYahoo) Stop() error {
176190 return nil
177191}
178192
193+ // handleUpdates listens for asset quote change messages and updates the cache
179194func (m * MonitorYahoo ) handleUpdates () {
180195 for {
181196 select {
@@ -188,8 +203,8 @@ func (m *MonitorYahoo) handleUpdates() {
188203
189204 assetQuote , exists := m .assetQuotesCacheLookup [updateMessage .ID ]
190205
206+ // If product id does not exist in cache, skip update (this would happen if the API returns a price for a symbol that was not requested)
191207 if ! exists {
192- // If product id does not exist in cache, skip update
193208 // TODO: log product not found in cache - should not happen
194209 m .mu .RUnlock ()
195210 continue
@@ -208,6 +223,7 @@ func (m *MonitorYahoo) handleUpdates() {
208223 // Price is different so update cache
209224 m .mu .Lock ()
210225
226+ // Update properties on the asset quote which may have changed
211227 assetQuote .QuotePrice .Price = updateMessage .Data .QuotePrice .Price
212228 assetQuote .QuotePrice .Change = updateMessage .Data .QuotePrice .Change
213229 assetQuote .QuotePrice .ChangePercent = updateMessage .Data .QuotePrice .ChangePercent
@@ -224,6 +240,7 @@ func (m *MonitorYahoo) handleUpdates() {
224240
225241 m .mu .Unlock ()
226242
243+ // Call the callback function for when a single asset quote is updated
227244 m .onUpdateAssetQuote (assetQuote .Symbol , * assetQuote )
228245
229246 continue
@@ -236,23 +253,17 @@ func (m *MonitorYahoo) handleUpdates() {
236253// Get asset quotes from unary API, add futures quotes, filter out assets not explicitly requested, and replace the asset quotes cache
237254func (m * MonitorYahoo ) getAssetQuotesAndReplaceCache () ([]c.AssetQuote , error ) {
238255
256+ // Make a synchronous call to get price quotes
239257 assetQuotes , assetQuotesByProductId , err := m .unaryAPI .GetAssetQuotes (m .productIds )
240258 if err != nil {
241259 return []c.AssetQuote {}, err
242260 }
243261
244- // Filter asset quotes to only include explicitly requested ones
245- assetQuotesEnriched := make ([]c.AssetQuote , 0 , len (m .input .productIds ))
246-
247- for _ , quote := range assetQuotes {
248- assetQuotesEnriched = append (assetQuotesEnriched , quote )
249- }
250-
251- // Lock updates to asset quotes while symbols are changed and subscriptions updates. ensure data from unary call supercedes potentially oudated streaming data
262+ // Replace the cache with new sets of asset quotes
252263 m .mu .Lock ()
253264 defer m .mu .Unlock ()
254265
255- m .assetQuotesCache = assetQuotesEnriched
266+ m .assetQuotesCache = assetQuotes
256267 m .assetQuotesCacheLookup = assetQuotesByProductId
257268
258269 return m .assetQuotesCache , nil
0 commit comments