1- namespace Ruler . IRule . Backend
1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . IO ;
4+ using System . Linq ;
5+ using System . Net . Http ;
6+ using System . Threading . Tasks ;
7+ using Newtonsoft . Json ;
8+ using Ruler . Engine . Manifest ;
9+ using Ruler . Engine . Platform ;
10+ using Spectre . Console ;
11+
12+ namespace Ruler . IRule . Backend
213{
314 public static class VersionSelector
415 {
5- public static void SelectVersion ( bool autoSelect )
16+ public static async Task SelectVersion ( bool autoSelect )
617 {
18+ if ( ! autoSelect )
19+ AnsiConsole . MarkupLine (
20+ "\n [gray]If you know what you're doing, you can change the release branch in the config menu![/]\n "
21+ ) ;
22+
23+ string branch = Program . Endpoint + Program . Config . Branch ;
724
25+ HttpResponseMessage resp = await Program . Client . GetAsync ( branch + "/versions-manifest.json" ) ;
26+ VersionsManifest ? vers = JsonConvert . DeserializeObject < VersionsManifest > (
27+ await resp . Content . ReadAsStringAsync ( )
28+ ) ;
29+
30+ if ( vers is null )
31+ throw new InvalidOperationException (
32+ "Could not parse JSON received from: " + branch + "/versions-manifest.json"
33+ ) ;
34+
35+ string version ;
36+
37+ if ( autoSelect )
38+ version = vers . Latest ;
39+ else
40+ {
41+ IEnumerable < string > choices = vers . Versions . Select ( x => x . Value . Name ) ;
42+
43+ string sel = AnsiConsole . Prompt (
44+ new SelectionPrompt < string > ( )
45+ . Title ( "Select an [red1 bold]I.RULE[/] version:" )
46+ . PageSize ( 5 )
47+ . MoreChoicesText ( "[gray]Scroll up/down for more![/]" )
48+ . AddChoices ( choices )
49+ ) ;
50+
51+ version = vers . Versions . First ( x => x . Value . Name . Equals ( sel ) ) . Key ;
52+ }
53+
54+ await InstallAndPlayVersion ( branch , version , autoSelect ) ;
55+ }
56+
57+ public static async Task InstallAndPlayVersion ( string endpoint , string version , bool autoSelect )
58+ {
59+ HttpResponseMessage resp = await Program . Client . GetAsync ( endpoint + "/versions/" + version + "/manifest.json" ) ;
60+ VersionManifest ? vers = JsonConvert . DeserializeObject < VersionManifest > (
61+ await resp . Content . ReadAsStringAsync ( )
62+ ) ;
63+
64+ if ( vers is null )
65+ throw new InvalidOperationException ( "Could not find version: " + version ) ;
66+
67+ string directory = Path . Combine ( DesktopLocationProvider . GetDesktopProvider ( ) . GetLocation ( ) , "I.RULE" , version ) ;
68+
69+ Directory . CreateDirectory ( directory ) ;
70+
71+ if ( new DirectoryInfo ( directory ) . EnumerateFiles ( ) . Any ( x => x . Extension . Equals ( ".exe" ) ) )
72+ {
73+ await GameLauncher . RunGame ( directory ) ;
74+ return ;
75+ }
76+
77+ AnsiConsole . MarkupLine ( $ "\n Selected version: [b]{ vers . Name } [/]") ;
78+
79+ if ( Program . Config . ReviewUpdates && ! autoSelect )
80+ {
81+ string desc = vers . Description ;
82+
83+ if ( desc == "{{ USE_CHANGELOG }}" )
84+ {
85+ HttpResponseMessage clResp = await Program . Client . GetAsync ( endpoint + "/versions/" + version + "/changelog.txt" ) ;
86+ desc = await clResp . Content . ReadAsStringAsync ( ) ;
87+ }
88+
89+ AnsiConsole . MarkupLine ( "[b]VERSION OVERVIEW[/]" +
90+ $ "\n [u]{ vers . Name } [/]" +
91+ "\n " +
92+ $ "\n [grey69]{ desc } [/]" +
93+ "\n \n Press [u]<ENTER>[/] to confirm this installation. Press [u]<SPACE>[/] to quit," +
94+ "\n [gray]Don't want to see this prompt? Modify \" Update Reviewing\" in the config![/]" ) ;
95+
96+ Guh :
97+ ConsoleKey key = Console . ReadKey ( true ) . Key ;
98+
99+ switch ( key )
100+ {
101+ case ConsoleKey . Enter :
102+ break ;
103+
104+ case ConsoleKey . Spacebar :
105+ return ;
106+
107+ default :
108+ goto Guh ;
109+ }
110+ }
111+
112+ await AnsiConsole . Progress ( )
113+ . Columns (
114+ new TaskDescriptionColumn ( ) ,
115+ new ProgressBarColumn ( ) ,
116+ new PercentageColumn ( ) ,
117+ new RemainingTimeColumn ( ) ,
118+ new SpinnerColumn ( )
119+ ) . StartAsync ( async x =>
120+ {
121+ var task = x . AddTask ( "Downloading release.zip" , new ProgressTaskSettings
122+ {
123+ AutoStart = false
124+ } ) ;
125+
126+ await DownloadRelease ( endpoint , directory , version , task ) ;
127+ } ) ;
128+
129+ AnsiConsole . MarkupLine ( "Unzipping (extracting) [u]release.zip[/]..." ) ;
130+ ZipImporter . UnzipFile ( directory , Path . Combine ( directory , "release.zip" ) ) ;
131+
132+ await GameLauncher . RunGame ( directory ) ;
133+ }
134+
135+ public static async Task DownloadRelease ( string endpoint , string directory , string version , ProgressTask task )
136+ {
137+ // https://stackoverflow.com/a/56091135
138+ const int bufferSize = 1024 ;
139+
140+ AnsiConsole . MarkupLine ( "[i]Preparing to download...[/]" ) ;
141+
142+ using HttpResponseMessage resp = await Program . Client . GetAsync ( endpoint + "/versions/" + version + "/release.zip" ) ;
143+ task . MaxValue ( resp . Content . Headers . ContentLength ?? 0 ) ;
144+ task . StartTask ( ) ;
145+
146+ AnsiConsole . MarkupLine (
147+ $ "Downloading [u]release.zip[/] according to version [u]{ version } [/]! ({ task . MaxValue } total bytes)"
148+ ) ;
149+
150+ await using Stream cStream = await resp . Content . ReadAsStreamAsync ( ) ;
151+ await using FileStream fStream = new (
152+ Path . Combine ( directory , "release.zip" ) ,
153+ FileMode . Create ,
154+ FileAccess . Write ,
155+ FileShare . None ,
156+ bufferSize ,
157+ true
158+ ) ;
159+
160+ byte [ ] buf = new byte [ bufferSize ] ;
161+ while ( true )
162+ {
163+ int read = await cStream . ReadAsync ( buf ) ;
164+
165+ if ( read == 0 )
166+ break ;
167+
168+ task . Increment ( read ) ;
169+
170+ await fStream . WriteAsync ( buf . AsMemory ( 0 , read ) ) ;
171+ }
8172 }
9173 }
10174}
0 commit comments