File: status.go

package info (click to toggle)
ipp-usb 0.9.30-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 756 kB
  • sloc: sh: 80; makefile: 40
file content (135 lines) | stat: -rw-r--r-- 2,989 bytes parent folder | download
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
/* 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)
}

// 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
		i++
	}

	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  Port  Model\n")
		for i, status := range devs {
			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.MfgAndProduct)

			s = "OK"
			if status.init != nil {
				s = devs[i].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()
}