Repository navigation
Expand file tree
/
Copy pathstatus.go
More file actions
138 lines (115 loc) · 3.1 KB
/
Copy pathstatus.go
File metadata and controls
138 lines (115 loc) · 3.1 KB
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
126
127
128
129
130
131
132
133
134
135
136
137
138
/* ipp-usb - HTTP reverse proxy, backed by IPP-over-USB connection to device
*
* Copyright (C) 2020 and up by Alexander Pevzner (pzz@apevzner.com)
* See LICENSE for license terms and conditions
*
* ipp-usb status support
*/
package main
import (
"bytes"
"fmt"
"io/ioutil"
"net"
"net/http"
"sort"
"strconv"
"sync"
)
// StatusOfDevice represents a status of the particular device
type StatusOfDevice struct {
desc UsbDeviceDesc // Device descriptor
init error // Initialization error, nil if none
HTTPPort int // Assigned http port for the device
}
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)
}
// StatusGet returns snapshot of the current status table
func StatusGet() []*StatusOfDevice {
// Snapshot the table
statusLock.RLock()
statuses := make([]*StatusOfDevice, 0, len(statusTable))
for _, status := range statusTable {
statuses = append(statuses, status)
}
statusLock.RUnlock()
// Sort statuses by address
sort.Slice(statuses, func(i, j int) bool {
return statuses[i].desc.UsbAddr.Less(statuses[j].desc.UsbAddr)
})
return statuses
}
// StatusFormat formats ipp-usb status as a text
func StatusFormat() []byte {
// Snapshot the statusTable
statuses := StatusGet()
// Dump ipp-usb daemon status. If we are here, we are
// definitely running :-)
buf := &bytes.Buffer{}
buf.WriteString("ipp-usb daemon: running\n")
// 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 Port Model\n")
for i, status := range statuses {
info, _ := status.desc.GetUsbDeviceInfo()
s := "-"
if status.HTTPPort != 0 {
s = strconv.Itoa(status.HTTPPort)
}
fmt.Fprintf(buf, " %3d. %s %4.4x:%.4x %-5s %q\n",
i+1, status.desc.UsbAddr,
info.Vendor, info.Product, s,
info.MakeAndModel())
s = "OK"
if status.init != nil {
s = status.init.Error()
}
fmt.Fprintf(buf, " status: %s\n", 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, HTTPPort int, init error) {
statusLock.Lock()
statusTable[addr] = &StatusOfDevice{
desc: desc,
init: init,
HTTPPort: HTTPPort,
}
statusLock.Unlock()
}
// StatusDel deletes device from the status table
func StatusDel(addr UsbAddr) {
statusLock.Lock()
delete(statusTable, addr)
statusLock.Unlock()
}