Skip to content

Commit c785422

Browse files
committed
Add auto update; Release 1.0.1
1 parent 4cee884 commit c785422

19 files changed

+485
-41
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using Newtonsoft.Json;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.ComponentModel;
5+
using System.Runtime.CompilerServices;
6+
using System.Text;
7+
8+
namespace Moesocks.Client.Services.Configuration
9+
{
10+
public abstract class ConfigurationBase : INotifyPropertyChanged
11+
{
12+
[JsonIgnore]
13+
public bool AutoSave { get; set; }
14+
15+
public event PropertyChangedEventHandler PropertyChanged;
16+
public event EventHandler Saving;
17+
18+
protected bool SetProperty<T>(ref T property, T value, [CallerMemberName]string propertyName = null)
19+
{
20+
if(!EqualityComparer<T>.Default.Equals(property, value))
21+
{
22+
property = value;
23+
OnPropertyChanged(propertyName);
24+
if (AutoSave)
25+
Save();
26+
return true;
27+
}
28+
return false;
29+
}
30+
31+
public void Save()
32+
{
33+
Saving?.Invoke(this, EventArgs.Empty);
34+
}
35+
36+
protected virtual void OnPropertyChanged(string propertyName)
37+
{
38+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
39+
}
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Moesocks.Client.Services.Configuration
6+
{
7+
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
8+
public sealed class ConfigurationSectionNameAttribute : Attribute
9+
{
10+
public string SectionName { get; }
11+
12+
public ConfigurationSectionNameAttribute(string sectionName)
13+
{
14+
SectionName = sectionName;
15+
}
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Microsoft.Extensions.Options;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Text;
5+
6+
namespace Moesocks.Client.Services.Configuration
7+
{
8+
[ConfigurationSectionName("update")]
9+
public class UpdateConfiguration : ConfigurationBase, IOptions<UpdateConfiguration>
10+
{
11+
private bool _enabled = true;
12+
public bool Enabled
13+
{
14+
get => _enabled;
15+
set => SetProperty(ref _enabled, value);
16+
}
17+
18+
private bool _useByteBasisNetwork;
19+
public bool UseByteBasisNetwork
20+
{
21+
get => _useByteBasisNetwork;
22+
set => SetProperty(ref _useByteBasisNetwork, value);
23+
}
24+
25+
UpdateConfiguration IOptions<UpdateConfiguration>.Value => this;
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Moesocks.Client
6+
{
7+
public interface IProductInformation
8+
{
9+
string ProductName { get; }
10+
Version ProductVersion { get; }
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Text;
5+
6+
namespace Moesocks.Client.Services
7+
{
8+
public class NewReleaseFoundEventArgs : EventArgs
9+
{
10+
public string Version { get; }
11+
public FileInfo UpdatePack { get; }
12+
13+
public NewReleaseFoundEventArgs(string version, FileInfo updatePack)
14+
{
15+
Version = version;
16+
UpdatePack = updatePack;
17+
}
18+
}
19+
20+
public interface IUpdateService
21+
{
22+
event EventHandler<NewReleaseFoundEventArgs> NewReleaseFound;
23+
24+
void Startup();
25+
}
26+
}

src/Moesocks.Client.Services/Moesocks.Client.Services.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
<ItemGroup>
88
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.1" />
9+
<PackageReference Include="Octokit" Version="0.24.1-alpha0001" />
10+
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
911
<PackageReference Include="System.Net.Security" Version="4.3.0" />
1012
<PackageReference Include="Tomato.Threading" Version="1.0.1" />
1113
</ItemGroup>

src/Moesocks.Client.Services/ServiceCollectionExtensions.cs

+7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using Microsoft.Extensions.Configuration;
22
using Microsoft.Extensions.DependencyInjection;
33
using Microsoft.Extensions.Options;
4+
using Moesocks.Client.Services;
45
using Moesocks.Client.Services.Network;
6+
using Moesocks.Client.Services.Update;
57
using System;
68
using System.Collections.Generic;
79
using System.Text;
@@ -20,5 +22,10 @@ public static IServiceCollection AddSecurity(this IServiceCollection services, I
2022
{
2123
return services.Configure<SecuritySettings>(configuration);
2224
}
25+
26+
public static IServiceCollection AddUpdate(this IServiceCollection services)
27+
{
28+
return services.AddSingleton<IUpdateService, UpdateService>();
29+
}
2330
}
2431
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
using Microsoft.Extensions.Options;
2+
using Moesocks.Client.Services.Configuration;
3+
using Octokit;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using System.Linq;
8+
using System.Net.Http;
9+
using System.Net.NetworkInformation;
10+
using System.Reflection;
11+
using System.Text;
12+
using System.Threading;
13+
using System.Threading.Tasks;
14+
15+
namespace Moesocks.Client.Services.Update
16+
{
17+
class UpdateService : IUpdateService
18+
{
19+
private readonly UpdateConfiguration _update;
20+
private CancellationTokenSource _cts;
21+
private readonly Timer _checkUpdate;
22+
private readonly TimeSpan _checkPeriod = TimeSpan.FromHours(1);
23+
private readonly GitHubClient _github;
24+
private readonly Version _currentVersion;
25+
private FileInfo _updatePack = null;
26+
private string _newVersion;
27+
28+
public event EventHandler<NewReleaseFoundEventArgs> NewReleaseFound;
29+
30+
protected bool CanUpdate => _updatePack == null && _update.Enabled && NetworkInterface.GetIsNetworkAvailable();
31+
32+
public UpdateService(IOptions<UpdateConfiguration> updateConfig, IProductInformation productInfo)
33+
{
34+
_currentVersion = productInfo.ProductVersion;
35+
_github = new GitHubClient(new ProductHeaderValue(productInfo.ProductName, _currentVersion.ToString()));
36+
_checkUpdate = new Timer(CheckUpdate, this, Timeout.InfiniteTimeSpan, _checkPeriod);
37+
_update = updateConfig.Value;
38+
_update.PropertyChanged += update_PropertyChanged;
39+
}
40+
41+
private void update_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
42+
{
43+
UpdateJob();
44+
}
45+
46+
private void UpdateJob()
47+
{
48+
if (!CanUpdate)
49+
{
50+
var oldCts = Interlocked.Exchange(ref _cts, null);
51+
if (oldCts != null)
52+
{
53+
oldCts.Cancel();
54+
_checkUpdate.Change(Timeout.InfiniteTimeSpan, _checkPeriod);
55+
_cts = null;
56+
}
57+
}
58+
else
59+
{
60+
var cts = new CancellationTokenSource();
61+
if (Interlocked.CompareExchange(ref _cts, cts, null) == null)
62+
_checkUpdate.Change(TimeSpan.Zero, _checkPeriod);
63+
}
64+
UpdateProduct();
65+
}
66+
67+
private static async void CheckUpdate(object me)
68+
{
69+
var service = (UpdateService)me;
70+
try
71+
{
72+
var token = service._cts.Token;
73+
token.ThrowIfCancellationRequested();
74+
if (service.CanUpdate)
75+
{
76+
var releaseClient = service._github.Repository.Release;
77+
var latest = await releaseClient.GetLatest("sunnycase", "Moesocks");
78+
token.ThrowIfCancellationRequested();
79+
var latestVersion = Version.Parse(latest.TagName);
80+
if (latestVersion > service._currentVersion)
81+
{
82+
var asset = latest.Assets.FirstOrDefault(o => o.Name == "client.bin.zip");
83+
if (asset != null)
84+
{
85+
var updatePackFile = CreateUpdatePackFile(latestVersion);
86+
if (!updatePackFile.Exists || updatePackFile.Length != asset.Size)
87+
{
88+
updatePackFile.Directory.Create();
89+
using (var updatePack = updatePackFile.OpenWrite())
90+
using (var client = new HttpClient())
91+
{
92+
token.ThrowIfCancellationRequested();
93+
var source = await client.GetStreamAsync(asset.BrowserDownloadUrl);
94+
token.ThrowIfCancellationRequested();
95+
await source.CopyToAsync(updatePack);
96+
}
97+
}
98+
token.ThrowIfCancellationRequested();
99+
service._newVersion = latest.Name;
100+
service._updatePack = updatePackFile;
101+
service.UpdateProduct();
102+
}
103+
}
104+
}
105+
}
106+
catch
107+
{
108+
109+
}
110+
finally
111+
{
112+
Interlocked.Exchange(ref service._cts, null);
113+
}
114+
}
115+
116+
private void UpdateProduct()
117+
{
118+
var pack = _updatePack;
119+
if (pack != null)
120+
NewReleaseFound?.Invoke(this, new NewReleaseFoundEventArgs(_newVersion, pack));
121+
}
122+
123+
private static FileInfo CreateUpdatePackFile(Version latestVersion)
124+
{
125+
return new FileInfo(Path.Combine("update", "client-v" + latestVersion + ".zip"));
126+
}
127+
128+
public void Startup()
129+
{
130+
UpdateJob();
131+
}
132+
}
133+
}

src/Moesocks.Client/App.config

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
1-
<?xml version="1.0" encoding="utf-8"?>
1+
<?xml version="1.0" encoding="utf-8"?>
22
<configuration>
33
<startup>
4-
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
4+
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/>
55
</startup>
66
<runtime>
77
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
88
<dependentAssembly>
9-
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
10-
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
9+
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
10+
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
1111
</dependentAssembly>
1212
<dependentAssembly>
13-
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
14-
<bindingRedirect oldVersion="0.0.0.0-1.2.1.0" newVersion="1.2.1.0" />
13+
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
14+
<bindingRedirect oldVersion="0.0.0.0-1.2.1.0" newVersion="1.2.1.0"/>
1515
</dependentAssembly>
1616
<dependentAssembly>
17-
<assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
18-
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
17+
<assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral"/>
18+
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0"/>
1919
</dependentAssembly>
2020
<dependentAssembly>
21-
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
22-
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
21+
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
22+
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0"/>
2323
</dependentAssembly>
2424
</assemblyBinding>
2525
</runtime>
26-
</configuration>
26+
</configuration>

0 commit comments

Comments
 (0)