NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

recommendationSvc.py (12177B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\recommendation\recommendationSvc.py
      2 import collections
      3 import logging
      4 import uuid
      5 from featuremanagement.client.flag import flag_bool
      6 import uthread2
      7 from carbon.common.script.sys.service import Service
      8 from eve.client.script.ui.shared.recommendation.const import CURRENT_ACTIVE, COMPLETED, NUM_SLOTS, MAX_QUEUE_LENGTH
      9 from eve.client.script.ui.shared.recommendation.message_bus.recommendationMessenger import RecommendationMessenger
     10 from eve.client.script.ui.shared.recommendation.recommendationController import RecommendationController, LastActiveOperationInfo
     11 from eve.client.script.ui.shared.recommendation.uiConst import HAS_ACCEPTED, HAS_INTERACTED_WITH
     12 from launchdarkly.client.const import OPPORTUNITIES_UI
     13 from operations.client.operationscontroller import GetOperationsController
     14 from operations.common.const import OPERATION_CATEGORY_RECOMMENDATIONS
     15 logger = logging.getLogger(__name__)
     16 FEATURE_FLAG_FALLBACK = False
     17 
     18 class RecommendationService(Service):
     19     __guid__ = 'svc.recommendationSvc'
     20     __displayname__ = 'Recommendation Service'
     21     __startupdependencies__ = ['publicGatewaySvc']
     22     __notifyevents__ = ['OnOperationCompleted', 'OnOperationMadeActive', 'OnSessionReset']
     23 
     24     def __init__(self):
     25         super(RecommendationService, self).__init__()
     26         self.ResetVariables()
     27         self._enabled = FEATURE_FLAG_FALLBACK
     28         flag_bool(key=OPPORTUNITIES_UI, default_value=FEATURE_FLAG_FALLBACK, callback=self._refresh_feature_flag)
     29 
     30     def _refresh_feature_flag(self, evaluate_flag):
     31         self._enabled = evaluate_flag()
     32 
     33     def ResetVariables(self):
     34         self.availableRecommendationQueue = collections.deque(maxlen=MAX_QUEUE_LENGTH)
     35         self.recommendationControllerBySlotID = {}
     36         self.activeRecommendation = None
     37         self.characterHasReceivedRecommendations = False
     38 
     39     def OnSessionReset(self):
     40         self.ResetVariables()
     41 
     42     def HasRecommendations(self):
     43         return any([ controller.operationID for controller in self.recommendationControllerBySlotID.values() ])
     44 
     45     def AddToQueue(self, operation_recommendations):
     46         if not operation_recommendations:
     47             return
     48         for recommendation in operation_recommendations:
     49             operationID, journeyID = self.UnpackOperationRecommendation(recommendation)
     50             if not operationID or not journeyID:
     51                 logger.error('recommendation is missing a required component, operationID or journeyID is None')
     52                 continue
     53             self.availableRecommendationQueue.append((operationID, journeyID))
     54 
     55         self.TryPopulateAllSlotControllers()
     56         sm.GetService('infoPanel').UpdateOperationsPanel(OPERATION_CATEGORY_RECOMMENDATIONS)
     57 
     58     def TryPopulateAllSlotControllers(self):
     59         for slotIdx in range(NUM_SLOTS):
     60             self.TryPopulateSlotController(slotIdx)
     61 
     62     def TryPopulateSlotController(self, slotIdx):
     63         controller = self.GetRecommendationControllerForSlot(slotIdx)
     64         if not controller:
     65             logger.warn('TryPopulateSlotController: could not get recommendation controller for this slot: %d' % slotIdx)
     66             return
     67         controller.TryPopulateController()
     68 
     69     def GetRecommendationControllerForSlot(self, slotIdx):
     70         if slotIdx in self.recommendationControllerBySlotID:
     71             return self.recommendationControllerBySlotID[slotIdx]
     72         return self._CreateRecommendationControllerForSlot(slotIdx)
     73 
     74     def GetRecommendationFromQueue(self):
     75         try:
     76             operationRecommendation = self.availableRecommendationQueue.popleft()
     77         except IndexError:
     78             return (None, None)
     79 
     80         return operationRecommendation
     81 
     82     @staticmethod
     83     def UnpackOperationRecommendation(operationRecommendation):
     84         try:
     85             operationID = operationRecommendation.operation.sequential
     86             recommendationJourneyID = uuid.UUID(bytes=operationRecommendation.journey)
     87         except AttributeError:
     88             logger.exception('failed to unpack operation recommendation')
     89             return (None, None)
     90 
     91         return (operationID, recommendationJourneyID)
     92 
     93     def _CreateRecommendationControllerForSlot(self, slotIdx):
     94         if self.activeRecommendation and not self.IsActiveRecommendationInASlot():
     95             operationID = self.activeRecommendation.operationID
     96             journeyID = None
     97         else:
     98             operationID, journeyID = self.GetRecommendationFromQueue()
     99         recommendationController = RecommendationController(operationID=operationID, slotIdx=slotIdx, journeyID=journeyID)
    100         self.recommendationControllerBySlotID[slotIdx] = recommendationController
    101         return recommendationController
    102 
    103     def IsActiveRecommendationInASlot(self):
    104         if not self.activeRecommendation:
    105             return False
    106         return any((controller.operationID == self.activeRecommendation.operationID for controller in self.recommendationControllerBySlotID.values()))
    107 
    108     def AcceptRecommendation(self, operationID, journeyID):
    109         settings.char.ui.Set(HAS_ACCEPTED, True)
    110         uthread2.StartTasklet(self._SendRecommendationAcceptedEvent, operationID, journeyID)
    111         sm.ScatterEvent('OnRecommendationAccepted')
    112 
    113     def _SendRecommendationAcceptedEvent(self, operationID, journeyID):
    114         message_bus = RecommendationMessenger(self.publicGatewaySvc)
    115         message_bus.accepted(operationID, journeyID)
    116 
    117     def QuitRecommendation(self, operationID, slotIdx):
    118         if operationID != GetOperationsController().get_active_operation_id():
    119             logger.error("Can't quit an inactive operation")
    120             return
    121         GetOperationsController().manager.cancel_current_treatment_operation()
    122         self.activeRecommendation = None
    123         self.ClearSlot(slotIdx)
    124         self.RequestRecommendations(1, allowOld=False)
    125 
    126     def DismissRecommendation(self, operationID, journeyID, slotIdx):
    127         if operationID == GetOperationsController().get_active_operation_id():
    128             self.QuitRecommendation(operationID, slotIdx)
    129         self.ClearSlot(slotIdx)
    130         uthread2.StartTasklet(self._SendRecommendationDismissedEvent, operationID, journeyID)
    131         if len(self.availableRecommendationQueue):
    132             self.TryPopulateSlotController(slotIdx)
    133         else:
    134             uthread2.StartTasklet(self.RequestRecommendations, 1, False)
    135 
    136     def _SendRecommendationDismissedEvent(self, operationID, journeyID):
    137         if not operationID:
    138             logger.error('can not dismiss this operation recommendation, operationID is None')
    139             return
    140         message_bus = RecommendationMessenger(self.publicGatewaySvc)
    141         message_bus.dismissed(operationID, journeyID)
    142 
    143     def ClearSlot(self, slotIdx):
    144         controller = self.GetRecommendationControllerForSlot(slotIdx)
    145         if not controller:
    146             return
    147         controller.ResetController()
    148 
    149     def OnOperationMadeActive(self, categoryID, operationID, *args, **kwargs):
    150         if categoryID != OPERATION_CATEGORY_RECOMMENDATIONS:
    151             self.activeRecommendation = None
    152             return
    153         self.SetActiveRecommendation()
    154         if self.activeRecommendation and self.IsActiveRecommendationInASlot():
    155             slotIdx = self.GetSlotIDForOperation(operationID)
    156             self.SetStatusForRecommendation(slotIdx, CURRENT_ACTIVE)
    157         else:
    158             self.GetSlotForActiveRecommendation()
    159 
    160     def GetSlotForActiveRecommendation(self):
    161         for controller in self.recommendationControllerBySlotID.values():
    162             existingRecommendationID = controller.operationID
    163             existingRecommendationJourneyID = controller.journeyID
    164             self.availableRecommendationQueue.appendleft((existingRecommendationID, existingRecommendationJourneyID))
    165             controller.ResetController()
    166             controller.operationID = self.activeRecommendation.operationID
    167             break
    168         else:
    169             self.GetRecommendationControllerForSlot(0)
    170 
    171     def SetActiveRecommendation(self):
    172         activeOperation = GetOperationsController().get_active_operation()
    173         if not activeOperation:
    174             self.activeRecommendation = None
    175             return
    176         taskTuples = GetOperationsController().get_active_task_tuples()
    177         self.activeRecommendation = LastActiveOperationInfo(OPERATION_CATEGORY_RECOMMENDATIONS, activeOperation, taskTuples)
    178 
    179     def SendRecommendationDisplayedEvent(self, operationID, journeyID):
    180         message_bus = RecommendationMessenger(self.publicGatewaySvc)
    181         message_bus.displayed(operationID, journeyID)
    182 
    183     def OnOperationCompleted(self, categoryID, operationID):
    184         if categoryID != OPERATION_CATEGORY_RECOMMENDATIONS:
    185             return
    186         if not self.activeRecommendation:
    187             return
    188         hasCompletedActiveRecommendation = operationID == self.activeRecommendation.operationID
    189         if not hasCompletedActiveRecommendation:
    190             return
    191         slotIDx = self.GetSlotIDForOperation(operationID)
    192         self.SetStatusForRecommendation(slotIDx, COMPLETED)
    193         controller = self.recommendationControllerBySlotID.get(slotIDx, None)
    194         if not controller:
    195             logger.warn('could not get recommendation controller for this operationID: %d, slot: %d' % (operationID, slotIDx))
    196             return
    197         sm.ScatterEvent('OnOperationRecommendationCompleted', operationID)
    198 
    199     def GetSlotIDForOperation(self, operationID):
    200         slotIDx = None
    201         for slotID, controller in self.recommendationControllerBySlotID.iteritems():
    202             if operationID == controller.operationID:
    203                 slotIDx = slotID
    204 
    205         return slotIDx
    206 
    207     def SetStatusForRecommendation(self, slotID, newStatus):
    208         controller = self.recommendationControllerBySlotID.get(slotID, None)
    209         if not controller:
    210             logger.warn('could not get recommendation controller for this slotID: %d' % slotID)
    211             return
    212         controller.SetStatus(newStatus)
    213 
    214     def IsActiveRecommendationComplete(self):
    215         if not self.activeRecommendation:
    216             return False
    217         operationID = self.activeRecommendation.operationID
    218         if not operationID:
    219             return False
    220         slotIDx = self.GetSlotIDForOperation(operationID)
    221         if not slotIDx:
    222             return False
    223         controller = self.GetRecommendationControllerForSlot(slotIDx)
    224         return controller.IsCompleted()
    225 
    226     def ShowLastCompleted(self):
    227         return self.IsActiveRecommendationComplete() and self.IsThereUnseenAndCompletedRecommendation()
    228 
    229     def IsThereUnseenAndCompletedRecommendation(self):
    230         for slotIdx in range(NUM_SLOTS):
    231             controller = self.GetRecommendationControllerForSlot(slotIdx)
    232             if not controller:
    233                 logger.warn('could not get recommendation controller for this slot: %d' % slotIdx)
    234                 continue
    235             if controller.IsCompletedAndUnseen():
    236                 return True
    237 
    238         return False
    239 
    240     def RequestRecommendations(self, amount, allowOld = False):
    241         if not self.IsFeatureEnabled() or not self.publicGatewaySvc.is_available():
    242             return
    243         message_bus = RecommendationMessenger(self.publicGatewaySvc)
    244         message_bus.request_recommendations(amount, allowOld, response_function=self.AddToQueue, timeout_function=self.RequestTimeoutHandler)
    245 
    246     def RequestTimeoutHandler(self):
    247         for controller in self.recommendationControllerBySlotID.values():
    248             controller.onRequestTimeout()
    249 
    250     def ShouldInfoPanelBlink(self):
    251         if not settings.char.ui.Get(HAS_INTERACTED_WITH, False):
    252             return True
    253         return self.IsThereUnseenAndCompletedRecommendation()
    254 
    255     def IsFeatureEnabled(self):
    256         if not sm.GetService('publicGatewaySvc').is_available():
    257             return False
    258         return self._enabled
    259 
    260     @staticmethod
    261     def ShouldBtnsBlink():
    262         return not settings.char.ui.Get(HAS_INTERACTED_WITH, False)
    263 
    264     @staticmethod
    265     def HasEverAcceptedARecommendation():
    266         return settings.char.ui.Get(HAS_ACCEPTED, False)