func (p *V2) init() error { p.RLock() if p.initialized { p.RUnlock() return nil } p.RUnlock() p.Lock() defer p.Unlock() if p.Port == 0 { p.Port = shared.DefaultPort } socket, err := net.ListenUDP(`udp4`, &net.UDPAddr{Port: p.Port}) if err != nil { return err } p.socket = socket addr := net.UDPAddr{ IP: net.IPv4(255, 255, 255, 255), Port: shared.DefaultPort, } broadcastDev, err := device.New(&addr, p.socket, p.timeout, p.retryInterval, false, nil) if err != nil { return err } p.broadcast = &device.Light{Device: broadcastDev} broadcastSub, err := p.broadcast.NewSubscription() if err != nil { return err } p.deviceQueue = make(chan device.GenericDevice, 16) p.devices = make(map[uint64]device.GenericDevice) p.locations = make(map[string]*device.Location) p.groups = make(map[string]*device.Group) p.subscriptions = make(map[string]*common.Subscription) p.quitChan = make(chan struct{}) go p.broadcastLimiter(broadcastSub.Events()) go p.dispatcher() go p.addDevices() p.initialized = true return nil }
func (p *V2) process(pkt *packet.Packet, addr *net.UDPAddr) { common.Log.Debugf("Processing packet from %v: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", addr.IP, pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) // Update device seen time for any targeted packets if pkt.Target != 0 { dev, err := p.getDevice(pkt.Target) if err == nil { dev.SetSeen(time.Now()) } } // Broadcast packets, or packets generated by other clients if pkt.GetSource() != packet.ClientID { switch pkt.GetType() { case device.StatePower: dev, err := p.getDevice(pkt.GetTarget()) if err != nil { common.Log.Debugf("Skipping StatePower packet for unknown device: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) return } err = dev.SetStatePower(pkt) if err != nil { common.Log.Debugf("Failed setting StatePower on device: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) return } case device.StateLabel: dev, err := p.getDevice(pkt.GetTarget()) if err != nil { common.Log.Debugf("Skipping StateLabel packet for unknown device: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) return } err = dev.SetStateLabel(pkt) if err != nil { common.Log.Debugf("Failed setting StatePower on device: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) return } case device.State: dev, err := p.getDevice(pkt.GetTarget()) if err != nil { common.Log.Debugf("Skipping State packet for unknown device: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) return } light, ok := dev.(*device.Light) if !ok { common.Log.Debugf("Skipping State packet for non-light device: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) return } err = light.SetState(pkt) if err != nil { common.Log.Debugf("Error setting State on device: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) return } default: common.Log.Debugf("Skipping packet with non-local source: source %v, type %v, sequence %v, target %v, tagged %v, resRequired %v, ackRequired %v: %+v\n", pkt.GetSource(), pkt.GetType(), pkt.GetSequence(), pkt.GetTarget(), pkt.GetTagged(), pkt.GetResRequired(), pkt.GetAckRequired(), *pkt) } return } // Packets processed at the protocol level regardless of target switch pkt.GetType() { case device.StateLocation: p.addLocation(pkt) case device.StateGroup: p.addGroup(pkt) } // Packets processed at the protocol level or returned to target switch pkt.GetType() { case device.StateService: dev, err := p.getDevice(pkt.Target) if err != nil { dev, err := device.New(addr, p.socket, p.timeout, p.retryInterval, p.Reliable, pkt) if err != nil { common.Log.Errorf("Failed creating device: %v\n", err) return } p.addDevice(dev) return } // Perform state discovery on lights if l, ok := dev.(*device.Light); ok { if err := l.Get(); err != nil { common.Log.Debugf("Failed getting light state: %v\n", err) } } default: if pkt.GetTarget() == 0 { common.Log.Debugf("Skipping packet without target: %+v\n", *pkt) return } dev, err := p.getDevice(pkt.GetTarget()) if err != nil { common.Log.Errorf("No known device with ID %v\n", pkt.GetTarget()) return } common.Log.Debugf("Returning packet to device %v: %+v\n", dev.ID(), *pkt) dev.Handle(pkt) } }