using System; using System.Collections.Generic; using System.IO; using System.ServiceModel; using System.ComponentModel.Composition; using WindowsPhone.Recipes.Push.Server.Models; using System.Xml.Linq; namespace WindowsPhone.Recipes.Push.Server.Services { /// /// Current push server services implementation. /// [Export, PartCreationPolicy(CreationPolicy.Shared), ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] internal class PushService : IPushService { #region Fields private ServiceHost _serviceHost; /// Dictionary contains users subscription objects. private readonly Dictionary _subscribers = new Dictionary(); /// Sync access to the subscribers dictionary. private readonly object SubscribersSync = new object(); #endregion #region Events /// /// Raise when user subscribed. /// public event EventHandler Subscribed; /// /// Raise when current server status is requested. /// public event EventHandler GetInfo; /// /// Raise when user requests a tile update. /// public event EventHandler TileUpdateRequest; #endregion #region Properties /// /// Get subscription list. /// public IEnumerable Subscribers { get { lock (_subscribers) { var subscribers = new Subscription[_subscribers.Count]; _subscribers.Values.CopyTo(subscribers, 0); return subscribers; } } } /// /// Get subscription count. /// public int SubscribersCount { get { lock (_subscribers) { return _subscribers.Count; } } } #endregion #region Operations /// /// Register user with notification channel uri. /// /// The user name to register. /// The notification channel uri. public void Register(string userName, Uri channelUri) { if (string.IsNullOrEmpty(userName)) { throw new ArgumentException("Invalid user name", "userName"); } if (channelUri == null) { throw new ArgumentNullException("channelUri"); } var subscription = new Subscription(userName, channelUri); lock (SubscribersSync) { // Add or update existing. _subscribers[userName] = subscription; } OnSubscribed(new SubscriptionEventArgs(subscription)); } /// /// Gets current server info. /// /// An instance info object contains server status. public ServerInfo GetServerInfo() { var args = new ServerInfoEventArgs(); OnGetInfo(args); return args.ServerInfo; } /// /// Send a tile update with given parameter. /// /// An instance info object contains server status. /// User parameter to send with the tile update request. public void UpdateTile(Uri channelUri, string parameter) { OnTileUpdateRequest(new TileUpdateRequestEventArgs(channelUri, parameter)); } internal Subscription TryGetSubscription(string userName) { lock (SubscribersSync) { Subscription subscription; if (!_subscribers.TryGetValue(userName, out subscription)) { subscription = null; } return subscription; } } #endregion #region Privates Logic public void Host() { _serviceHost = new ServiceHost(this); _serviceHost.Open(); } private void OnSubscribed(SubscriptionEventArgs args) { if (Subscribed != null) { Subscribed(this, args); } } private void OnGetInfo(ServerInfoEventArgs args) { if (GetInfo != null) { GetInfo(this, args); } } private void OnTileUpdateRequest(TileUpdateRequestEventArgs args) { if (TileUpdateRequest != null) { TileUpdateRequest(this, args); } } #endregion } }