Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions daze.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (

"github.com/mohanson/daze/lib/doa"
"github.com/mohanson/daze/lib/lru"
"github.com/mohanson/daze/lib/pretty"
)

// ============================================================================
Expand Down Expand Up @@ -1052,6 +1053,24 @@ func (r *RandomReader) Read(p []byte) (int, error) {
return len(p), nil
}

// The PrettyReader struct represents a custom reader that keeps track of read bytes and prints progress.
type PrettyReader struct {
E uint64 // Total number of bytes read so far
F uint64 // Total capacity of the input stream
R io.Reader // The underlying reader that this object wraps around
}

// The Read method reads data from the wrapped reader and prints progress updates.
func (r *PrettyReader) Read(p []byte) (int, error) {
if r.E == 0 {
pretty.PrintProgress(0)
}
n, err := r.R.Read(p)
r.E += uint64(n)
pretty.PrintProgress(float64(r.E) / float64(r.F))
return n, err
}

// Salt converts the stupid password passed in by the user to 32-sized byte array.
func Salt(s string) []byte {
h := sha256.Sum256([]byte(s))
Expand All @@ -1075,8 +1094,14 @@ func Salt(s string) []byte {
// LoadApnic loads remote resource. APNIC is the Regional Internet Registry administering IP addresses for the Asia
// Pacific.
func LoadApnic() map[string][]*net.IPNet {
log.Println("main: load apnic data from http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest")
f := doa.Try(OpenFile("http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest"))
url := "http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest"
log.Println("main: load apnic data from", url)
rep := doa.Try(http.Get(url))
f := &ReadWriteCloser{
Reader: &PrettyReader{0, uint64(rep.ContentLength), rep.Body},
Writer: nil,
Closer: rep.Body,
}
defer f.Close()
r := map[string][]*net.IPNet{}
s := bufio.NewScanner(f)
Expand Down
29 changes: 29 additions & 0 deletions lib/pretty/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Pretty

Utilities to prettify console output.

**Progress**

```
$ go run cmd/progress/main.go

2025/03/12 09:53:42 pretty: [=========================> ] 59%
```



**Table**

```
$ go run cmd/table/main.go

2025/03/12 09:51:57 pretty: City name Area Population Annual Rainfall
2025/03/12 09:51:57 pretty: -----------------------------------------
2025/03/12 09:51:57 pretty: Adelaide 1295 1158259 600.5
2025/03/12 09:51:57 pretty: Brisbane 5905 1857594 1146.4
2025/03/12 09:51:57 pretty: Darwin 112 120900 1714.7
2025/03/12 09:51:57 pretty: Hobart 1357 205556 619.5
2025/03/12 09:51:57 pretty: Melbourne 1566 3806092 646.9
2025/03/12 09:51:57 pretty: Perth 5386 1554769 869.4
2025/03/12 09:51:57 pretty: Sydney 2058 4336374 1214.8
```
16 changes: 16 additions & 0 deletions lib/pretty/cmd/progress/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package main

import (
"time"

"github.com/mohanson/daze/lib/pretty"
)

func main() {
pretty.PrintProgress(0)
for i := range 100 {
time.Sleep(time.Millisecond * 16)
pretty.PrintProgress(float64(i+1) / 100)
}
pretty.PrintProgress(1)
}
18 changes: 18 additions & 0 deletions lib/pretty/cmd/table/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package main

import (
"github.com/mohanson/daze/lib/pretty"
)

func main() {
pretty.PrintTable([][]string{
{"City name", "Area", "Population", "Annual Rainfall"},
{"Adelaide", "1295", "1158259", "600.5"},
{"Brisbane", "5905", "1857594", "1146.4"},
{"Darwin", "112", "120900", "1714.7"},
{"Hobart", "1357", "205556", "619.5"},
{"Melbourne", "1566", "3806092", "646.9"},
{"Perth", "5386", "1554769", "869.4"},
{"Sydney", "2058", "4336374", "1214.8"},
})
}
64 changes: 64 additions & 0 deletions lib/pretty/pretty.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package pretty

import (
"fmt"
"log"
"os"
"strings"

"github.com/mohanson/daze/lib/doa"
)

// PrintProgress draw a progress bar in the terminal. The percent takes values ​​from 0 to 1.
func PrintProgress(percent float64) {
doa.Doa(0 <= percent && percent <= 1)
out, _ := os.Stdout.Stat()
// Identify if we are displaying to a terminal or through a pipe or redirect.
if out.Mode()&os.ModeCharDevice == os.ModeCharDevice {
// Save or restore cursor position.
if percent == 0 {
log.Writer().Write([]byte{0x1b, 0x37})
}
if percent != 0 {
log.Writer().Write([]byte{0x1b, 0x38})
}
}
cap := int(percent * 44)
buf := []byte("[ ] 000%")
for i := 1; i < cap+1; i++ {
buf[i] = '='
}
buf[1+cap] = '>'
num := fmt.Sprintf("%3d", int(percent*100))
buf[48] = num[0]
buf[49] = num[1]
buf[50] = num[2]
log.Println("pretty:", string(buf))
}

// PrintTable easily draw tables in terminal/console applications from a list of lists of strings.
func PrintTable(data [][]string) {
size := make([]int, len(data[0]))
for _, r := range data {
for j, c := range r {
size[j] = max(size[j], len(c))
}
}
line := make([]string, len(data[0]))
for j, c := range data[0] {
l := size[j]
line[j] = strings.Repeat(" ", l-len(c)) + c
}
log.Println("pretty:", strings.Join(line, " "))
for i, c := range size {
line[i] = strings.Repeat("-", c)
}
log.Println("pretty:", strings.Join(line, "-"))
for _, r := range data[1:] {
for j, c := range r {
l := size[j]
line[j] = strings.Repeat(" ", l-len(c)) + c
}
log.Println("pretty:", strings.Join(line, " "))
}
}
Loading
Loading