| package main | |
| import ( | |
| "bufio" | |
| "bytes" | |
| "encoding/json" | |
| "fmt" | |
| "io" | |
| "net/http" | |
| "os" | |
| "os/exec" | |
| "runtime" | |
| "strings" | |
| "time" | |
| ) | |
| // ANSI color escape codes | |
| const ( | |
| Reset = "\033[0m" | |
| Bold = "\033[1m" | |
| Dim = "\033[2m" | |
| Red = "\033[31m" | |
| Green = "\033[32m" | |
| Yellow = "\033[33m" | |
| Blue = "\033[34m" | |
| Purple = "\033[35m" | |
| Cyan = "\033[36m" | |
| ) | |
| func ok(s string) string { return fmt.Sprintf("%s%s✔%s %s", Green, Bold, Reset, s) } | |
| func err(s string) string { return fmt.Sprintf("%s%s✘%s %s", Red, Bold, Reset, s) } | |
| func inf(s string) string { return fmt.Sprintf("%s%sℹ%s %s", Cyan, Bold, Reset, s) } | |
| func wrn(s string) string { return fmt.Sprintf("%s%s⚠%s %s", Yellow, Bold, Reset, s) } | |
| func hdr(s string) string { | |
| border := strings.Repeat("═", len(s)+8) | |
| return fmt.Sprintf("\n%s%s╔%s╗\n║ %s ║\n╚%s╝%s\n", Purple, Bold, border, s, border, Reset) | |
| } | |
| func ask(question string) string { | |
| fmt.Printf("%s%s%s", Bold, question, Reset) | |
| reader := bufio.NewReader(os.Stdin) | |
| input, _ := reader.ReadString('\n') | |
| return strings.TrimSpace(input) | |
| } | |
| func fetchAPI(method, url string, body interface{}, token string) (map[string]interface{}, error) { | |
| var bodyReader io.Reader | |
| if body != nil { | |
| jsonData, err := json.Marshal(body) | |
| if err != nil { | |
| return nil, err | |
| } | |
| bodyReader = bytes.NewBuffer(jsonData) | |
| } | |
| req, errAPIReq := http.NewRequest(method, url, bodyReader) | |
| if errAPIReq != nil { | |
| return nil, errAPIReq | |
| } | |
| req.Header.Set("Content-Type", "application/json") | |
| if token != "" { | |
| req.Header.Set("Authorization", "Bearer "+token) | |
| } | |
| client := &http.Client{Timeout: 30 * time.Second} | |
| resp, errReq := client.Do(req) | |
| if errReq != nil { | |
| return nil, errReq | |
| } | |
| defer resp.Body.Close() | |
| respBody, errBody := io.ReadAll(resp.Body) | |
| if errBody != nil { | |
| return nil, errBody | |
| } | |
| if resp.StatusCode < 200 || resp.StatusCode >= 300 { | |
| var errorResponse map[string]interface{} | |
| json.Unmarshal(respBody, &errorResponse) | |
| if errorResponse != nil { | |
| if errMsg, ok := errorResponse["error"].(string); ok { | |
| return nil, fmt.Errorf("%s (status: %d)", errMsg, resp.StatusCode) | |
| } | |
| } | |
| return nil, fmt.Errorf("HTTP request failed with status %d", resp.StatusCode) | |
| } | |
| var result map[string]interface{} | |
| if len(respBody) > 0 { | |
| errUnm := json.Unmarshal(respBody, &result) | |
| if errUnm != nil { | |
| return nil, errUnm | |
| } | |
| } | |
| return result, nil | |
| } | |
| type Spinner struct { | |
| done chan bool | |
| } | |
| func startSpinner(label string) *Spinner { | |
| s := &Spinner{done: make(chan bool)} | |
| frames := []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"} | |
| go func() { | |
| ticker := time.NewTicker(80 * time.Millisecond) | |
| defer ticker.Stop() | |
| i := 0 | |
| for { | |
| select { | |
| case <-s.done: | |
| return | |
| case <-ticker.C: | |
| fmt.Printf("\r%s%s%s %s", Cyan, frames[i], Reset, label) | |
| i = (i + 1) % len(frames) | |
| } | |
| } | |
| }() | |
| return s | |
| } | |
| func (s *Spinner) Stop(successMsg string) { | |
| s.done <- true | |
| fmt.Printf("\r\033[K%s\n", ok(successMsg)) | |
| } | |
| func (s *Spinner) Fail(failMsg string) { | |
| s.done <- true | |
| fmt.Printf("\r\033[K%s\n", err(failMsg)) | |
| } | |
| var ValueFlags = map[string]bool{ | |
| "--username": true, "-u": true, | |
| "--password": true, "-p": true, | |
| "--host": true, | |
| "--file": true, "-f": true, | |
| "--id": true, | |
| "--limit": true, | |
| "--model": true, "-m": true, | |
| "--export": true, "-e": true, | |
| "--session": true, | |
| "--profile": true, "-pr": true, | |
| } | |
| type ParsedArgs struct { | |
| Flags map[string]string | |
| Positional []string | |
| } | |
| func parseArgs(args []string) ParsedArgs { | |
| flags := make(map[string]string) | |
| var positional []string | |
| for i := 0; i < len(args); i++ { | |
| arg := args[i] | |
| if strings.HasPrefix(arg, "-") { | |
| if strings.Contains(arg, "=") { | |
| parts := strings.SplitN(arg, "=", 2) | |
| flags[parts[0]] = parts[1] | |
| } else { | |
| if ValueFlags[arg] { | |
| if i+1 < len(args) && !strings.HasPrefix(args[i+1], "-") { | |
| flags[arg] = args[i+1] | |
| i++ | |
| } else { | |
| flags[arg] = "" | |
| } | |
| } else { | |
| flags[arg] = "true" | |
| } | |
| } | |
| } else { | |
| positional = append(positional, arg) | |
| } | |
| } | |
| return ParsedArgs{Flags: flags, Positional: positional} | |
| } | |
| func (p ParsedArgs) Get(long, short string) string { | |
| if val, ok := p.Flags[long]; ok && val != "" { | |
| return val | |
| } | |
| if val, ok := p.Flags[short]; ok && val != "" { | |
| return val | |
| } | |
| return "" | |
| } | |
| func (p ParsedArgs) Has(long, short string) bool { | |
| _, hasLong := p.Flags[long] | |
| _, hasShort := p.Flags[short] | |
| return hasLong || hasShort | |
| } | |
| func getMapVal(m map[string]interface{}, key string) interface{} { | |
| if val, ok := m[key]; ok { | |
| return val | |
| } | |
| return nil | |
| } | |
| func truncateOrPad(s string, length int) string { | |
| runes := []rune(s) | |
| if len(runes) > length { | |
| if length > 1 { | |
| return string(runes[:length-1]) + "…" | |
| } | |
| return string(runes[:length]) | |
| } | |
| return fmt.Sprintf("%-*s", length, s) | |
| } | |
| func formatDate(val interface{}) string { | |
| str, ok := val.(string) | |
| if !ok || str == "" { | |
| return "—" | |
| } | |
| t, err := time.Parse(time.RFC3339, str) | |
| if err != nil { | |
| // Try custom ISO format | |
| t, err = time.Parse("2006-01-02T15:04:05.999999", str) | |
| if err != nil { | |
| t, err = time.Parse("2006-01-02T15:04:05", str) | |
| if err != nil { | |
| return str | |
| } | |
| } | |
| } | |
| return t.Format("2006-01-02 15:04:05") | |
| } | |
| // openBrowser opens the specified URL in the default browser of the user. | |
| func openBrowser(url string) error { | |
| var cmd string | |
| var args []string | |
| switch runtime.GOOS { | |
| case "windows": | |
| cmd = "cmd" | |
| args = []string{"/c", "start"} | |
| case "darwin": | |
| cmd = "open" | |
| default: // "linux", "freebsd", "openbsd", "netbsd" | |
| cmd = "xdg-open" | |
| } | |
| args = append(args, url) | |
| return exec.Command(cmd, args...).Start() | |
| } | |
Xet Storage Details
- Size:
- 5.65 kB
- Xet hash:
- 07239396bd2c45939076ce1ed63ba27faf42dabca3f817eacf2afcc37bcdef27
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.