-
Notifications
You must be signed in to change notification settings - Fork 14
/
status.go
125 lines (102 loc) · 2.69 KB
/
status.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/* ipp-usb - HTTP reverse proxy, backed by IPP-over-USB connection to device
*
* Copyright (C) 2020 and up by Alexander Pevzner ([email protected])
* See LICENSE for license terms and conditions
*
* ipp-usb status support
*/
package main
import (
"bytes"
"fmt"
"io/ioutil"
"net"
"net/http"
"sort"
"sync"
)
// statusOfDevice represents a status of the particular device
type statusOfDevice struct {
desc UsbDeviceDesc // Device descriptor
init error // Initialization error, nil if none
}
var (
// statusTable maintains a per-device status,
// indexed by the UsbAddr
statusTable = make(map[UsbAddr]*statusOfDevice)
// statusLock protects access to the statusTable
statusLock sync.RWMutex
)
// StatusRetrieve connects to the running ipp-usb daemon, retrieves
// its status and returns retrieved status as a printable text
func StatusRetrieve() ([]byte, error) {
t := &http.Transport{
Dial: func(network, addr string) (net.Conn, error) {
return CtrlsockDial()
},
}
c := &http.Client{
Transport: t,
}
rsp, err := c.Get("http://localhost/status")
if err != nil {
return nil, err
}
defer rsp.Body.Close()
return ioutil.ReadAll(rsp.Body)
}
// StatusFormat formats ipp-usb status as a text
func StatusFormat() []byte {
buf := &bytes.Buffer{}
// Lock the statusTable
statusLock.RLock()
defer statusLock.RUnlock()
// Dump ipp-usb daemon status. If we are here, we are
// definitely running :-)
buf.WriteString("ipp-usb daemon: running\n")
// Sort devices by address
devs := make([]*statusOfDevice, len(statusTable))
i := 0
for _, status := range statusTable {
devs[i] = status
}
sort.Slice(devs, func(i, j int) bool {
return devs[i].desc.UsbAddr.Less(devs[j].desc.UsbAddr)
})
// Format per-device status
buf.WriteString("ipp-usb devices:")
if len(statusTable) == 0 {
buf.WriteString(" not found\n")
} else {
buf.WriteString("\n")
fmt.Fprintf(buf, " Num Device Vndr:Prod Model\n")
for i, status := range devs {
info, _ := status.desc.GetUsbDeviceInfo()
fmt.Fprintf(buf, " %3d. %s %4.4x:%.4x %q\n",
i+1, status.desc.UsbAddr,
info.Vendor, info.Product, info.MfgAndProduct)
s := "OK"
if status.init != nil {
s = devs[i].init.Error()
}
fmt.Fprintf(buf, " status: %s", s)
}
}
return buf.Bytes()
}
// StatusSet adds device to the status table or updates status
// of the already known device
func StatusSet(addr UsbAddr, desc UsbDeviceDesc, init error) {
statusLock.Lock()
statusTable[addr] = &statusOfDevice{
desc: desc,
init: init,
}
statusLock.Unlock()
}
// StatusDel deletes device from the status table
func StatusDel(addr UsbAddr) {
statusLock.Lock()
delete(statusTable, addr)
statusLock.Unlock()
}