Example #1
0
    def _set_balance(self, cur, imsi, pncounter):
        """
        Sets a subscriber balance to the given PN counter. Subscriber must
        exist in the database.

        Important: This doesn't do anything about transactions, you need to
        make sure the caller appropriately implements that logic.

        Arguments:
            imsi: Subscriber IMSI
            cursor: DB cursor
            pncounter: A PNCounter representing the subscriber's balance

        Returns: None

        Raises:
            ValueError: Invalid PNCounter
            SubscriberNotFound: No subscriber exists in the DB
        """
        bal = pncounter.serialize()

        # validate state; raises ValueError if there's a problem
        crdt.PNCounter.from_state(pncounter.state)

        try:
            self._update(cur, imsi, bal)
        except KeyError:
            # No subscriber affected
            raise SubscriberNotFound(imsi)
Example #2
0
    def _set_credit(self, imsi, new_balance):
        """
        Set a subscriber's balance.

        Note: behavior of this is somewhat counter-intuitive. Internally, we'll
        either increment or decrement the counter such that

            balance.value() + X = new_balance.

        This kinda breaks the underlying model of the PNCounter representation,
        which only supports increment() and decrement() operations. So, if you
        run set_credit(imsi, 5) in two places such that those two set_credit's
        don't have a causal dependency, the subscriber balance will converge to
        a value that is something other than 5 probably, depending on what
        operations were necessary to get that value on each device.

        Raises:
            SubscriberNotFound if the subscriber doesn't exist
        """
        try:
            self[imsi] = new_balance
        except TypeError:
            raise IOError('corrupt billing table: multiple records for %s' %
                          (imsi, ))
        except IndexError:
            raise SubscriberNotFound(imsi)
Example #3
0
    def _get_balance(self, cur, imsi):
        """
        Get a PN counter representing the subscribers' balance.

        Important: This doesn't do anything about transactions, you need to
        make sure the caller appropriately implements that logic.

        Arguments:
            imsi: Subscriber IMSI
            cursor: DB cursor

        Returns: PNCounter representing subscriber's balance.

        Raises:
            IOError: Invalid DB state (more than one record for an IMSI)
            SubscriberNotFound: No subscriber exists in the DB
        """
        try:
            res = self._get_option(cur, imsi)
        except TypeError:
            raise IOError()
        else:
            if res is None:
                raise SubscriberNotFound(imsi)
            return crdt.PNCounter.from_json(res)
Example #4
0
    def get_account_balance(self, imsi):
        """
        Gets a subscriber's balance as an integer.

        Raises:
            SubscriberNotFound if the subscriber doesn't exist
        """
        try:
            return int(crdt.PNCounter.from_json(self[imsi]).value())
        except KeyError:
            raise SubscriberNotFound(imsi)