Author: Kevin Schoon [kevinschoon@gmail.com]
Hash: a897198dae1df4827712961562e786332eca9854
Timestamp: Thu, 29 Jul 2021 17:01:25 +0000 (3 years ago)

+105 -10 +/-5 browse
support serving and receiving requests for status via sockets
1diff --git a/README.md b/README.md
2index dac20d9..28fe9e5 100644
3--- a/README.md
4+++ b/README.md
5 @@ -59,6 +59,21 @@ Example:
6
7 ## Integrations
8
9+ By default pomo will setup a Unix socket and serve it's status there.
10+
11+ ```bash
12+ echo | socat stdio UNIX-CONNECT:/home/kevin/.pomo/pomo.sock | jq .
13+ {
14+ "state": 1,
15+ "remaining": 1492000000000,
16+ "count": 0,
17+ "n_pomodoros": 4
18+ }
19+ ```
20+
21+ Alternately by setting the `publish` flag to `true` it will publish it's status
22+ to an existing socket.
23+
24 ### Status Bars
25
26 The Pomo CLI can output the current state of a running task session via the `pomo status`
27 @@ -76,6 +91,43 @@ interval = 1
28 exec = pomo status
29 ```
30
31+ #### [luastatus](https://github.com/shdown/luastatus)
32+
33+ Configured this bar by setting `publish` to `true`.
34+
35+ ```lua
36+ widget = {
37+ plugin = "unixsock",
38+ opts = {
39+ path = "pomo.sock",
40+ timeout = 2,
41+ },
42+ cb = function(t)
43+ local full_text
44+ local foreground = ""
45+ local background = ""
46+ if t.what == "line" then
47+ if string.match(t.line, "R") then
48+ -- green
49+ foreground = "#ffffff"
50+ background = "#307335"
51+ end
52+ if string.match(t.line, "B") or string.match(t.line, "P") or string.match(t.line, "C") then
53+ -- red
54+ foreground = "#ffffff"
55+ background = "ff8080"
56+ end
57+ return { full_text = t.line, background = background, foreground = foreground }
58+ elseif t.what == "timeout" then
59+ return { full_text = "-" }
60+ elseif t.what == "hello" then
61+ return { full_text = "-" }
62+ end
63+ end,
64+ }
65+
66+ ```
67+
68
69 ## Roadmap
70
71 diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go
72index 0f6825c..2c8fdc9 100644
73--- a/pkg/cmd/cmd.go
74+++ b/pkg/cmd/cmd.go
75 @@ -212,13 +212,13 @@ func _status(config *pomo.Config) func(*cli.Cmd) {
76 cmd.Action = func() {
77 client, err := pomo.NewClient(config.SocketPath)
78 if err != nil {
79- pomo.OutputStatus(pomo.Status{})
80+ fmt.Println(pomo.FormatStatus(pomo.Status{}))
81 return
82 }
83 defer client.Close()
84 status, err := client.Status()
85 maybe(err)
86- pomo.OutputStatus(*status)
87+ fmt.Println(pomo.FormatStatus(*status))
88 }
89 }
90 }
91 diff --git a/pkg/internal/config.go b/pkg/internal/config.go
92index e5090f1..04d3a44 100644
93--- a/pkg/internal/config.go
94+++ b/pkg/internal/config.go
95 @@ -21,6 +21,12 @@ type Config struct {
96 DBPath string `json:"dbPath"`
97 SocketPath string `json:"socketPath"`
98 IconPath string `json:"iconPath"`
99+ // Publish pushes updates to the configured
100+ // SocketPath rather than listening for requests
101+ Publish bool `json:"publish"`
102+ // PublishJson pushes socket updates as a JSON
103+ // encoded status message instead of string formatted
104+ PublishJson bool `json:"publishJson"`
105 }
106
107 type ColorMap struct {
108 diff --git a/pkg/internal/server.go b/pkg/internal/server.go
109index 38357c7..03e7443 100644
110--- a/pkg/internal/server.go
111+++ b/pkg/internal/server.go
112 @@ -6,14 +6,18 @@ import (
113 "fmt"
114 "net"
115 "os"
116+ "time"
117 )
118
119 // Server listens on a Unix domain socket
120 // for Pomo status requests
121 type Server struct {
122- listener net.Listener
123- runner *TaskRunner
124- running bool
125+ listener net.Listener
126+ runner *TaskRunner
127+ running bool
128+ publish bool
129+ publishJson bool
130+ socketPath string
131 }
132
133 func (s *Server) listen() {
134 @@ -31,17 +35,50 @@ func (s *Server) listen() {
135 }
136 }
137
138+ func (s *Server) push() {
139+ ticker := time.NewTicker(1 * time.Second)
140+ for s.running {
141+ conn, err := net.Dial("unix", s.socketPath)
142+ if err != nil {
143+ <-ticker.C
144+ continue
145+ }
146+ status := s.runner.Status()
147+ if s.publishJson {
148+ raw, _ := json.Marshal(status)
149+ json.NewEncoder(conn).Encode(raw)
150+ } else {
151+ conn.Write([]byte(FormatStatus(*status) + "\n"))
152+ }
153+ conn.Close()
154+ <-ticker.C
155+ }
156+ }
157+
158 func (s *Server) Start() {
159 s.running = true
160- go s.listen()
161+ if s.publish {
162+ go s.push()
163+ } else {
164+ go s.listen()
165+ }
166 }
167
168 func (s *Server) Stop() {
169 s.running = false
170- s.listener.Close()
171+ if s.listener != nil {
172+ s.listener.Close()
173+ }
174 }
175
176 func NewServer(runner *TaskRunner, config *Config) (*Server, error) {
177+ if config.Publish {
178+ return &Server{
179+ runner: runner,
180+ publish: true,
181+ publishJson: config.PublishJson,
182+ socketPath: config.SocketPath}, nil
183+ }
184 //check if socket file exists
185 if _, err := os.Stat(config.SocketPath); err == nil {
186 _, err := net.Dial("unix", config.SocketPath)
187 diff --git a/pkg/internal/util.go b/pkg/internal/util.go
188index 70b4433..f8b0c5c 100644
189--- a/pkg/internal/util.go
190+++ b/pkg/internal/util.go
191 @@ -68,14 +68,14 @@ func SummerizeTasks(config *Config, tasks []*Task) {
192 }
193 }
194
195- func OutputStatus(status Status) {
196+ func FormatStatus(status Status) string {
197 state := "?"
198 if status.State >= RUNNING {
199 state = string(status.State.String()[0])
200 }
201 if status.State == RUNNING {
202- fmt.Printf("%s [%d/%d] %s", state, status.Count, status.NPomodoros, status.Remaining)
203+ return fmt.Sprintf("%s [%d/%d] %s", state, status.Count, status.NPomodoros, status.Remaining)
204 } else {
205- fmt.Printf("%s [%d/%d] -", state, status.Count, status.NPomodoros)
206+ return fmt.Sprintf("%s [%d/%d] -", state, status.Count, status.NPomodoros)
207 }
208 }