package utils import ( "context" "database/sql" "encoding/base64" "fmt" "log" "log/slog" "net" "os" "path/filepath" "reflect" "time" ) const rsaBits = 4096 func GetFilePath(path string) string { // Check for empty filename if len(path) == 0 { return "" } // check if filename exists if _, err := os.Stat(path); os.IsNotExist((err)) { slog.Info("File not found, searching in same directory as binary", "filename", path) // if not, check that it exists in the same directory as the currently executing binary ex, err2 := os.Executable() if err2 != nil { slog.Error("Error determining binary path", "error", err) return "" } binaryPath := filepath.Dir(ex) path = filepath.Join(binaryPath, path) slog.Info("Found file", "path", path) } return path } // Get preferred outbound ip of this machine // @see https://stackoverflow.com/questions/23558425/how-do-i-get-the-local-ip-address-in-go func GetOutboundIP() net.IP { conn, err := net.Dial("udp", "8.8.8.8:80") if err != nil { log.Fatal(err) } defer conn.Close() localAddr := conn.LocalAddr().(*net.UDPAddr) return localAddr.IP } // Check if a file exists from https://stackoverflow.com/questions/12518876/how-to-check-if-a-file-exists-in-go func FileExists(filename string) bool { info, err := os.Stat(filename) if os.IsNotExist(err) { return false } return !info.IsDir() } func SleepWithContext(ctx context.Context, d time.Duration) { timer := time.NewTimer(d) select { case <-ctx.Done(): if !timer.Stop() { <-timer.C } case <-timer.C: } } // Generic converter using reflection for all sqlc/sqlite types func ConvertStruct(src interface{}, dst interface{}) { srcVal := reflect.ValueOf(src) srcType := reflect.TypeOf(src) dstVal := reflect.ValueOf(dst).Elem() for i := 0; i < srcVal.NumField(); i++ { srcField := srcVal.Field(i) srcFieldType := srcField.Type() dstField := dstVal.FieldByName(srcType.Field(i).Name) //slog.Info("Source field", "name", srcType.Field(i).Name) if !dstField.IsValid() || !dstField.CanSet() { continue } switch srcFieldType { case reflect.TypeOf(sql.NullString{}): //slog.Info("Sourcefield is string") if srcField.FieldByName("Valid").Bool() { dstField.SetString(srcField.FieldByName("String").String()) } else { dstField.SetString("") } case reflect.TypeOf(sql.NullInt64{}): //slog.Info("Sourcefield is int64") if srcField.FieldByName("Valid").Bool() { val := srcField.FieldByName("Int64").Int() if dstField.Kind() == reflect.String { dstField.SetString(fmt.Sprintf("%d", val)) } else { dstField.SetInt(val) } } else { if dstField.Kind() == reflect.String { dstField.SetString("") } else { dstField.SetInt(0) } } case reflect.TypeOf(sql.NullFloat64{}): if srcField.FieldByName("Valid").Bool() { val := srcField.FieldByName("Float64").Float() if dstField.Kind() == reflect.String { dstField.SetString(fmt.Sprintf("%f", val)) } else { dstField.SetFloat(val) } } else { if dstField.Kind() == reflect.String { dstField.SetString("") } else { dstField.SetFloat(0) } } case reflect.TypeOf(sql.NullBool{}): if srcField.FieldByName("Valid").Bool() { val := srcField.FieldByName("Bool").Bool() if dstField.Kind() == reflect.String { dstField.SetString(fmt.Sprintf("%t", val)) } else { dstField.SetBool(val) } } else { if dstField.Kind() == reflect.String { dstField.SetString("") } else { dstField.SetBool(false) } } case reflect.TypeOf(sql.NullTime{}): //slog.Info("Sourcefield is time") if srcField.FieldByName("Valid").Bool() { t := srcField.FieldByName("Time").Interface().(time.Time) dstField.SetString(t.Format("2006-01-02 15:04:05")) } else { slog.Info("value is not valid") dstField.SetString("") } default: // Handle []byte (often from BLOB fields) if srcField.Kind() == reflect.Slice && srcField.Type().Elem().Kind() == reflect.Uint8 { if !srcField.IsNil() { encoded := base64.StdEncoding.EncodeToString(srcField.Bytes()) dstField.SetString(encoded) } else { dstField.SetString("") } } // Fallback: copy if types are directly assignable if srcField.Type().AssignableTo(dstField.Type()) { dstField.Set(srcField) } } } }