Skip to content
This repository was archived by the owner on Jul 19, 2021. It is now read-only.

Commit c377c2a

Browse files
author
Maximilian Krauss
committed
Added broadcasting system
1 parent 37613fb commit c377c2a

15 files changed

+323
-5
lines changed

Winfy.Core/AppContracts.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public string SpotifyLocalHost {
4242
get { return "winfy.spotilocal.com"; }
4343
}
4444

45+
public string BroadcastUrl { get { return "http://deploy.krausshq.com/winfy/broadcast.json"; } }
46+
4547
public string SettingsLocation {
4648
get {
4749
var location = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), ApplicationName);

Winfy.Core/AppSettings.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public sealed class AppSettings : PropertyChangedBase {
77

88
public AppSettings() {
99
Positions = new List<WindowPosition>();
10+
ReadBroadcastMessageIds = new List<string>();
1011
UniqueApplicationIdentifier = Guid.NewGuid().ToString();
1112
}
1213

@@ -35,6 +36,7 @@ public bool DisableAnimations {
3536
}
3637

3738
public List<WindowPosition> Positions { get; set; }
39+
public List<string> ReadBroadcastMessageIds { get; set; }
3840
public string UniqueApplicationIdentifier { get; set; }
3941

4042
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System.Runtime.Serialization;
2+
3+
namespace Winfy.Core.Broadcast {
4+
[DataContract]
5+
public sealed class BroadcastMessage {
6+
7+
[DataMember(Name = "id")]
8+
public string Id { get; set; }
9+
10+
[DataMember(Name = "active")]
11+
public bool Active { get; set; }
12+
13+
[DataMember(Name = "affected_version")]
14+
public string AffectedVersion { get; set; }
15+
16+
[DataMember(Name = "title")]
17+
public string Title { get; set; }
18+
19+
[DataMember(Name = "body")]
20+
public string Body { get; set; }
21+
22+
[DataMember(Name = "action_name")]
23+
public string ActionName { get; set; }
24+
25+
[DataMember(Name = "action_url")]
26+
public string ActionUrl { get; set; }
27+
}
28+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System;
2+
3+
namespace Winfy.Core.Broadcast {
4+
public sealed class BroadcastMessageReceivedEventArgs : EventArgs {
5+
public BroadcastMessageReceivedEventArgs(BroadcastMessage message) {
6+
Message = message;
7+
}
8+
9+
public BroadcastMessage Message { get; private set; }
10+
11+
}
12+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Net;
5+
using System.Text;
6+
using System.Timers;
7+
8+
namespace Winfy.Core.Broadcast {
9+
public sealed class BroadcastService : IBroadcastService {
10+
11+
private readonly AppSettings _Settings;
12+
private readonly AppContracts _Contracts;
13+
private readonly ILog _Log;
14+
15+
private Timer _BroadcastTimer;
16+
private DateTime _LastTimeChecked;
17+
private bool _CheckLock;
18+
19+
public event EventHandler<BroadcastMessageReceivedEventArgs> BroadcastMessageReceived;
20+
21+
public BroadcastService(AppSettings settings, AppContracts contracts, ILog log) {
22+
_Settings = settings;
23+
_Contracts = contracts;
24+
_Log = log;
25+
_LastTimeChecked = DateTime.MinValue;
26+
}
27+
28+
private void OnBroadcastMessageReceived(BroadcastMessageReceivedEventArgs e) {
29+
var handler = BroadcastMessageReceived;
30+
if (handler != null) handler(this, e);
31+
}
32+
33+
public void StartListening() {
34+
_BroadcastTimer = new Timer(1000) {AutoReset = true, Enabled = true};
35+
_BroadcastTimer.Elapsed += (o, e) => {
36+
if (DateTime.Now.Subtract(_LastTimeChecked).TotalHours < 1 || _CheckLock)
37+
return;
38+
39+
try {
40+
_CheckLock = true;
41+
CheckBroadcast();
42+
}
43+
finally {
44+
_LastTimeChecked = DateTime.Now;
45+
_CheckLock = false;
46+
}
47+
};
48+
}
49+
50+
private void CheckBroadcast() {
51+
try {
52+
List<BroadcastMessage> broadcastMessages;
53+
var request = Helper.CreateWebRequest(_Contracts.BroadcastUrl);
54+
var response = (HttpWebResponse) request.GetResponse();
55+
using (var responseStream = response.GetResponseStream())
56+
broadcastMessages = Serializer.DeserializeFromJson<List<BroadcastMessage>>(responseStream);
57+
response.Close();
58+
59+
if (broadcastMessages.Count == 0)
60+
return;
61+
62+
var newMessages = broadcastMessages.Where(m =>
63+
m.Active &&
64+
_Contracts.ApplicationVersion <= new Version(m.AffectedVersion) &&
65+
_Settings.ReadBroadcastMessageIds.All(id => id != m.Id)).ToList();
66+
67+
if(newMessages.Any())
68+
OnBroadcastMessageReceived(new BroadcastMessageReceivedEventArgs(newMessages.First()));
69+
}
70+
catch (Exception exc) {
71+
_Log.WarnException("CheckBroadcast failed", exc);
72+
}
73+
}
74+
75+
public void StopListening() {
76+
if (_BroadcastTimer != null) {
77+
_BroadcastTimer.Stop();
78+
_BroadcastTimer.Dispose();
79+
}
80+
}
81+
}
82+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System;
2+
3+
namespace Winfy.Core.Broadcast {
4+
public interface IBroadcastService {
5+
event EventHandler<BroadcastMessageReceivedEventArgs> BroadcastMessageReceived;
6+
void StartListening();
7+
void StopListening();
8+
}
9+
}

Winfy.Core/Winfy.Core.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
<SpecificVersion>False</SpecificVersion>
3737
<HintPath>..\packages\Caliburn.Micro.1.5.1\lib\net40\Caliburn.Micro.dll</HintPath>
3838
</Reference>
39+
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
40+
<SpecificVersion>False</SpecificVersion>
41+
<HintPath>..\packages\Newtonsoft.Json.5.0.6\lib\net40\Newtonsoft.Json.dll</HintPath>
42+
</Reference>
3943
<Reference Include="NLog, Version=2.0.1.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
4044
<SpecificVersion>False</SpecificVersion>
4145
<HintPath>..\packages\NLog.2.0.1.2\lib\net40\NLog.dll</HintPath>
@@ -63,6 +67,10 @@
6367
<Compile Include="AppContracts.cs" />
6468
<Compile Include="AppSettings.cs" />
6569
<Compile Include="AutorunService.cs" />
70+
<Compile Include="Broadcast\BroadcastMessage.cs" />
71+
<Compile Include="Broadcast\BroadcastMessageReceivedEventArgs.cs" />
72+
<Compile Include="Broadcast\BroadcastService.cs" />
73+
<Compile Include="Broadcast\IBroadcastService.cs" />
6674
<Compile Include="CoverService.cs" />
6775
<Compile Include="Deployment\AppDeployment.cs" />
6876
<Compile Include="Deployment\Release.cs" />

Winfy/AppBootstrapper.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Deployment.Application;
44
using Caliburn.Micro.TinyIOC;
55
using Winfy.Core;
6+
using Winfy.Core.Broadcast;
67
using Winfy.ViewModels;
78
using Caliburn.Micro;
89
using System.IO;
@@ -39,6 +40,7 @@ protected override void Configure() {
3940
Container.Register<Core.ILog>(new ProductionLogger());
4041
Container.Register<AutorunService>(new AutorunService(Container.Resolve<Core.ILog>(), _Settings, _Contracts));
4142
Container.Register<IWindowManager>(new AppWindowManager(_Settings));
43+
Container.Register<IBroadcastService>(new BroadcastService(_Settings, _Contracts, Container.Resolve<Core.ILog>()));
4244

4345
Container.Register<SpotifyLocalApi>(new SpotifyLocalApi(Container.Resolve<Core.ILog>(), _Contracts, _Settings));
4446
Container.Register<ISpotifyController>(new SpotifyController(Container.Resolve<Core.ILog>(), Container.Resolve<SpotifyLocalApi>()));
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System.Windows;
2+
using Caliburn.Micro;
3+
using Winfy.Core;
4+
using Winfy.Core.Broadcast;
5+
6+
namespace Winfy.ViewModels {
7+
public class NewBroadcastMessageViewModel : Screen, IFixedPosition {
8+
private readonly AppSettings _Settings;
9+
private readonly BroadcastMessage _Message;
10+
11+
public NewBroadcastMessageViewModel(AppSettings settings, BroadcastMessage message) {
12+
_Settings = settings;
13+
_Message = message;
14+
ActionName = message.ActionName;
15+
Title = message.Title;
16+
Body = message.Body;
17+
ActionToolTip = string.Format("Opens \"{0}\"", _Message.ActionUrl);
18+
}
19+
20+
protected override void OnViewLoaded(object view) {
21+
base.OnViewLoaded(view);
22+
DisplayName = "Important Winfy broadcast message";
23+
}
24+
25+
protected override void OnDeactivate(bool close) {
26+
base.OnDeactivate(close);
27+
28+
if(close)
29+
_Settings.ReadBroadcastMessageIds.Add(_Message.Id);
30+
}
31+
32+
public WindowStartupLocation WindowStartupLocation {
33+
get { return WindowStartupLocation.CenterScreen; }
34+
}
35+
36+
private string _Title;
37+
public string Title {
38+
get { return _Title; }
39+
set { _Title = value; NotifyOfPropertyChange(() => Title); }
40+
}
41+
42+
private string _Body;
43+
public string Body {
44+
get { return _Body; }
45+
set { _Body = value;NotifyOfPropertyChange(() => Body); }
46+
}
47+
48+
private string _ActionName;
49+
public string ActionName {
50+
get { return _ActionName; }
51+
set { _ActionName = value; NotifyOfPropertyChange(() => ActionName); NotifyOfPropertyChange(() => HasAction); }
52+
}
53+
54+
private string _ActionToolTip;
55+
public string ActionToolTip {
56+
get { return _ActionToolTip; }
57+
set { _ActionToolTip = value; NotifyOfPropertyChange(() => ActionToolTip); }
58+
}
59+
60+
public bool HasAction { get { return !string.IsNullOrEmpty(_ActionName) && !string.IsNullOrEmpty(_Message.ActionUrl); } }
61+
62+
public void WindowClose() {
63+
TryClose();
64+
}
65+
66+
public void ExecuteAction() {
67+
if (string.IsNullOrEmpty(_Message.ActionUrl))
68+
return;
69+
70+
Helper.OpenUrl(_Message.ActionUrl);
71+
}
72+
}
73+
}

Winfy/ViewModels/ShellViewModel.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66
using Winfy.Core;
7+
using Winfy.Core.Broadcast;
78
using Winfy.Core.Deployment;
89
using Action = System.Action;
910
using TinyIoC;
@@ -17,6 +18,7 @@ public sealed class ShellViewModel : Screen, IToggleVisibility {
1718
private readonly IEventAggregator _EventAggregator;
1819
private readonly IUpdateService _UpdateService;
1920
private readonly IUsageTrackerService _UsageTrackerService;
21+
private readonly IBroadcastService _BroadcastService;
2022
private readonly AppSettings _Settings;
2123
private readonly Core.ILog _Logger;
2224
private const string NoCoverUri = @"pack://application:,,,/Winfy;component/Images/LogoWhite.png";
@@ -26,7 +28,7 @@ public sealed class ShellViewModel : Screen, IToggleVisibility {
2628
public event EventHandler CoverDisplayFadeOut;
2729
public event EventHandler CoverDisplayFadeIn;
2830

29-
public ShellViewModel(IWindowManager windowManager, ISpotifyController spotifyController, ICoverService coverService, IEventAggregator eventAggregator, AppSettings settings, Core.ILog logger, IUpdateService updateService, IUsageTrackerService usageTrackerService) {
31+
public ShellViewModel(IWindowManager windowManager, ISpotifyController spotifyController, ICoverService coverService, IEventAggregator eventAggregator, AppSettings settings, Core.ILog logger, IUpdateService updateService, IUsageTrackerService usageTrackerService, IBroadcastService broadcastService) {
3032
_WindowManager = windowManager;
3133
_SpotifyController = spotifyController;
3234
_CoverService = coverService;
@@ -35,6 +37,7 @@ public ShellViewModel(IWindowManager windowManager, ISpotifyController spotifyCo
3537
_Logger = logger;
3638
_UpdateService = updateService;
3739
_UsageTrackerService = usageTrackerService;
40+
_BroadcastService = broadcastService;
3841

3942
CoverImage = NoCoverUri;
4043
UpdateView();
@@ -45,6 +48,9 @@ public ShellViewModel(IWindowManager windowManager, ISpotifyController spotifyCo
4548
_UpdateService.UpdateReady += UpdateReady;
4649
_UpdateService.StartBackgroundCheck();
4750
_UsageTrackerService.Track();
51+
52+
_BroadcastService.BroadcastMessageReceived += BroadcastMessageReceived;
53+
_BroadcastService.StartListening();
4854
}
4955

5056
protected override void OnViewLoaded(object view) {
@@ -209,7 +215,12 @@ void UpdateReady(object sender, UpdateReadyEventArgs e) {
209215
}))));
210216

211217
}
212-
218+
219+
private void BroadcastMessageReceived(object sender, BroadcastMessageReceivedEventArgs e) {
220+
Execute.OnUIThread(() => _WindowManager.ShowDialog(
221+
TinyIoCContainer.Current.Resolve<NewBroadcastMessageViewModel>(
222+
new NamedParameterOverloads(new Dictionary<string, object> {{"message", e.Message}}))));
223+
}
213224

214225
private void OnToggleVisibility(ToggleVisibilityEventArgs e) {
215226
Execute.OnUIThread(() => {

0 commit comments

Comments
 (0)