WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit d88592d

Browse files
authored
Merge pull request #210 from cmsax/main
feat: add an HTTP server to enable users to monitor status updates via status bars or other UI components.
2 parents 77ce0b9 + d4ec079 commit d88592d

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

progressbar.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ package progressbar
22

33
import (
44
"bytes"
5+
"encoding/json"
56
"errors"
67
"fmt"
78
"io"
9+
"log"
810
"math"
11+
"net/http"
912
"os"
1013
"regexp"
1114
"strings"
@@ -1009,6 +1012,31 @@ func (p *ProgressBar) State() State {
10091012
return s
10101013
}
10111014

1015+
// StartHTTPServer starts an HTTP server dedicated to serving progress bar updates. This allows you to
1016+
// display the status in various UI elements, such as an OS status bar with an `xbar` extension.
1017+
// It is recommended to run this function in a separate goroutine to avoid blocking the main thread.
1018+
//
1019+
// hostPort specifies the address and port to bind the server to, for example, "0.0.0.0:19999".
1020+
func (p *ProgressBar) StartHTTPServer(hostPort string) {
1021+
// for advanced users, we can return the data as json
1022+
http.HandleFunc("/state", func(w http.ResponseWriter, r *http.Request) {
1023+
w.Header().Set("Content-Type", "text/json")
1024+
// since the state is a simple struct, we can just ignore the error
1025+
bs, _ := json.Marshal(p.State())
1026+
w.Write(bs)
1027+
})
1028+
// for others, we just return the description in a plain text format
1029+
http.HandleFunc("/desc", func(w http.ResponseWriter, r *http.Request) {
1030+
w.Header().Set("Content-Type", "text/plain")
1031+
fmt.Fprintf(w,
1032+
"%d/%d, %.2f%%, %s left",
1033+
p.State().CurrentNum, p.State().Max, p.State().CurrentPercent*100,
1034+
(time.Second * time.Duration(p.State().SecondsLeft)).String(),
1035+
)
1036+
})
1037+
log.Fatal(http.ListenAndServe(hostPort, nil))
1038+
}
1039+
10121040
// regex matching ansi escape codes
10131041
var ansiRegex = regexp.MustCompile(`\x1b\[[0-9;]*[a-zA-Z]`)
10141042

progressbar_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"crypto/md5"
66
"encoding/hex"
7+
"encoding/json"
78
"fmt"
89
"io"
910
"log"
@@ -1123,3 +1124,42 @@ func TestOptionShowTotalTrueIndeterminate(t *testing.T) {
11231124
t.Errorf("wrong string: %s", buf.String())
11241125
}
11251126
}
1127+
1128+
func TestStartHTTPServer(t *testing.T) {
1129+
bar := Default(10, "test")
1130+
bar.Add(1)
1131+
1132+
hostPort := "localhost:9696"
1133+
go bar.StartHTTPServer(hostPort)
1134+
1135+
// check plain text
1136+
resp, err := http.Get(fmt.Sprintf("http://%s/desc", hostPort))
1137+
if err != nil {
1138+
t.Error(err)
1139+
}
1140+
got, err := io.ReadAll(resp.Body)
1141+
if err != nil {
1142+
t.Error(err)
1143+
}
1144+
if string(got) != "1/10, 10.00%, 0s left" {
1145+
t.Errorf("wrong string: %s", string(got))
1146+
}
1147+
1148+
// check json
1149+
resp, err = http.Get(fmt.Sprintf("http://%s/state", hostPort))
1150+
if err != nil {
1151+
t.Error(err)
1152+
}
1153+
got, err = io.ReadAll(resp.Body)
1154+
if err != nil {
1155+
t.Error(err)
1156+
}
1157+
var result State
1158+
err = json.Unmarshal(got, &result)
1159+
if err != nil {
1160+
t.Error(err)
1161+
}
1162+
if result.Max != bar.State().Max || result.CurrentNum != bar.State().CurrentNum {
1163+
t.Errorf("wrong state: %v", result)
1164+
}
1165+
}

0 commit comments

Comments
 (0)