Skip to content

Commit bbee620

Browse files
committed
Implemented simple update progress
1 parent 16b1c97 commit bbee620

File tree

7 files changed

+348
-7
lines changed

7 files changed

+348
-7
lines changed

src/CleanBrowsingClient/CleanBrowsingClient.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.6.0" />
5454
<PackageReference Include="System.Text.Encoding.Extensions" Version="4.3.0" />
5555
<PackageReference Include="System.Threading" Version="4.3.0" />
56+
<PackageReference Include="YamlDotNet" Version="8.0.0" />
5657
</ItemGroup>
5758
<ItemGroup>
5859
<None Update="dnscrypt-proxy\LICENSE">

src/CleanBrowsingClient/Config/Global.cs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,21 @@ public static class Global
99
/// </summary>
1010
public const string ApplicationName = "Clean Browsing Client";
1111

12+
/// <summary>
13+
/// Name of the company.
14+
/// </summary>
1215
public const string CompanyName = "cleanbrowsing.org";
1316

17+
/// <summary>
18+
/// First year of copyright.
19+
/// </summary>
1420
public const int CopyrightYear = 2019;
1521

22+
/// <summary>
23+
/// Remote URI where the application will find the update informations.
24+
/// </summary>
25+
public const string RemoteUpdateCheckUrl = "https://raw.githubusercontent.com/bitbeans/CleanBrowsingClient/master/update.yml";
26+
1627
/// <summary>
1728
/// The name of the application configuration file.
1829
/// </summary>
@@ -33,13 +44,39 @@ public static class Global
3344
/// </summary>
3445
public const string DnsCryptConfigurationFile = "dnscrypt-proxy.toml";
3546

47+
/// <summary>
48+
/// Name of the family filter key.
49+
/// </summary>
3650
public const string DefaultFamilyFilterKey = "cleanbrowsing-family";
51+
52+
/// <summary>
53+
/// Default family filter stamp.
54+
/// </summary>
3755
public const string DefaultFamilyFilterStamp = "sdns://AQMAAAAAAAAAFDE4NS4yMjguMTY4LjE2ODo4NDQzILysMvrVQ2kXHwgy1gdQJ8MgjO7w6OmflBjcd2Bl1I8pEWNsZWFuYnJvd3Npbmcub3Jn";
56+
57+
/// <summary>
58+
/// Name of the adult filter key.
59+
/// </summary>
3860
public const string DefaultAdultFilterKey = "cleanbrowsing-adult";
61+
62+
/// <summary>
63+
/// Default adult filter stamp.
64+
/// </summary>
3965
public const string DefaultAdultFilterStamp = "sdns://AQMAAAAAAAAAEzE4NS4yMjguMTY4LjEwOjg0NDMgvKwy-tVDaRcfCDLWB1AnwyCM7vDo6Z-UGNx3YGXUjykRY2xlYW5icm93c2luZy5vcmc";
66+
67+
/// <summary>
68+
/// Name of the custom filter key.
69+
/// </summary>
4070
public const string DefaultCustomFilterKey = "cleanbrowsing-custom";
4171

72+
/// <summary>
73+
/// String to validate DoH stamps.
74+
/// </summary>
4275
public const string ValidCleanBrowsingDohStamp = "doh.cleanbrowsing.org";
76+
77+
/// <summary>
78+
/// String to validate DnsCrypt stamps.
79+
/// </summary>
4380
public const string ValidCleanBrowsingDnsCryptStamp = "cleanbrowsing.org";
4481

4582
/// <summary>
@@ -67,11 +104,11 @@ public static class Global
67104
/// </summary>
68105
public const int ServiceInstallTime = 3000;
69106

107+
/// <summary>
108+
/// Default log level.
109+
/// </summary>
70110
public const LogEventLevel DefaultLogEventLevel = LogEventLevel.Information;
71111

72-
public const string DefaultResolverIpv4 = "127.0.0.1:53";
73-
public const string DefaultResolverIpv6 = "[::1]:53";
74-
75112
/// <summary>
76113
/// List of files must exist.
77114
/// </summary>
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using System;
2+
using System.IO;
3+
using System.Net.Http;
4+
using System.Threading.Tasks;
5+
6+
namespace CleanBrowsingClient.Helper
7+
{
8+
public class HttpClientDownloadWithProgress : IDisposable
9+
{
10+
private readonly string _downloadUrl;
11+
private readonly string _destinationFilePath;
12+
13+
private HttpClient _httpClient;
14+
15+
public delegate void ProgressChangedHandler(long? totalFileSize, long totalBytesDownloaded, double? progressPercentage);
16+
17+
public event ProgressChangedHandler ProgressChanged;
18+
19+
public HttpClientDownloadWithProgress(string downloadUrl, string destinationFilePath)
20+
{
21+
_downloadUrl = downloadUrl;
22+
_destinationFilePath = destinationFilePath;
23+
}
24+
25+
public HttpClientDownloadWithProgress(Uri downloadUrl, string destinationFilePath)
26+
{
27+
_downloadUrl = downloadUrl.ToString();
28+
_destinationFilePath = destinationFilePath;
29+
}
30+
31+
public async Task StartDownload()
32+
{
33+
_httpClient = new HttpClient { Timeout = TimeSpan.FromDays(1), DefaultRequestVersion = new Version(2, 0) };
34+
using var response = await _httpClient.GetAsync(_downloadUrl, HttpCompletionOption.ResponseHeadersRead);
35+
await DownloadFileFromHttpResponseMessage(response);
36+
}
37+
38+
private async Task DownloadFileFromHttpResponseMessage(HttpResponseMessage response)
39+
{
40+
response.EnsureSuccessStatusCode();
41+
42+
var totalBytes = response.Content.Headers.ContentLength;
43+
44+
using var contentStream = await response.Content.ReadAsStreamAsync();
45+
await ProcessContentStream(totalBytes, contentStream);
46+
}
47+
48+
private async Task ProcessContentStream(long? totalDownloadSize, Stream contentStream)
49+
{
50+
var totalBytesRead = 0L;
51+
var readCount = 0L;
52+
var buffer = new byte[8192];
53+
var isMoreToRead = true;
54+
55+
using var fileStream = new FileStream(_destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true);
56+
do
57+
{
58+
var bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length);
59+
if (bytesRead == 0)
60+
{
61+
isMoreToRead = false;
62+
TriggerProgressChanged(totalDownloadSize, totalBytesRead);
63+
continue;
64+
}
65+
66+
await fileStream.WriteAsync(buffer, 0, bytesRead);
67+
68+
totalBytesRead += bytesRead;
69+
readCount += 1;
70+
71+
if (readCount % 100 == 0)
72+
TriggerProgressChanged(totalDownloadSize, totalBytesRead);
73+
}
74+
while (isMoreToRead);
75+
}
76+
77+
private void TriggerProgressChanged(long? totalDownloadSize, long totalBytesRead)
78+
{
79+
if (ProgressChanged == null)
80+
return;
81+
82+
double? progressPercentage = null;
83+
if (totalDownloadSize.HasValue)
84+
progressPercentage = Math.Round((double)totalBytesRead / totalDownloadSize.Value * 100, 2);
85+
86+
ProgressChanged(totalDownloadSize, totalBytesRead, progressPercentage);
87+
}
88+
89+
public void Dispose()
90+
{
91+
_httpClient?.Dispose();
92+
}
93+
}
94+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using System;
2+
3+
namespace CleanBrowsingClient.Models
4+
{
5+
/// <summary>
6+
/// Outer remote update class.
7+
/// </summary>
8+
public class RemoteUpdate
9+
{
10+
/// <summary>
11+
/// Indicates if the requested update can be done.
12+
/// </summary>
13+
public bool CanUpdate { get; set; }
14+
15+
/// <summary>
16+
/// The update data.
17+
/// </summary>
18+
public Update Update { get; set; }
19+
}
20+
21+
/// <summary>
22+
/// The update data.
23+
/// </summary>
24+
public class Update
25+
{
26+
/// <summary>
27+
/// The available version.
28+
/// </summary>
29+
public Version Version { get; set; }
30+
31+
/// <summary>
32+
/// The date of this release.
33+
/// </summary>
34+
public DateTime Release { get; set; }
35+
36+
/// <summary>
37+
/// The installer object.
38+
/// </summary>
39+
public Installer Installer { get; set; }
40+
}
41+
42+
/// <summary>
43+
/// The installer information.
44+
/// </summary>
45+
public class Installer
46+
{
47+
/// <summary>
48+
/// Name of the installer file.
49+
/// </summary>
50+
public string Name { get; set; }
51+
52+
/// <summary>
53+
/// Uri to download the installer file.
54+
/// </summary>
55+
public Uri Uri { get; set; }
56+
}
57+
}

0 commit comments

Comments
 (0)