view Stocks/Stocks.Service/StocksService.cs @ 4:57f20ba55884

Fix for webClientShim to use downloadString instead of downloadData Refactoring and introduction of static TimedDelegates.Execute() helper method
author stevenh7776 stevenhollidge@hotmail.com
date Mon, 20 Feb 2012 23:04:58 +0700
parents 29ed98d659e9
children c812bca7b1ac
line wrap: on
line source

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using NLog;
using Stocks.Common;
using Stocks.Common.Events;
using Stocks.Common.Models;
using Stocks.Common.Core;

namespace Stocks.Service
{ 
  public class StocksService : IStocksService
  {
    private static readonly Logger Log = LogManager.GetCurrentClassLogger();

    private IList<Company> _companies;
    private IConfigurationService _configurationService;
    private List<Price> _currentPrices;
    private string _serviceUrl;
    private IWebClientShim _webClient;

    public bool IsActive { get; private set; }
    public SummaryStats Stats { get; private set; }

    public StocksService(
      IConfigurationService configurationService,
      IWebClientShim webClientShim)
    {
      new AssemblyInit();

      _webClient = webClientShim;
      _configurationService = configurationService;
      Stats = new SummaryStats();

      GetCompanyList();
    }

    private void GetCompanyList()
    {
      _companies = _configurationService.GetCompanies();

      string symbolsCsv = _companies.Select(
        c => c.Symbol).Aggregate((c, d) => c + "," + d);
      _serviceUrl = _configurationService.GetServiceUrl(symbolsCsv);
    }

    public delegate void PriceChangedEventHandler(object sender, PriceChangedEventArgs e);
    public event PriceChangedEventHandler PriceChanged;
    protected virtual void RaisePriceChanged(Price price)
    {
      Stats.PriceChangeEvents++;

      if (PriceChanged != null)
        PriceChanged(this, new PriceChangedEventArgs() { Price = price });
    }

    public void Start()
    {
      PrepareForServiceStarting();
      Task.Factory.StartNew(() => DownloadPrices());
    }

    public void Stop()
    {
      IsActive = false;
      Log.Debug("StockService stopped");
    }

    private void PrepareForServiceStarting()
    {
      Log.Debug("StockService starting");
      IsActive = true;
      Stats.Reset();
      _currentPrices = new List<Price>(_companies.Count);
    }

    private void DownloadPrices()
    {
      try
      {
        Stopwatch timeToDownload;

        while (IsActive)
        {
          string webResponse = TimedDelegates.Execute<string>(
            _webClient.DownloadString,
            _serviceUrl,
            out timeToDownload);

          PopulatePricesFromWebResponse(webResponse);
          UpdateStats(timeToDownload, webResponse);
        }
      }
      catch (Exception e)
      {
        Log.Error("Exception during DownloadPrices()");
        Log.Error("Stack Trace {0}: /r/nException Message: {1}", e.StackTrace, e.Message);
        this.Stop();
      }
    }

    private void PopulatePricesFromWebResponse(string webResponse)
    {
      string[] webPrices = webResponse.Split(
        new string[] { "\n", "\r\n" },
        StringSplitOptions.RemoveEmptyEntries);

      foreach (string webPriceData in webPrices)
      {
        var webPrice = Factory.CreatePrice(webPriceData);
        var localPrice = _currentPrices.Find(x => x.Symbol == webPrice.Symbol);

        if (localPrice == null) {
          _currentPrices.Add(new Price(webPrice.Symbol, webPrice.CurrentPrice, webPrice.PreviousPrice));
          continue;
        }

        if (localPrice.Equals(webPrice))
          continue;
        else
          UpdateLocalPrice(webPrice, localPrice);
      }
    }

    private void UpdateLocalPrice(Price webPrice, Price localPrice)
    {
      localPrice.PreviousPrice = localPrice.CurrentPrice;
      localPrice.CurrentPrice = webPrice.CurrentPrice;
      RaisePriceChanged(localPrice);
    }

    private void UpdateStats(Stopwatch timeToDownload, string webResponse)
    {
      Stats.LastWebRequest.Duration = (int)timeToDownload.ElapsedMilliseconds;
      Stats.LastWebRequest.PricesDownloaded = _currentPrices.Count;
      Stats.LastWebRequest.Response = webResponse;
      Stats.LastWebRequest.Request = _serviceUrl;
      Stats.LastWebRequest.SymbolCount = _companies.Count;
      Stats.NumberOfRequests++;
      Log.Trace(Stats);
    }
  }
}