Skip to content

Commit 919bbbb

Browse files
committed
Refactor
- Remove stuff I don't use for now. - A single source can now update multiple status items in a single tick.
1 parent f02108a commit 919bbbb

File tree

12 files changed

+368
-452
lines changed

12 files changed

+368
-452
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/cmd/*/*
2+
!/cmd/*/*.go

README.md

+2-30
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,8 @@
22

33
My custom status for i3bar.
44

5-
There's no configuration files, everything is decided at compile time.
6-
7-
I don't even use this anymore, but I also don't want to archive it just
8-
yet.
9-
10-
## Compile-time requirements
11-
12-
* Go compiler. See the `go.mod' file to know which version I was using
13-
last time I updated this repository.
14-
15-
## Runtime requirements
16-
17-
* A running instance of MPD. Take a look at the `cmd/dsts' package to
18-
know which port number is expected.
19-
20-
## What is being displayed
21-
22-
* Current date and time in the same format as Skyrim.
23-
* Song currently playing in MPD.
24-
25-
## How it works
26-
27-
Each `component' is a function receiving a channel as its only argument.
28-
Each time a status is sent to that channel, a refresh is triggered.
29-
30-
The main program coordinates all those updates, and sends new messages
31-
when necessary.
32-
33-
This allows components to each have their own `refresh rate', instead of
34-
using a single global refresh rate for everything.
5+
There's runtime no configuration files. The whole point of this, is to
6+
have a single executable that just works.
357

368
## License
379

cmd/dsts/main.go

+78-45
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,37 @@
44
package main
55

66
import (
7+
"context"
78
"encoding/json"
9+
"errors"
810
"os"
911
"sync"
1012

1113
"github.com/c032/dsts"
12-
"github.com/c032/dsts/mpd"
13-
"github.com/c032/dsts/tamrieltime"
14+
timesource "github.com/c032/dsts/sources/time"
1415
)
1516

16-
const (
17-
// mpdAddr is the address where MPD is listening in.
18-
mpdAddr = ":6600"
17+
func main() {
18+
rootContext := context.Background()
19+
ctx, cancel := context.WithCancelCause(rootContext)
1920

20-
// mpdStatusMaxWidth is the maximum width, in characters, allowed for the
21-
// MPD status.
22-
mpdStatusMaxWidth = 80
23-
)
21+
srcTime, err := timesource.New(ctx, nil)
22+
if err != nil {
23+
// Programmer error.
24+
panic(err)
25+
}
2426

25-
func main() {
26-
// Active providers, in the same order that they will be displayed in the
27-
// i3bar.
27+
sources := []dsts.Source{
28+
srcTime,
29+
}
30+
31+
// Active status readers, in the same order that they will be displayed in
32+
// the i3bar.
2833
//
29-
// Providers with a lower index will be displayed somewhere to the left of
30-
// providers with a higher index.
31-
providers := []dsts.Provider{
32-
dsts.Wrap(
33-
mpd.Dial(mpdAddr),
34-
mpdStatusMaxWidth,
35-
),
36-
tamrieltime.TamrielTime,
34+
// From left to right. Index `0` if leftmost.
35+
statusReaders := []dsts.StatusReader{
36+
srcTime.StatusUnix,
37+
srcTime.StatusDateTime,
3738
}
3839

3940
enc := json.NewEncoder(os.Stdout)
@@ -42,40 +43,72 @@ func main() {
4243

4344
// tick is only used to notify when the status line must be updated.
4445
tick := make(chan struct{})
46+
go func(ctx context.Context) {
47+
<-ctx.Done()
4548

46-
// mu prevents multiple goroutines from modifying `i3sts` at the same time.
47-
mu := sync.RWMutex{}
48-
49-
// i3sts is what will be serialized as JSON and printed to standard output.
50-
i3sts := make([]dsts.I3Status, len(providers))
51-
52-
// Run each provider on their own goroutine, coordinate updates to the
53-
// i3status line, and trigger a refresh when necessary.
54-
for i, p := range providers {
55-
ch := make(chan dsts.I3Status)
56-
57-
// Run the provider, usually forever.
58-
go p(ch)
49+
close(tick)
50+
}(ctx)
5951

60-
// For each update from the provider, update the current status and
61-
// trigger a refresh.
62-
go func(i int, p dsts.Provider) {
63-
for status := range ch {
64-
mu.Lock()
65-
i3sts[i] = status
66-
mu.Unlock()
52+
// `mu` prevents multiple goroutines from modifying `i3sts` at the same
53+
// time.
54+
mu := sync.RWMutex{}
6755

56+
// `i3sts` is what will be serialized as JSON and printed to standard
57+
// output.
58+
i3sts := make([]dsts.I3Status, len(statusReaders))
59+
60+
// Trigger a refresh each time a source has an update.
61+
for _, s := range sources {
62+
// `ch` receives a value when there's an update.
63+
//
64+
// The `Subscribe` method will close `ch`.
65+
ch := s.Subscribe(ctx)
66+
67+
// Start listening for updates in background.
68+
//
69+
// This goroutine will exit when `ch` is closed.
70+
go func(tick chan<- struct{}, ch <-chan struct{}) {
71+
for range ch {
6872
tick <- struct{}{}
6973
}
70-
}(i, p)
74+
}(tick, ch)
7175
}
7276

73-
// Wait for a refresh to trigger, and update the status line.
77+
// Wait for a refresh to trigger. Then read from all status readers and
78+
// update the status line.
7479
for range tick {
80+
if ctx.Err() != nil {
81+
// The error will be handled outside the loop.
82+
break
83+
}
84+
7585
os.Stdout.Write([]byte{','})
7686

77-
mu.RLock()
78-
_ = enc.Encode(i3sts)
79-
mu.RUnlock()
87+
mu.Lock()
88+
89+
for i, readStatus := range statusReaders {
90+
i3sts[i] = readStatus()
91+
}
92+
93+
var err error
94+
err = enc.Encode(i3sts)
95+
96+
mu.Unlock()
97+
98+
if err != nil {
99+
cancel(err)
100+
}
101+
}
102+
103+
err = ctx.Err()
104+
if err != nil {
105+
if !errors.Is(err, context.Canceled) {
106+
os.Exit(1)
107+
}
108+
109+
cause := context.Cause(ctx)
110+
if cause != nil && cause != err {
111+
os.Exit(1)
112+
}
80113
}
81114
}

color.go

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package dsts
2+
3+
import (
4+
"errors"
5+
)
6+
7+
var ErrInvalidColor = errors.New("invalid color")
8+
9+
const DefaultStatusColor = "#999999"
10+
11+
func isNumber(c rune) bool {
12+
return c >= '0' && c <= '9'
13+
}
14+
15+
func IsValidColor(color string) bool {
16+
if len(color) != len("#000") && len(color) != len("#000000") {
17+
return false
18+
}
19+
if color[0] != '#' {
20+
return false
21+
}
22+
23+
for i, c := range color {
24+
if i == 0 {
25+
continue
26+
}
27+
if !isNumber(c) {
28+
return false
29+
}
30+
}
31+
32+
return true
33+
}

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module github.com/c032/dsts
22

3-
go 1.12
3+
go 1.21.6

0 commit comments

Comments
 (0)