+86
-16
@@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -31,18 +32,19 @@ type app struct {
|
||||
quiet bool
|
||||
unattended bool
|
||||
|
||||
mu sync.RWMutex
|
||||
task taskDTO
|
||||
seq int64
|
||||
points map[string]point
|
||||
me meDTO
|
||||
ws *websocket.Conn
|
||||
wsConnected bool
|
||||
sessionCancel context.CancelFunc
|
||||
switching bool
|
||||
leaderWatch bool
|
||||
lastGuessAt time.Time
|
||||
lastGuessOK bool
|
||||
mu sync.RWMutex
|
||||
task taskDTO
|
||||
seq int64
|
||||
points map[string]point
|
||||
me meDTO
|
||||
ws *websocket.Conn
|
||||
wsConnected bool
|
||||
sessionCancel context.CancelFunc
|
||||
switching bool
|
||||
leaderWatch bool
|
||||
lastGuessAt time.Time
|
||||
lastGuessOK bool
|
||||
beaconPathMode string
|
||||
}
|
||||
|
||||
func newApp(api *apiClient, identityPath, passphrase string, maxNodes int, quiet, unattended bool) *app {
|
||||
@@ -428,6 +430,16 @@ func (a *app) refreshTask(taskID string) {
|
||||
}
|
||||
}
|
||||
|
||||
func chooseBeaconPath(mode, clientID string, seq int64) string {
|
||||
switch strings.ToUpper(strings.TrimSpace(mode)) {
|
||||
case "PULSE", "FLUX", "ORBIT":
|
||||
return strings.ToUpper(strings.TrimSpace(mode))
|
||||
}
|
||||
h := sha256.Sum256([]byte(fmt.Sprintf("nh-cli-beacon-auto|%s|%d", clientID, seq)))
|
||||
paths := []string{"PULSE", "FLUX", "ORBIT"}
|
||||
return paths[int(h[0])%len(paths)]
|
||||
}
|
||||
|
||||
func (a *app) guessLoop(ctx context.Context, taskID string) {
|
||||
for {
|
||||
a.mu.RLock()
|
||||
@@ -461,7 +473,14 @@ func (a *app) guessLoop(ctx context.Context, taskID string) {
|
||||
if t.Paused || !connected {
|
||||
continue
|
||||
}
|
||||
correct, err := a.api.guess(ctx, t, seq)
|
||||
path := ""
|
||||
if t.BeaconHuntEnabled == 1 && t.GuessLotteryMaxAccepted > 0 {
|
||||
path = chooseBeaconPath(a.beaconPathMode, a.api.cid, seq)
|
||||
if !a.quiet {
|
||||
fmt.Printf("[beacon] Pfad %s · Bonusgewicht bei Treffer ×%d\n", path, t.BeaconBonusWeight)
|
||||
}
|
||||
}
|
||||
correct, err := a.api.guess(ctx, t, seq, path)
|
||||
if err != nil {
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
@@ -613,6 +632,31 @@ func (a *app) printNFTs(ctx context.Context, limit int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *app) printMyNFTs(ctx context.Context, limit int) error {
|
||||
if limit <= 0 {
|
||||
limit = 30
|
||||
}
|
||||
items, err := a.api.ownedArtifacts(ctx, limit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("\nMEINE NFTS / ORIGINAL-ARTEFAKTE")
|
||||
fmt.Println("──────────────────────────────────────────────────────────────────────────")
|
||||
for i, n := range items {
|
||||
name := strings.TrimSpace(n.DisplayName)
|
||||
if name == "" {
|
||||
name = shortID(n.TaskID)
|
||||
}
|
||||
fmt.Printf("%2d %-24s task=%-16s %3dbit %s\n", i+1, name, shortID(n.TaskID), n.RangeBits, n.CompletedAt.Local().Format("2006-01-02 15:04"))
|
||||
fmt.Printf(" Original: %s%s\n", a.api.base, n.DownloadURI)
|
||||
}
|
||||
if len(items) == 0 {
|
||||
fmt.Println("(für diese Identität noch keine fertigen Gewinner-Artefakte)")
|
||||
}
|
||||
fmt.Println()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *app) watcher(ctx context.Context) {
|
||||
t := time.NewTicker(5 * time.Second)
|
||||
defer t.Stop()
|
||||
@@ -638,7 +682,7 @@ func (a *app) watcher(ctx context.Context) {
|
||||
|
||||
func (a *app) commandLoop(ctx context.Context, in io.Reader) error {
|
||||
s := bufio.NewScanner(in)
|
||||
fmt.Println("Befehle: help, tasks, use <nr|id|name>, status, map [n], leaderboard [n|watch|stop], nfts [n], nft get <task-id> <datei>, identity, identity export <datei>, quit")
|
||||
fmt.Println("Befehle: help, tasks, use <nr|id|name>, status, map [n], leaderboard [n|watch|stop], nfts [n], my-nfts [n], nft get <task-id> <datei>, nft original <task-id> <datei>, identity, identity export <datei>, hosted-code, quit")
|
||||
for {
|
||||
fmt.Print("neuralhunt> ")
|
||||
if !s.Scan() {
|
||||
@@ -658,10 +702,13 @@ func (a *app) commandLoop(ctx context.Context, in io.Reader) error {
|
||||
fmt.Println(" map [n] textuelles Target Field / Nähe")
|
||||
fmt.Println(" leaderboard [n] Live-Rangliste")
|
||||
fmt.Println(" leaderboard watch|stop Rangliste alle 5s ein/aus")
|
||||
fmt.Println(" nfts [n] Wasserzeichen-NFTs anzeigen")
|
||||
fmt.Println(" nfts [n] öffentliche Wasserzeichen-NFTs anzeigen")
|
||||
fmt.Println(" my-nfts [n] eigene Gewinner-Artefakte anzeigen")
|
||||
fmt.Println(" nft get <task-id> <datei> Wasserzeichen-Preview speichern")
|
||||
fmt.Println(" nft original <task-id> <datei> eigenes Original speichern")
|
||||
fmt.Println(" identity Client-ID und Identity-Datei")
|
||||
fmt.Println(" identity export <datei> browser-kompatiblen verschlüsselten Export schreiben")
|
||||
fmt.Println(" hosted-code 10-Minuten-Code zum Koppeln als Reward-Identität")
|
||||
fmt.Println(" quit beenden")
|
||||
case "tasks":
|
||||
if _, err := a.printTasks(ctx); err != nil {
|
||||
@@ -723,6 +770,14 @@ func (a *app) commandLoop(ctx context.Context, in io.Reader) error {
|
||||
if err := a.printNFTs(ctx, n); err != nil {
|
||||
fmt.Println("Fehler:", err)
|
||||
}
|
||||
case "my-nfts", "mine":
|
||||
n := 30
|
||||
if len(parts) > 1 {
|
||||
n, _ = strconv.Atoi(parts[1])
|
||||
}
|
||||
if err := a.printMyNFTs(ctx, n); err != nil {
|
||||
fmt.Println("Fehler:", err)
|
||||
}
|
||||
case "nft":
|
||||
if len(parts) == 4 && strings.EqualFold(parts[1], "get") {
|
||||
if err := a.api.downloadPreview(ctx, parts[2], parts[3]); err != nil {
|
||||
@@ -730,8 +785,14 @@ func (a *app) commandLoop(ctx context.Context, in io.Reader) error {
|
||||
} else {
|
||||
fmt.Println("Wasserzeichen-Preview gespeichert:", parts[3])
|
||||
}
|
||||
} else if len(parts) == 4 && (strings.EqualFold(parts[1], "original") || strings.EqualFold(parts[1], "download")) {
|
||||
if err := a.api.downloadOwnedArtifact(ctx, parts[2], parts[3]); err != nil {
|
||||
fmt.Println("Fehler:", err)
|
||||
} else {
|
||||
fmt.Println("Original-Artefakt gespeichert:", parts[3])
|
||||
}
|
||||
} else {
|
||||
fmt.Println("nft get <task-id> <datei>")
|
||||
fmt.Println("nft get <task-id> <datei> | nft original <task-id> <datei>")
|
||||
}
|
||||
case "identity", "id":
|
||||
if len(parts) >= 2 && strings.EqualFold(parts[1], "export") {
|
||||
@@ -748,6 +809,15 @@ func (a *app) commandLoop(ctx context.Context, in io.Reader) error {
|
||||
fmt.Println("Client-ID:", a.api.cid)
|
||||
fmt.Println("Identity :", a.identityPath)
|
||||
}
|
||||
case "hosted-code", "hosted-link":
|
||||
x, err := a.api.hostedLinkCode(ctx)
|
||||
if err != nil {
|
||||
fmt.Println("Fehler:", err)
|
||||
} else {
|
||||
fmt.Println("Hosted-Code:", x.Code)
|
||||
fmt.Println("Client-ID :", x.ClientID)
|
||||
fmt.Println("Gültig bis :", x.ExpiresAt.Local().Format(time.RFC3339))
|
||||
}
|
||||
case "quit", "exit", "q":
|
||||
return nil
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user