Exemplo n.º 1
0
    def checkLimits(self, user_obj):
        result = CanStayOnlineResult()

        if CHARGE_DEBUG:
            toLog("checkLimits called for %s" % user_obj.getUserID(),
                  LOG_DEBUG)

        credit = user_obj.calcCurrentCredit()
        if credit <= 0:  #now set reasons for all instances to credit finished
            result.setKillForAllInstances(
                errorText("USER_LOGIN", "CREDIT_FINISHED", False),
                user_obj.instances)
            return result

        credit_usage_per_second = 0
        earliest_rule_end = defs.MAXLONG
        next_more_applicable = defs.MAXLONG
        seconds_from_morning = secondsFromMorning()

        for _index in range(user_obj.instances):
            if not user_obj.charge_info.accounting_started[_index]:
                continue

            cur_rule = user_obj.charge_info.effective_rules[_index]

            # find new rule
            try:
                effective_rule = self.getEffectiveRule(user_obj, _index + 1)
            except LoginException, e:
                result.addInstanceToKill(_index + 1, e.getErrorText())
                continue

            if cur_rule != effective_rule:

                cur_rule.end(user_obj, _index + 1)
                effective_rule.start(user_obj, _index + 1)

                #change current effective rule
                user_obj.charge_info.setEffectiveRule(_index + 1,
                                                      effective_rule)

            # if effective_rule ras or port are wildcards
            if effective_rule.priority < 3:
                #check if a more applicable rule (ras or ports are specified)
                #can be used before this rule ends
                next_more_applicable_rule = self.getNextMoreApplicableRule(
                    user_obj, _index + 1)
                if next_more_applicable_rule != None:
                    next_more_applicable = min(
                        next_more_applicable_rule.interval.getStartSeconds() -
                        seconds_from_morning, next_more_applicable)

            earliest_rule_end = min(
                earliest_rule_end,
                effective_rule.interval.getEndSeconds() -
                seconds_from_morning +
                1)  #+1 to ensure we don't run at 23:59:59 or such times

            credit_usage_per_second += effective_rule.cpm / 60.0 + \
                                        effective_rule.cpk * effective_rule.assumed_kps
Exemplo n.º 2
0
    def checkLimits(self,user_obj,before_start_accounting=False):
        """
            Check Limits and return a CanStayOnlineResult
            The remaining time returned is the time until one of instances should be killed
            This works for no-multilogin and multilogin rases
            
            before_start_accounting(boolean): for no-multilogin session, we want to know how much user can talk
                                              before the start accounting. So we should set this to True 
        """
        result=CanStayOnlineResult()

        credit=user_obj.calcCurrentCredit()
        if credit<=0: #now set reasons for all instances to credit finished
            result.setKillForAllInstances(errorText("USER_LOGIN","CREDIT_FINISHED",False),user_obj.instances)
            return result

        start=time.time()

        playing={}
        for instance in range(1,user_obj.instances+1):
            if before_start_accounting or user_obj.charge_info.accounting_started[instance-1]:
                playing[instance]={"call_start_time":user_obj.getTypeObj().getCallStartTime(instance)}
                playing[instance]["call_start_rule"]=self._getEffectiveRuleForTime(user_obj,instance,playing[instance]["call_start_time"])
                playing[instance]["call_start_prefix"]=playing[instance]["call_start_rule"].getPrefixObj(user_obj,instance,not before_start_accounting)

        if CHARGE_DEBUG:
            toLog("Playing Dic: %s"%playing, LOG_DEBUG)
        #playing instances, those who have accounting started
        
        remaining_time = 0
        first_iter = True #is this the first iteration? first iteration is important because it examines current state of user
        break_loop = False
        while not break_loop: #continue until one of instances should be killed
                              #this works well on single login sessions, that we want to know when user should
                              #be killed at start of session
                              #for multi login users, we do the loop just once
            credit_usage_per_second=0
            credit_finish_time=defs.MAXLONG
            earliest_rule_end=defs.MAXLONG
            next_more_applicable=defs.MAXLONG
            free_seconds_end=defs.MAXLONG #if user has free seconds remaining from first rule

            seconds_from_morning=secondsFromMorning(start)

            no_effective_rule=0 #number of instances without effective rule for this iteration

            if CHARGE_DEBUG:
                toLog("Loop Start: %s first_iter: %s remaining_time: %s before_start_accounting=%s"%(start,first_iter,remaining_time, before_start_accounting),LOG_DEBUG)


            for instance in playing.keys():


                try:
                    effective_rule = self._getEffectiveRuleForTime(user_obj,instance,start)
                except LoginException,e:
                    no_effective_rule += 1
                    
                    if first_iter:
                        result.addInstanceToKill(instance,str(e))
                        del(playing[instance])
                    else:
                        break_loop=True
                    continue
        
                if first_iter and not before_start_accounting:
                    #change effective rule
                    cur_rule=user_obj.charge_info.effective_rules[instance-1]
                    if  cur_rule!= effective_rule:

                        cur_rule.end(user_obj, instance)
                        effective_rule.start(user_obj,instance)

                        user_obj.charge_info.setEffectiveRule(instance, effective_rule)

                        
                    
                # if effective_rule ras or port are wildcards
                if effective_rule.priority < 3: 
                    #check if a more applicable rule (ras or ports are specified) 
                    #can be used before this rule ends
                    next_more_applicable_rule=self._getNextMoreApplicableRuleForTime(user_obj, instance, effective_rule, start) 
                    if next_more_applicable_rule!=None:
                        next_more_applicable=min(next_more_applicable_rule.interval.getStartSeconds()-seconds_from_morning,next_more_applicable)
                        
                earliest_rule_end=min(earliest_rule_end,effective_rule.interval.getEndSeconds()-seconds_from_morning+1)
    
                #check free seconds
                if start - playing[instance]["call_start_time"] < playing[instance]["call_start_prefix"].getFreeSeconds():
                    free_seconds_end=min(free_seconds_end,playing[instance]["call_start_prefix"].getFreeSeconds() - (start - playing[instance]["call_start_time"]) )
                else:
                    credit_usage_per_second += effective_rule.getPrefixObj(user_obj,instance,False).getCPM() / 60.0
            #end for

            #if all instances knocked out because of no effective rule
            if not len(playing) or no_effective_rule==len(playing): 
                break

            if credit_usage_per_second:
                credit_finish_time = credit / credit_usage_per_second
                
            next_event = min(earliest_rule_end,next_more_applicable,credit_finish_time,free_seconds_end)

            # we should have at least one increment
            if next_event < 1:
                next_event = 1

                toLog("VoIPCharge:Next Event is zero credit: %s credit_usage_per: %s remaining_time: %s next_event: %s credit_finish_time: %s free_seconds_end: %s earliest_rule_end: %s next_more_applicable: %s seconds_from_morning: %s"% \
                (credit,credit_usage_per_second,remaining_time,next_event,credit_finish_time,free_seconds_end,earliest_rule_end,next_more_applicable,seconds_from_morning) \
                ,LOG_ERROR)
        
            #reduce the temp credit
            if credit_usage_per_second:
                credit -= next_event * credit_usage_per_second
                if credit <= 0:
                    break_loop=True
        
            remaining_time += next_event
            # don't go for more than 1 week, who can talk for one week? ;)
            # this may happen if cpm is 0
            if remaining_time > 7 * 24 * 3600 : 
                break_loop = True

            first_iter = False

            start += next_event

            if CHARGE_DEBUG:
                toLog("Loop End: credit: %s credit_usage_per: %s remaining_time: %s next_event: %s credit_finish_time: %s free_seconds_end: %s earliest_rule_end: %s next_more_applicable: %s seconds_from_morning: %s"% \
                (credit,credit_usage_per_second,remaining_time,next_event,credit_finish_time,free_seconds_end,earliest_rule_end,next_more_applicable,seconds_from_morning) \
                ,LOG_DEBUG)
        
            if not before_start_accounting:
                break_loop=True