@@ -2,6 +2,7 @@ package cli
22
33import (
44 "context"
5+ "errors"
56 "fmt"
67 "strings"
78 "time"
@@ -10,26 +11,39 @@ import (
1011)
1112
1213type App struct {
13- inputTimeout time.Duration
14+ inputTimeout time.Duration
15+ lookupTimeout time.Duration
1416}
1517
1618func NewApp () * App {
17- return & App {inputTimeout : 3 * time .Second }
19+ return & App {
20+ inputTimeout : 3 * time .Second ,
21+ lookupTimeout : 45 * time .Second ,
22+ }
1823}
1924
2025func (a * App ) Run () error {
2126 for {
2227 config , err := a .collectConfig ()
2328 if err != nil {
29+ if errors .Is (err , errAborted ) {
30+ return nil
31+ }
2432 return err
2533 }
2634
2735 if err := a .execute (config ); err != nil {
36+ if errors .Is (err , errAborted ) {
37+ return nil
38+ }
2839 return err
2940 }
3041
3142 again , err := a .askAgain ()
3243 if err != nil {
44+ if errors .Is (err , errAborted ) {
45+ return nil
46+ }
3347 return err
3448 }
3549 if ! again {
@@ -39,28 +53,117 @@ func (a *App) Run() error {
3953}
4054
4155type Config struct {
56+ Mode Mode
57+ Direct DirectConfig
58+ Lookup LookupConfig
59+ }
60+
61+ func (a * App ) collectConfig () (Config , error ) {
62+ mode , err := a .askMode ()
63+ if err != nil {
64+ return Config {}, err
65+ }
66+
67+ if mode == ModeLookup {
68+ lookup , err := a .collectLookupConfig ()
69+ if err != nil {
70+ return Config {}, err
71+ }
72+ return Config {Mode : mode , Lookup : lookup }, nil
73+ }
74+
75+ direct , err := a .collectDirectConfig ()
76+ if err != nil {
77+ return Config {}, err
78+ }
79+
80+ return Config {Mode : mode , Direct : direct }, nil
81+ }
82+
83+ type Mode string
84+
85+ const (
86+ ModeDirect Mode = "direct"
87+ ModeLookup Mode = "lookup"
88+ )
89+
90+ type DirectConfig struct {
4291 Host string
4392 Port int
4493 Edition ping.Edition
4594}
4695
47- func (a * App ) collectConfig () (Config , error ) {
96+ type LookupConfig struct {
97+ Edition ping.Edition
98+ BaseHost string
99+ Port int
100+ Subdomains []string
101+ Endings []string
102+ }
103+
104+ func (a * App ) collectDirectConfig () (DirectConfig , error ) {
48105 edition , err := a .askEdition ()
49106 if err != nil {
50- return Config {}, err
107+ return DirectConfig {}, err
51108 }
52109
53110 host , err := a .askHost ()
54111 if err != nil {
55- return Config {}, err
112+ return DirectConfig {}, err
56113 }
57114
58115 port , err := a .askPort (edition )
59116 if err != nil {
60- return Config {}, err
117+ return DirectConfig {}, err
61118 }
62119
63- return Config {Host : host , Port : port , Edition : edition }, nil
120+ return DirectConfig {Host : host , Port : port , Edition : edition }, nil
121+ }
122+
123+ func (a * App ) collectLookupConfig () (LookupConfig , error ) {
124+ edition , err := a .askEdition ()
125+ if err != nil {
126+ return LookupConfig {}, err
127+ }
128+
129+ subdomains , err := a .askSubdomainChoice ()
130+ if err != nil {
131+ return LookupConfig {}, err
132+ }
133+
134+ baseHost , err := a .askBaseHost ()
135+ if err != nil {
136+ return LookupConfig {}, err
137+ }
138+
139+ endings , err := a .askDomainEndings ()
140+ if err != nil {
141+ return LookupConfig {}, err
142+ }
143+
144+ port , err := a .askPort (edition )
145+ if err != nil {
146+ return LookupConfig {}, err
147+ }
148+
149+ return LookupConfig {
150+ Edition : edition ,
151+ BaseHost : baseHost ,
152+ Port : port ,
153+ Subdomains : subdomains ,
154+ Endings : endings ,
155+ }, nil
156+ }
157+
158+ func (a * App ) askMode () (Mode , error ) {
159+ index , err := selectOption ("Startmodus" , []string {"UWP/TCP Abfrage" , "IP Lookup" })
160+ if err != nil {
161+ return "" , err
162+ }
163+ if index == 1 {
164+ return ModeLookup , nil
165+ }
166+ return ModeDirect , nil
64167}
65168
66169func (a * App ) askEdition () (ping.Edition , error ) {
@@ -89,6 +192,69 @@ func (a *App) askHost() (string, error) {
89192 }
90193}
91194
195+ func (a * App ) askBaseHost () (string , error ) {
196+ var errMsg string
197+ for {
198+ value , err := promptInput ("IP/Domain ohne Endung" , "z.B. example" , errMsg )
199+ if err != nil {
200+ return "" , err
201+ }
202+ value = strings .TrimSpace (value )
203+ if value == "" {
204+ errMsg = "Wert darf nicht leer sein"
205+ continue
206+ }
207+ return value , nil
208+ }
209+ }
210+
211+ func (a * App ) askSubdomainChoice () ([]string , error ) {
212+ index , err := selectOption ("Subdomain" , []string {"Eigene Subdomain" , "Subdomain-Pool" })
213+ if err != nil {
214+ return nil , err
215+ }
216+ if index == 1 {
217+ return subdomainPool , nil
218+ }
219+
220+ var errMsg string
221+ for {
222+ value , err := promptInput ("Subdomain (optional)" , "z.B. play (leer lassen für keine)" , errMsg )
223+ if err != nil {
224+ return nil , err
225+ }
226+ value = strings .TrimSpace (value )
227+ return []string {value }, nil
228+ }
229+ }
230+
231+ func (a * App ) askDomainEndings () ([]string , error ) {
232+ index , err := selectOption ("Domain-Endung" , []string {"Eigene Endung" , "Endungs-Pool" })
233+ if err != nil {
234+ return nil , err
235+ }
236+ if index == 1 {
237+ endings , err := loadDomainEndings ()
238+ if err != nil {
239+ return endings , nil
240+ }
241+ return endings , nil
242+ }
243+ var errMsg string
244+ for {
245+ value , err := promptInput ("Domain-Endung" , "z.B. com oder de" , errMsg )
246+ if err != nil {
247+ return nil , err
248+ }
249+ value = normalizeEnding (value )
250+ if value == "" {
251+ errMsg = "Endung darf nicht leer sein"
252+ continue
253+ }
254+ return []string {value }, nil
255+ }
256+ }
257+
92258func (a * App ) askPort (edition ping.Edition ) (int , error ) {
93259 defaultPort := ping .DefaultPort (edition )
94260 var errMsg string
@@ -114,6 +280,15 @@ func (a *App) askPort(edition ping.Edition) (int, error) {
114280}
115281
116282func (a * App ) execute (config Config ) error {
283+ switch config .Mode {
284+ case ModeLookup :
285+ return a .executeLookup (config .Lookup )
286+ default :
287+ return a .executeDirect (config .Direct )
288+ }
289+ }
290+
291+ func (a * App ) executeDirect (config DirectConfig ) error {
117292 ctx , cancel := context .WithTimeout (context .Background (), a .inputTimeout )
118293 defer cancel ()
119294
@@ -132,10 +307,62 @@ func (a *App) execute(config Config) error {
132307 return nil
133308}
134309
310+ func (a * App ) executeLookup (config LookupConfig ) error {
311+ ctx , cancel := context .WithTimeout (context .Background (), a .lookupTimeout )
312+ defer cancel ()
313+
314+ resultText , err := withSpinner ("IP Lookup" , "Domains werden überprüft" , 120 * time .Millisecond , func () (string , error ) {
315+ result , lookupErr := ping .LookupDomains (ctx , ping.LookupConfig {
316+ Edition : config .Edition ,
317+ Port : config .Port ,
318+ BaseHost : config .BaseHost ,
319+ Subdomains : config .Subdomains ,
320+ DomainEndings : config .Endings ,
321+ Concurrency : 24 ,
322+ PerHostTimeout : 2 * time .Second ,
323+ })
324+ if lookupErr != nil && ! errors .Is (lookupErr , context .DeadlineExceeded ) {
325+ return "" , lookupErr
326+ }
327+ return formatLookupResult (result , errors .Is (lookupErr , context .DeadlineExceeded )), nil
328+ })
329+ if err != nil {
330+ return err
331+ }
332+
333+ renderTextPage ("Ergebnis" , resultText )
334+ return nil
335+ }
336+
135337func (a * App ) askAgain () (bool , error ) {
136338 index , err := selectOption ("Nächster Schritt" , []string {"Neue Abfrage" , "Beenden" })
137339 if err != nil {
138340 return false , err
139341 }
140342 return index == 0 , nil
141343}
344+
345+ func formatLookupResult (result ping.LookupResult , timedOut bool ) string {
346+ var builder strings.Builder
347+ builder .WriteString (fmt .Sprintf ("Kombinationen geprüft: %d/%d\n " , result .Completed , result .Attempts ))
348+ builder .WriteString (fmt .Sprintf ("Treffer: %d\n " , len (result .Matches )))
349+ if timedOut {
350+ builder .WriteString ("Hinweis: Zeitlimit erreicht, Ergebnisse können unvollständig sein.\n " )
351+ }
352+ builder .WriteString ("\n " )
353+
354+ if len (result .Matches ) == 0 {
355+ builder .WriteString ("Keine passenden Server gefunden." )
356+ return builder .String ()
357+ }
358+
359+ for i , match := range result .Matches {
360+ if i > 0 {
361+ builder .WriteString ("\n " )
362+ }
363+ builder .WriteString (fmt .Sprintf ("Host: %s\n " , match .Host ))
364+ builder .WriteString (match .Result .String ())
365+ builder .WriteString ("\n " )
366+ }
367+ return builder .String ()
368+ }
0 commit comments