diff --git a/client/core/checkin.py b/client/core/checkin.py index dddfedf0..9db37429 100644 --- a/client/core/checkin.py +++ b/client/core/checkin.py @@ -21,6 +21,7 @@ from core.bts import bts from core.config_database import ConfigDB from core.event_store import EventStore +from core.denomination_store import DenominationStore from core.registration import reset_registration from core.subscriber import subscriber @@ -30,6 +31,7 @@ class CheckinHandler(object): CONFIG_SECTION = "config" EVENTS_SECTION = "events" SUBSCRIBERS_SECTION = "subscribers" + NETWORK_DENOMINATION = "network_denomination" # NOTE: Keys in section_ctx dictionary below must match the keys of # optimized checkin sections: "config", "events", "subscribers", etc. @@ -42,6 +44,7 @@ class CheckinHandler(object): def __init__(self, response): self.conf = ConfigDB() self.eventstore = EventStore() + self.denominationstore = DenominationStore() r = self.validate(response) self.process(r) @@ -59,6 +62,8 @@ def process(self, resp_dict): self.process_events(resp_dict[section]) elif section == CheckinHandler.SUBSCRIBERS_SECTION: self.process_subscribers(resp_dict[section]) + elif section == CheckinHandler.NETWORK_DENOMINATION: + self.process_denomination(resp_dict[section]) elif section != 'status': logger.error("Unexpected checkin section: %s" % section) @@ -93,6 +98,18 @@ def process_config(self, config_dict): def process_subscribers(self, data_dict): subscriber.process_update(data_dict) + # process denomination table if denomination bracket is not then it add, + # if it's deleted then it delete , if it's updated then update + def process_denomination(self, data_dict): + for data in data_dict: + if self.denominationstore.get_record(data['id']) == None: + self.denominationstore.add_record(data['id'],data['start_amount'], + data['end_amount'],data['validity']) + id_list = self.denominationstore.get_all_id() + for id in id_list: + if id not in [d['id'] for d in data_dict]: + self.denominationstore.delete_record(id) + def process_events(self, data_dict): """Process information about events. diff --git a/client/core/config_database.py b/client/core/config_database.py index ae82dbe6..a8a7b432 100644 --- a/client/core/config_database.py +++ b/client/core/config_database.py @@ -154,8 +154,9 @@ def set_defaults(force_replace=False): 'external_interface': 'tun0', # The internal interface is the NIC used by the BSC/BTS to address this # system - 'internal_interface': 'lo' - + 'internal_interface': 'lo', + # default network balance limit + 'network_max_balance': 100000 } config = ConfigDB() diff --git a/client/core/denomination_store.py b/client/core/denomination_store.py new file mode 100644 index 00000000..c5637c10 --- /dev/null +++ b/client/core/denomination_store.py @@ -0,0 +1,124 @@ +""" +store denomination bracket in the backend database. + +Copyright (c) 2017-present, Facebook, Inc. +All rights reserved. + +This source code is licensed under the BSD-style license found in the +LICENSE file in the root directory of this source tree. An additional grant +of patent rights can be found in the PATENTS file in the same directory. +""" + + + + + + +import os + +import psycopg2 + + +# In our CI system, Postgres credentials are stored in env vars. +PG_USER = os.environ.get('PG_USER', 'endaga') +PG_PASSWORD = os.environ.get('PG_PASSWORD', 'endaga') + + +class DenominationStore(object): + """Update denomination bracket from cloud to get validity days.""" + + def __init__(self): + self.connection = psycopg2.connect(host='localhost', database='endaga', + user=PG_USER, password=PG_PASSWORD) + self.table_name = 'denomination_store' + # Create the table if it doesn't yet exist. + with self.connection.cursor() as cursor: + command = ("CREATE TABLE IF NOT EXISTS %s(" + " id integer NOT NULL," + " start_amount bigint NOT NULL," + " end_amount bigint NOT NULL," + " validity_days integer NOT NULL" + ");") + cursor.execute(command % self.table_name) + self.connection.commit() + + def empty(self): + """Drops all records from the table.""" + with self.connection.cursor() as cursor: + command = 'truncate %s' % self.table_name + cursor.execute(command) + self.connection.commit() + + def get_records(self): + res = [] + template = ('select * from %s ') + command = template % (self.table_name) + with self.connection.cursor() as cursor: + + cursor.execute(command) + self.connection.commit() + r = cursor.fetchall() + for item in r: + data = {'start_amount': item[1], + 'end_amount': item[2], 'validity': item[3]} + + return res + + def get_all_id(self): + res =[] + + template = 'select * from %s ' + command = template % (self.table_name) + with self.connection.cursor() as cursor: + cursor.execute(command) + self.connection.commit() + r = cursor.fetchall() + for item in r: + res.append(item[0]) + return res + + def get_record(self, id): + """Gets the most recent record for an Id. + + Returns None if no record was found. + """ + command = "select * from %s where id='%s'" + with self.connection.cursor() as cursor: + cursor.execute(command % (self.table_name, id)) + self.connection.commit() + if not cursor.rowcount: + return None + else: + return cursor.fetchall()[0] + + def delete_record(self, id): + template = 'delete from %s where id = %s' + command = template % (self.table_name, id) + with self.connection.cursor() as cursor: + cursor.execute(command) + self.connection.commit() + + def get_validity_days(self,top_up): + + template = "select validity_days from %s where start_amount <=%s " \ + "and end_amount >=%s order by -end_amount" + command = template %(self.table_name, top_up, top_up) + with self.connection.cursor() as cursor: + cursor.execute(command) + self.connection.commit() + r = cursor.fetchall() + if len(r): + return r[0] + else: + return None + + def add_record(self,id, start_amount, end_amount, validity): + schema = ('id, start_amount, end_amount, validity_days') + values = "'%s','%s', '%s', %s" % ( + id, start_amount, end_amount, validity) + command = 'insert into %s (%s) values(%s)' % ( + self.table_name, schema, values) + with self.connection.cursor() as cursor: + cursor.execute(command) + self.connection.commit() + diff --git a/cloud/endagaweb/checkin.py b/cloud/endagaweb/checkin.py index efa19311..b298486f 100644 --- a/cloud/endagaweb/checkin.py +++ b/cloud/endagaweb/checkin.py @@ -26,7 +26,7 @@ from endagaweb.models import TimeseriesStat from endagaweb.models import UsageEvent from endagaweb.util.parse_destination import parse_destination - +from endagaweb.models import NetworkDenomination class CheckinResponder(object): @@ -163,6 +163,8 @@ def process(self, status): self.gen_subscribers()) resp['events'] = self.gen_events() resp['sas'] = self.gen_spectrum() + # send network denomination bracket data with response + resp['network_denomination'] = self.get_network_denomination() self.bts.save() return resp @@ -403,6 +405,7 @@ def gen_config(self): 'latest_stable_version': latest_stable_version, 'latest_beta_version': latest_beta_version, } + result['endaga']['network_max_balance'] = self.bts.network.max_balance return result def gen_events(self): @@ -485,6 +488,19 @@ def sas_request(): } return {'ok': False} + def get_network_denomination(self): + """ + Returns a list of denomination bracket for status done + """ + res = [] + for s in NetworkDenomination.objects.filter(network=self.bts.network, + status='done'): + data = {'id': s.id,'start_amount': s.start_amount, + 'end_amount': s.end_amount, 'validity': str(s.validity_days)} + res.append(data) + return res + + def handle_event(bts, event, destinations=None): """Handles a usage event from a BTS.