Changeset - 3db40ecf9e61
[Not reviewed]
default
0 1 0
drewp@bigasterisk.com - 20 months ago 2023-05-22 08:04:46
drewp@bigasterisk.com
refactor setAttrs
1 file changed with 47 insertions and 47 deletions:
0 comments (0 inline, 0 general)
light9/collector/collector.py
Show inline comments
 
@@ -105,6 +105,48 @@ class Collector:
 
            end = typedValue(float, self.graph, remap, L9['end'])
 
            self.remapOut[(dev, attr)] = OutputRange((start, end))
 

	
 
    def setAttrs(self, client: ClientType, clientSession: ClientSessionType, settings: DeviceSettings, sendTime: UnixTime):
 
        """
 
        Given DeviceSettings, we resolve conflicting values,
 
        process them into output attrs, and call Output.update
 
        to send the new outputs.
 

	
 
        client is a string naming the type of client.
 
        (client, clientSession) is a unique client instance.
 
        clientSession is deprecated.
 

	
 
        Each client session's last settings will be forgotten
 
        after clientTimeoutSec.
 
        """
 
        # todo: cleanup session code if we really don't want to be able to run multiple sessions of one client
 
        clientSession = ClientSessionType("no_longer_used")
 

	
 
        now = UnixTime(time.time())
 
        self._warnOnLateRequests(client, now, sendTime)
 

	
 
        self._forgetStaleClients(now)
 

	
 
        self.lastRequest[(client, clientSession)] = (now, self._resolvedSettingsDict(settings))
 

	
 
        deviceAttrs = self._merge(iter(self.lastRequest.values()))
 

	
 
        outputAttrsByDevice = self._convertToOutputAttrsPerDevice(deviceAttrs)
 
        pendingOut = self._flattenDmxOutput(outputAttrsByDevice)
 

	
 
        dt1 = time.time() - now
 

	
 
        self._updateOutputs(pendingOut)
 

	
 
        dt2 = time.time() - dt1
 
        if dt1 > .030 or dt2 > .030:
 
            log.warning("slow setAttrs: prepare %.1fms -> updateOutputs %.1fms" % (dt1 * 1000, dt2 * 1000))
 

	
 
    def _warnOnLateRequests(self, client, now, sendTime):
 
        requestLag = now - sendTime
 
        if requestLag > .1 and now > self._initTime + 10 and getattr(self, '_lastWarnTime', 0) < now - 3:
 
            self._lastWarnTime = now
 
            log.warning('collector.setAttrs from %s is running %.1fms after the request was made', client, requestLag * 1000)
 

	
 
    def _forgetStaleClients(self, now):
 
        staleClientSessions = []
 
        for clientSession, (reqTime, _) in self.lastRequest.items():
 
@@ -125,12 +167,6 @@ class Collector:
 
                out[(devUri, devAttr)] = val
 
        return out
 

	
 
    def _warnOnLateRequests(self, client, now, sendTime):
 
        requestLag = now - sendTime
 
        if requestLag > .1 and now > self._initTime + 10 and getattr(self, '_lastWarnTime', 0) < now - 3:
 
            self._lastWarnTime = now
 
            log.warn('collector.setAttrs from %s is running %.1fms after the request was made', client, requestLag * 1000)
 

	
 
    def _merge(self, lastRequests):
 
        deviceAttrs: Dict[DeviceUri, Dict[DeviceAttr, VTUnion]] = {}  # device: {deviceAttr: value}
 
        for _, lastSettings in lastRequests:
 
@@ -157,51 +193,15 @@ class Collector:
 

	
 
        return deviceAttrs
 

	
 
    def setAttrs(self, client: ClientType, clientSession: ClientSessionType, settings: DeviceSettings, sendTime: UnixTime):
 
        """
 
        settings is a list of (device, attr, value). These attrs are
 
        device attrs. We resolve conflicting values, process them into
 
        output attrs, and call Output.update to send the new outputs.
 

	
 
        client is a string naming the type of client. (client,
 
        clientSession) is a unique client instance.
 

	
 
        Each client session's last settings will be forgotten after
 
        clientTimeoutSec.
 
        """
 
        # todo: cleanup session code if we really don't want to be able to run multiple sessions of one client
 
        clientSession = ClientSessionType("no_longer_used")
 

	
 
        now = UnixTime(time.time())
 
        self._warnOnLateRequests(client, now, sendTime)
 

	
 
        self._forgetStaleClients(now)
 

	
 
        self._acceptNewClientSessionSettings(client, clientSession, settings, now)
 

	
 
        deviceAttrs = self._merge(iter(self.lastRequest.values()))
 

	
 
        outputAttrs = cast(Dict[DeviceUri, Dict[OutputAttr, OutputValue]], {})
 
    def _convertToOutputAttrsPerDevice(self, deviceAttrs):
 
        ret: Dict[DeviceUri, Dict[OutputAttr, OutputValue]] = {}
 
        for d, devType in self._deviceType.items():
 
            try:
 
                outputAttrs[d] = toOutputAttrs(devType, deviceAttrs.get(d, {}))
 
                self.listeners.outputAttrsSet(d, outputAttrs[d], self._outputMap)
 
                ret[d] = toOutputAttrs(devType, deviceAttrs.get(d, {}))
 
                self.listeners.outputAttrsSet(d, ret[d], self._outputMap)
 
            except Exception as e:
 
                log.error('failing toOutputAttrs on %s: %r', d, e)
 

	
 
        pendingOut = self._flattenDmxOutput(outputAttrs)
 

	
 
        dt1 = 1000 * (time.time() - now)
 

	
 
        self._updateOutputs(pendingOut)
 

	
 
        dt2 = 1000 * (time.time() - now) - dt1
 
        if dt1 > 30 or dt2 > 30:
 
            log.warn("slow setAttrs: prepare %.1fms -> updateOutputs %.1fms" % (dt1, dt2 - dt1))
 

	
 
    def _acceptNewClientSessionSettings(self, client, clientSession, settings, now):
 
        uniqueSettings = self.resolvedSettingsDict(settings)
 
        self.lastRequest[(client, clientSession)] = (now, uniqueSettings)
 
        return ret
 

	
 
    def _flattenDmxOutput(self, outputAttrs: Dict[DeviceUri, Dict[OutputAttr, OutputValue]]) -> Dict[OutputUri, bytearray]:
 
        pendingOut = cast(Dict[OutputUri, bytearray], {})
0 comments (0 inline, 0 general)