1+ using Microsoft . Extensions . Options ;
2+
3+ using Proxxi . Core . Models ;
4+ using Proxxi . Core . Options ;
5+ using Proxxi . Core . Providers ;
6+ using Proxxi . Core . ProxyWriters ;
7+ using Proxxi . Plugin . Loader . Extensions ;
8+ using Proxxi . Plugin . Loader . PluginLoaders ;
9+ using Proxxi . Plugin . Sdk . ProxySources ;
10+
11+ using Spectre . Console ;
12+ using Spectre . Console . Cli ;
13+
14+ namespace Proxxi . Cli . Commands . Fetch ;
15+
16+ public sealed class FetchCommand (
17+ IAnsiConsole console ,
18+ IPluginConfigProvider configProvider ,
19+ IPluginLoader pluginLoader ,
20+ IOptions < ProxxiPathsOptions > options
21+ )
22+ : AsyncCommand < FetchCommandSettings >
23+ {
24+ private readonly ProxxiPathsOptions _pathOptions = options . Value ;
25+
26+ public override async Task < int > ExecuteAsync ( CommandContext context , FetchCommandSettings settings ,
27+ CancellationToken ct )
28+ {
29+ Stream stream ;
30+ OutputFormat format ;
31+
32+ if ( settings . Output != null )
33+ {
34+ stream = File . OpenWrite ( settings . Output ) ;
35+
36+ if ( ! Enum . TryParse ( Path . GetExtension ( settings . Output ) . TrimStart ( '.' ) , true , out format ) )
37+ format = settings . Format ;
38+ }
39+ else
40+ {
41+ stream = Console . OpenStandardOutput ( ) ;
42+ format = settings . Format ;
43+ }
44+
45+ try
46+ {
47+ ( IBatchProxySource ? batchProxySource , IStreamProxySource ? streamProxySource ) =
48+ await GetPluginInstance ( settings . Id , ct ) ;
49+
50+ var writer = CreateProxyWriter ( stream , format , settings . Pretty ) ;
51+
52+ if ( settings . Stream )
53+ {
54+ if ( writer is not IStreamProxyWriter streamProxyWriter )
55+ throw new InvalidOperationException ( $ "{ format } output does not support stream mode.") ;
56+
57+ await FetchAndWriteProxiesAsync ( streamProxySource , streamProxyWriter , ct ) ;
58+ }
59+ else
60+ {
61+ if ( writer is not IBatchProxyWriter batchProxyWriter )
62+ throw new InvalidOperationException ( $ "{ format } output does not support stream mode.") ;
63+
64+ await FetchAndWriteProxiesAsync ( batchProxySource , batchProxyWriter , ct ) ;
65+ }
66+
67+ return 0 ;
68+ }
69+ catch ( OperationCanceledException )
70+ {
71+ console . MarkupLine ( "[yellow]Operation canceled.[/]" ) ;
72+ return 130 ;
73+ }
74+ finally
75+ {
76+ if ( settings . Output != null )
77+ await stream . DisposeAsync ( ) ;
78+ }
79+ }
80+
81+ private async Task < ( IBatchProxySource ? , IStreamProxySource ? ) > GetPluginInstance ( string id , CancellationToken ct )
82+ {
83+ var pluginConfig = configProvider . Get ( id ) ;
84+
85+ if ( pluginConfig == null )
86+ throw new InvalidOperationException ( $ "Plugin '{ id } ' is not installed.") ;
87+
88+ if ( ! pluginConfig . Enabled )
89+ throw new InvalidOperationException ( $ "Plugin '{ id } ' is disabled.") ;
90+
91+ var path = Path . Combine ( _pathOptions . PluginsDir , pluginConfig . Path ) ;
92+
93+ var plugin = pluginLoader . LoadPlugins ( [ path ] )
94+ . FirstOrDefault ( pd => StringComparer . OrdinalIgnoreCase . Equals ( pd . Id , pluginConfig . Id ) ) ;
95+
96+ if ( plugin == null )
97+ throw new InvalidOperationException ( $ "Plugin '{ id } ' is not loaded.") ;
98+
99+ return await plugin . CreateAsync ( pluginConfig . Parameters . ToDictionary ( ) , ct ) ;
100+ }
101+
102+ private static async Task FetchAndWriteProxiesAsync ( IBatchProxySource ? batchProxySource ,
103+ IBatchProxyWriter writer , CancellationToken ct )
104+ {
105+ if ( batchProxySource == null )
106+ throw new InvalidOperationException ( "The plugin does not support batch mode." ) ;
107+
108+ var proxies = await batchProxySource . FetchAsync ( ct ) ;
109+
110+ await writer . WriteAsync ( proxies , ct ) ;
111+ }
112+
113+ private static async Task FetchAndWriteProxiesAsync ( IStreamProxySource ? streamProxySource ,
114+ IStreamProxyWriter writer , CancellationToken ct )
115+ {
116+ if ( streamProxySource == null )
117+ throw new InvalidOperationException ( "The plugin does not support stream mode." ) ;
118+
119+ var proxies = streamProxySource . FetchAsync ( ct ) ;
120+
121+ await writer . WriteAsync ( proxies , ct ) ;
122+ }
123+
124+ private static IProxyWriter CreateProxyWriter ( Stream stream , OutputFormat format , bool isPretty ) =>
125+ format switch
126+ {
127+ OutputFormat . Plain => new PlainProxyWriter ( stream ) ,
128+ OutputFormat . Url => new UrlProxyWriter ( stream ) ,
129+ OutputFormat . Json => new JsonProxyWriter ( stream , isPretty ) ,
130+ OutputFormat . Jsonl => new JsonLineProxyWriter ( stream ) ,
131+ OutputFormat . Xml => new XmlProxyWriter ( stream , isPretty ) ,
132+ OutputFormat . Csv => new CsvProxyWriter ( stream , isPretty ) ,
133+ OutputFormat . Psv => new PsvProxyWriter ( stream , isPretty ) ,
134+ OutputFormat . Tsv => new TsvProxyWriter ( stream , isPretty ) ,
135+ _ => new PlainProxyWriter ( stream )
136+ } ;
137+ }
0 commit comments