tahamajs/IE / Projects /cli /utils.go
tahamajs's picture
download
raw
5.65 kB
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.