a438f6212b
Drop the constructor guard so client import-all (Devices empty/omitted) actually works, route ledger lease mutations through a new mutateAndBroadcast helper so Unsubscribe-triggered release reaches all subscribers, and tighten the Events contract: subscribe at Start so a host failure aborts service start instead of silently disabling hotplug.
73 lines
1.7 KiB
Go
73 lines
1.7 KiB
Go
package option
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
E "github.com/sagernet/sing/common/exceptions"
|
|
"github.com/sagernet/sing/common/json"
|
|
)
|
|
|
|
type USBIPHexUint16 uint16
|
|
|
|
func (h USBIPHexUint16) MarshalJSON() ([]byte, error) {
|
|
if h == 0 {
|
|
return []byte(`""`), nil
|
|
}
|
|
return json.Marshal(fmt.Sprintf("0x%04x", uint16(h)))
|
|
}
|
|
|
|
func (h *USBIPHexUint16) UnmarshalJSON(data []byte) error {
|
|
var asNumber uint64
|
|
err := json.Unmarshal(data, &asNumber)
|
|
if err == nil {
|
|
if asNumber > 0xffff {
|
|
return E.New("usb id out of uint16 range: ", asNumber)
|
|
}
|
|
*h = USBIPHexUint16(asNumber)
|
|
return nil
|
|
}
|
|
var asString string
|
|
err = json.Unmarshal(data, &asString)
|
|
if err != nil {
|
|
return E.Cause(err, "parse usb id")
|
|
}
|
|
asString = strings.TrimSpace(asString)
|
|
if asString == "" {
|
|
*h = 0
|
|
return nil
|
|
}
|
|
asString = strings.TrimPrefix(strings.TrimPrefix(asString, "0x"), "0X")
|
|
parsed, err := strconv.ParseUint(asString, 16, 16)
|
|
if err != nil {
|
|
return E.Cause(err, "parse usb id ", asString)
|
|
}
|
|
*h = USBIPHexUint16(parsed)
|
|
return nil
|
|
}
|
|
|
|
type USBIPDeviceMatch struct {
|
|
BusID string `json:"busid,omitempty"`
|
|
VendorID USBIPHexUint16 `json:"vendor_id,omitempty"`
|
|
ProductID USBIPHexUint16 `json:"product_id,omitempty"`
|
|
Serial string `json:"serial,omitempty"`
|
|
}
|
|
|
|
func (m USBIPDeviceMatch) IsZero() bool {
|
|
return m.BusID == "" && m.VendorID == 0 && m.ProductID == 0 && m.Serial == ""
|
|
}
|
|
|
|
type USBIPServerServiceOptions struct {
|
|
ListenOptions
|
|
Devices []USBIPDeviceMatch `json:"devices,omitempty"`
|
|
}
|
|
|
|
type USBIPClientServiceOptions struct {
|
|
ServerOptions
|
|
DialerOptions
|
|
// Devices selects which exported devices to import. Omit or leave
|
|
// empty to import every device the server exports.
|
|
Devices []USBIPDeviceMatch `json:"devices,omitempty"`
|
|
}
|