@@ -9,67 +9,103 @@ namespace Compiler
99{
1010 public class GithubUpdater
1111 {
12- public static async Task UpdateFromGithub ( Config config )
12+ private static readonly string ApiURL = "https://api.github.com/repos/johnoclockdk/CssCompiler/releases/latest" ;
13+ private static readonly HttpClient httpClient = new HttpClient ( ) ;
14+
15+ static GithubUpdater ( )
1316 {
14- string apiURL = $ "https://api.github.com/repos/johnoclockdk/CssCompiler/releases/latest";
15- string tempFilePath = Path . Combine ( Path . GetTempPath ( ) , "newExecutable.exe" ) ;
16- string currentExecutablePath = Process . GetCurrentProcess ( ) . MainModule ! . FileName ;
17- string batchScriptPath = Path . Combine ( Path . GetTempPath ( ) , "updateScript.bat" ) ;
17+ httpClient . DefaultRequestHeaders . UserAgent . TryParseAdd ( "request" ) ;
18+ }
1819
19- using ( var httpClient = new HttpClient ( ) )
20+ public static async Task UpdateFromGithubAsync ( Config config )
21+ {
22+ try
2023 {
21- httpClient . DefaultRequestHeaders . UserAgent . TryParseAdd ( "request" ) ;
24+ var latestRelease = await GetLatestReleaseAsync ( ) ;
25+ var latestVersion = new Version ( latestRelease [ "tag_name" ] ! . ToString ( ) ) ;
2226
23- try
27+ if ( IsUpdateRequired ( config , latestVersion ) )
2428 {
25- var response = await httpClient . GetStringAsync ( apiURL ) ;
26- var latestRelease = JObject . Parse ( response ) ;
27-
28- string latestVersion = latestRelease [ "tag_name" ] ! . ToString ( ) ;
29-
30- Version latestVer = new Version ( latestVersion ) ;
31- Version currentVer = new Version ( config . Version ) ;
32-
33- if ( latestVer > currentVer )
34- {
35- Console . WriteLine ( "Downloading Latest Version: " + latestVersion ) ;
36-
37- string downloadUrl = latestRelease [ "assets" ] ! [ 0 ] ! [ "browser_download_url" ] ! . ToString ( ) ;
38-
39- var downloadResponse = await httpClient . GetAsync ( downloadUrl , HttpCompletionOption . ResponseHeadersRead ) ;
40- using ( var fs = new FileStream ( tempFilePath , FileMode . Create , FileAccess . Write , FileShare . None ) )
41- {
42- await downloadResponse . Content . CopyToAsync ( fs ) ;
43- }
44-
45- config . Version = latestVersion ;
46- ConfigurationManager . SaveConfig ( config ) ;
47-
48- // Create a batch script for updating
49- using ( StreamWriter sw = new StreamWriter ( batchScriptPath ) )
50- {
51- sw . WriteLine ( "@echo off" ) ;
52- //sw.WriteLine("TIMEOUT /T 2 /NOBREAK");
53- sw . WriteLine ( $ "COPY /Y \" { tempFilePath } \" \" { currentExecutablePath } \" ") ;
54- sw . WriteLine ( $ "DEL \" { tempFilePath } \" ") ;
55- sw . WriteLine ( $ "START \" \" \" { currentExecutablePath } \" ") ;
56- sw . WriteLine ( $ "DEL \" %~f0\" ") ;
57- }
58-
59- // Start the batch script and exit the application
60- Process . Start ( batchScriptPath ) ;
61- Environment . Exit ( 0 ) ;
62- }
63- else
64- {
65- Console . WriteLine ( "No update required. Running the latest version." ) ;
66- }
29+ var tempFilePath = Path . GetTempFileName ( ) ;
30+ await DownloadLatestVersionAsync ( latestRelease , tempFilePath ) ;
31+
32+ config . Version = latestVersion . ToString ( ) ;
33+ ConfigurationManager . SaveConfig ( config ) ;
34+
35+ await ApplyUpdateAsync ( tempFilePath ) ;
6736 }
68- catch ( Exception ex )
37+ else
6938 {
70- Console . WriteLine ( "Error: " + ex . Message ) ;
39+ Console . WriteLine ( "No update required. Running the latest version." ) ;
7140 }
7241 }
42+ catch ( Exception ex )
43+ {
44+ Console . WriteLine ( "Error updating: " + ex . Message ) ;
45+ }
46+ }
47+
48+ private static bool IsUpdateRequired ( Config config , Version latestVersion )
49+ {
50+ return latestVersion > new Version ( config . Version ) ;
51+ }
52+
53+ private static async Task < JObject > GetLatestReleaseAsync ( )
54+ {
55+ var response = await httpClient . GetStringAsync ( ApiURL ) ;
56+ return JObject . Parse ( response ) ;
57+ }
58+
59+ private static async Task DownloadLatestVersionAsync ( JObject latestRelease , string tempFilePath )
60+ {
61+ string downloadUrl = latestRelease [ "assets" ] ! [ 0 ] ! [ "browser_download_url" ] ! . ToString ( ) ;
62+
63+ Console . WriteLine ( "Downloading Latest Version..." ) ;
64+ using var downloadResponse = await httpClient . GetAsync ( downloadUrl , HttpCompletionOption . ResponseHeadersRead ) ;
65+ using var fs = new FileStream ( tempFilePath , FileMode . Create , FileAccess . Write , FileShare . None ) ;
66+
67+ await CopyContentToStream ( downloadResponse . Content , fs ) ;
68+ }
69+
70+ private static async Task CopyContentToStream ( HttpContent content , FileStream fileStream )
71+ {
72+ var totalBytes = content . Headers . ContentLength ?? 0 ;
73+ var buffer = new byte [ 8192 ] ;
74+ var totalRead = 0L ;
75+ using var stream = await content . ReadAsStreamAsync ( ) ;
76+
77+ int read ;
78+ while ( ( read = await stream . ReadAsync ( buffer , 0 , buffer . Length ) ) > 0 )
79+ {
80+ await fileStream . WriteAsync ( buffer , 0 , read ) ;
81+ totalRead += read ;
82+ Console . Write ( $ "\r Download progress: { totalRead * 100 / totalBytes } %") ;
83+ }
84+ Console . WriteLine ( "\n Download Complete." ) ;
85+ }
86+
87+ private static async Task ApplyUpdateAsync ( string tempFilePath )
88+ {
89+ string currentExecutablePath = Process . GetCurrentProcess ( ) . MainModule ! . FileName ;
90+ string backupExecutablePath = currentExecutablePath + ".bak" ;
91+
92+ // Rename current executable as a backup
93+ File . Move ( currentExecutablePath , backupExecutablePath ) ;
94+
95+ // Move new executable to application path
96+ File . Move ( tempFilePath , currentExecutablePath ) ;
97+
98+ // Restart application
99+ ProcessStartInfo startInfo = new ProcessStartInfo ( currentExecutablePath )
100+ {
101+ Arguments = "restart" ,
102+ UseShellExecute = false
103+ } ;
104+
105+ Process . Start ( startInfo ) ;
106+
107+ // Exit current application
108+ Environment . Exit ( 0 ) ;
73109 }
74110 }
75- }
111+ }
0 commit comments