Skip to content

Commit

Permalink
updated few api methods, working on storage contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
vesellov committed Dec 8, 2023
1 parent 558c574 commit 364bcac
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 62 deletions.
5 changes: 1 addition & 4 deletions bitdust/automats/automat.py
Original file line number Diff line number Diff line change
Expand Up @@ -765,10 +765,7 @@ def addStateChangedCallback(self, cb, oldstate=None, newstate=None, callback_id=
if key not in self._state_callbacks:
self._state_callbacks[key] = []
if cb not in self._state_callbacks[key]:
self._state_callbacks[key].append((
callback_id,
cb,
))
self._state_callbacks[key].append((callback_id, cb))
return True

def removeStateChangedCallback(self, cb=None, callback_id=None):
Expand Down
82 changes: 55 additions & 27 deletions bitdust/customer/fire_hire.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
* :red:`search-failed`
* :red:`supplier-connected`
* :red:`supplier-state-changed`
* :red:`timer-15sec`
* :red:`timer-25sec`
"""

#------------------------------------------------------------------------------
Expand All @@ -103,8 +103,8 @@

#------------------------------------------------------------------------------

_Debug = False
_DebugLevel = 8
_Debug = True
_DebugLevel = 14

#------------------------------------------------------------------------------

Expand All @@ -126,6 +126,7 @@
from bitdust.lib import misc
from bitdust.lib import diskspace
from bitdust.lib import strng
from bitdust.lib import utime

from bitdust.main import config
from bitdust.main import settings
Expand Down Expand Up @@ -230,7 +231,7 @@ class FireHire(automat.Automat):
fast = False

timers = {
'timer-15sec': (25.0, ['FIRE_MANY', 'SUPPLIERS?']),
'timer-25sec': (25.0, ['FIRE_MANY', 'SUPPLIERS?']),
}

def init(self):
Expand Down Expand Up @@ -271,12 +272,12 @@ def A(self, event, *args, **kwargs):
self.NeedRestart = False
#---READY---
elif self.state == 'READY':
if (event == 'restart' or (event == 'instant' and self.NeedRestart)) and self.isConfigChanged(*args, **kwargs) and self.isExistSomeSuppliers(*args, **kwargs):
if (event == 'restart' or (event == 'instant' and self.NeedRestart)) and (self.isConfigChanged(*args, **kwargs) or self.isContractExpiring(*args, **kwargs)) and self.isExistSomeSuppliers(*args, **kwargs):
self.state = 'SUPPLIERS?'
self.NeedRestart = False
self.doSaveConfig(*args, **kwargs)
self.doConnectSuppliers(*args, **kwargs)
elif (event == 'restart' or (event == 'instant' and self.NeedRestart)) and not (self.isConfigChanged(*args, **kwargs) and self.isExistSomeSuppliers(*args, **kwargs)):
elif (event == 'restart' or (event == 'instant' and self.NeedRestart)) and not ((self.isConfigChanged(*args, **kwargs) or self.isContractExpiring(*args, **kwargs)) and self.isExistSomeSuppliers(*args, **kwargs)):
self.state = 'DECISION?'
self.NeedRestart = False
self.doDecideToDismiss(*args, **kwargs)
Expand Down Expand Up @@ -322,12 +323,7 @@ def A(self, event, *args, **kwargs):
self.doScheduleNextRestart(*args, **kwargs)
#---FIRE_MANY---
elif self.state == 'FIRE_MANY':
if event == 'timer-15sec':
self.state = 'READY'
self.doCloseConnectors(*args, **kwargs)
self.doClearDismissList(*args, **kwargs)
self.doNotifySuppliersChanged(*args, **kwargs)
elif event == 'supplier-state-changed' and not self.isAllDismissed(*args, **kwargs):
if event == 'supplier-state-changed' and not self.isAllDismissed(*args, **kwargs):
self.doCloseConnector(*args, **kwargs)
elif event == 'restart':
self.NeedRestart = True
Expand All @@ -336,11 +332,16 @@ def A(self, event, *args, **kwargs):
self.doCloseConnector(*args, **kwargs)
self.doClearDismissList(*args, **kwargs)
self.doNotifySuppliersChanged(*args, **kwargs)
elif event == 'timer-25sec':
self.state = 'READY'
self.doCloseConnectors(*args, **kwargs)
self.doClearDismissList(*args, **kwargs)
self.doNotifySuppliersChanged(*args, **kwargs)
#---SUPPLIERS?---
elif self.state == 'SUPPLIERS?':
if event == 'restart':
self.NeedRestart = True
elif (event == 'supplier-state-changed' and self.isAllReady(*args, **kwargs)) or event == 'timer-15sec':
elif (event == 'supplier-state-changed' and self.isAllReady(*args, **kwargs)) or event == 'timer-25sec':
self.state = 'DECISION?'
self.doDecideToDismiss(*args, **kwargs)
return None
Expand Down Expand Up @@ -421,10 +422,15 @@ def isConfigChanged(self, *args, **kwargs):
"""
Condition method.
"""
if None in self.configs:
return True
curconfigs = (settings.getSuppliersNumberDesired(), diskspace.GetBytesFromString(settings.getNeededString()))
return self.configs[0] != curconfigs[0] or self.configs[1] != curconfigs[1]
return self._is_config_changed()

def isContractExpiring(self, *args, **kwargs):
"""
Condition method.
"""
if not driver.is_on('service_customer_contracts'):
return False
return len(self._get_suppliers_with_expired_contracts()) > 0

def isExistSomeSuppliers(self, *args, **kwargs):
"""
Expand All @@ -450,11 +456,18 @@ def doConnectSuppliers(self, *args, **kwargs):
from bitdust.p2p import online_status
self.connect_list = []
my_current_family = contactsdb.suppliers()
if self._is_config_changed():
target_suppliers = list(my_current_family)
else:
# only select suppliers with expired contracts
target_suppliers = self._get_suppliers_with_expired_contracts()
for pos, supplier_idurl in enumerate(my_current_family):
if not supplier_idurl:
continue
if self.configs[0] and pos >= self.configs[0]:
continue
if not id_url.is_in(supplier_idurl, target_suppliers):
continue
sc = supplier_connector.by_idurl(supplier_idurl)
if sc is None:
sc = supplier_connector.create(
Expand Down Expand Up @@ -550,10 +563,7 @@ def doDecideToDismiss(self, *args, **kwargs):
potentialy_fired.add(supplier_idurl)
elif sc.state == 'CONNECTED':
connected_suppliers.add(supplier_idurl)
elif sc.state in [
'DISCONNECTED',
'REFUSE',
]:
elif sc.state in ['DISCONNECTED', 'REFUSE']:
disconnected_suppliers.add(supplier_idurl)
# elif sc.state in ['QUEUE?', 'REQUEST', ]:
# requested_suppliers.add(supplier_idurl)
Expand Down Expand Up @@ -602,12 +612,9 @@ def doDecideToDismiss(self, *args, **kwargs):
# only replace suppliers one by one at the moment
result = list(potentialy_fired)
lg.info('will replace supplier %s' % result[0])
self.automat(
'made-decision',
[
result[0],
],
)
self.automat('made-decision', [
result[0],
])

def doRememberSuppliers(self, *args, **kwargs):
"""
Expand Down Expand Up @@ -861,6 +868,27 @@ def doNotifyFinished(self, *args, **kwargs):
from bitdust.storage import backup_monitor
backup_monitor.A('fire-hire-finished')

def _is_config_changed(self):
if None in self.configs:
return True
curconfigs = (settings.getSuppliersNumberDesired(), diskspace.GetBytesFromString(settings.getNeededString()))
return self.configs[0] != curconfigs[0] or self.configs[1] != curconfigs[1]

def _get_suppliers_with_expired_contracts(self):
from bitdust.customer import supplier_connector
now = utime.utcnow_to_sec1970()
ret = []
for supplier_idurl in contactsdb.suppliers():
if supplier_idurl:
sc = supplier_connector.by_idurl(supplier_idurl)
if sc:
if sc.state == 'CONNECTED':
if sc.storage_contract:
if now > utime.unpack_time(sc.storage_contract['complete_after']):
lg.warn('storage contract with %s is expired' % supplier_idurl)
ret.append(supplier_idurl)
return ret

def _scheduled_restart(self):
self.restart_task = None
self.automat('restart')
Expand Down
2 changes: 1 addition & 1 deletion bitdust/customer/payment.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,4 @@ def pay_for_storage():
for unpaid_contract in unpaid_contracts:
sum_to_pay += unpaid_contract['value']
if _Debug:
lg.args(_DebugLevel, to_pay=sum_to_pay, pay_before_earliest=utime.pack_time(pay_before_earliest), pay_before_latest=utime.pack_time(pay_before_latest))
lg.args(_DebugLevel, s=supplier_idurl, to_pay=sum_to_pay, pay_before_earliest=utime.pack_time(pay_before_earliest), pay_before_latest=utime.pack_time(pay_before_latest))
11 changes: 7 additions & 4 deletions bitdust/customer/supplier_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@

#------------------------------------------------------------------------------

_Debug = False
_DebugLevel = 16
_Debug = True
_DebugLevel = 14

#------------------------------------------------------------------------------

Expand Down Expand Up @@ -229,6 +229,7 @@ def __init__(self, supplier_idurl, customer_idurl, needed_bytes, key_id=None, qu
self.request_queue_packet_id = None
self.latest_supplier_ack = None
self.callbacks = {}
self.storage_contract = None
try:
st = bpio.ReadTextFile(settings.SupplierServiceFilename(
idurl=self.supplier_idurl,
Expand Down Expand Up @@ -296,7 +297,8 @@ def state_changed(self, oldstate, newstate, event, *args, **kwargs):
def set_callback(self, name, cb):
if name not in self.callbacks:
self.callbacks[name] = []
self.callbacks[name].append(cb)
if cb not in self.callbacks[name]:
self.callbacks[name].append(cb)

def remove_callback(self, name, cb=None):
if name in self.callbacks:
Expand Down Expand Up @@ -657,7 +659,8 @@ def _supplier_service_acked(self, response, info):
except:
lg.exc()
if _Debug:
lg.args(_DebugLevel, response=response, info=info)
lg.args(_DebugLevel, response=response, info=info, contract=the_contract)
self.storage_contract = the_contract
if the_contract:
if not accounting.verify_storage_contract(the_contract):
lg.err('received storage contract from %r is not valid' % self.supplier_idurl)
Expand Down
49 changes: 30 additions & 19 deletions bitdust/interface/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3715,23 +3715,23 @@ def friends_list():
result = []
for idurl, alias in contactsdb.correspondents():
glob_id = global_id.ParseIDURL(idurl)
contact_status = 'offline'
# contact_status = 'offline'
contact_state = 'OFFLINE'
friend = {
'idurl': idurl,
'global_id': glob_id['customer'],
'idhost': glob_id['idhost'],
'username': glob_id['user'],
'alias': alias,
'contact_status': contact_status,
# 'contact_status': contact_status,
'contact_state': contact_state,
}
if driver.is_on('service_identity_propagate'):
from bitdust.p2p import online_status
state_machine_inst = online_status.getInstance(idurl, autocreate=False)
if state_machine_inst:
friend.update(state_machine_inst.to_json())
friend['contact_status'] = online_status.stateToLabel(state_machine_inst.state)
# friend['contact_status'] = online_status.stateToLabel(state_machine_inst.state)
friend['contact_state'] = state_machine_inst.state
result.append(friend)
return RESULT(result)
Expand Down Expand Up @@ -3921,7 +3921,7 @@ def user_status(user_id):
# if not state_machine_inst:
# return ERROR('error fetching user status')
return OK({
'contact_status': online_status.getStatusLabel(idurl),
# 'contact_status': online_status.getStatusLabel(idurl),
'contact_state': online_status.getCurrentState(idurl),
'idurl': idurl,
'global_id': global_id.UrlToGlobalID(idurl),
Expand Down Expand Up @@ -3961,7 +3961,7 @@ def user_status_check(user_id, timeout=None):
idurl=idurl,
global_id=global_id.UrlToGlobalID(idurl),
contact_state=peer_status.state,
contact_status=online_status.stateToLabel(peer_status.state),
# contact_status=online_status.stateToLabel(peer_status.state),
),
api_method='user_status_check',
))
Expand Down Expand Up @@ -4474,35 +4474,39 @@ def suppliers_list(customer_id=None, verbose=False):
'global_id': '',
'supplier_state': None,
'connected': None,
'contact_status': 'offline',
# 'contact_status': 'offline',
'contact_state': 'OFFLINE',
}
results.append(r)
continue
sc = None
if supplier_connector.is_supplier(supplier_idurl, customer_idurl):
sc = supplier_connector.by_idurl(supplier_idurl, customer_idurl)
r = {
'position': pos,
'idurl': supplier_idurl,
'global_id': global_id.UrlToGlobalID(supplier_idurl),
'supplier_state': None if not supplier_connector.is_supplier(supplier_idurl, customer_idurl) else supplier_connector.by_idurl(supplier_idurl, customer_idurl).state,
'supplier_state': None if not sc else sc.state,
'connected': misc.readSupplierData(supplier_idurl, 'connected', customer_idurl),
'contact_status': 'offline',
# 'contact_status': 'offline',
'contact_state': 'OFFLINE',
}
if online_status.isKnown(supplier_idurl):
r['contact_status'] = online_status.getStatusLabel(supplier_idurl)
# r['contact_status'] = online_status.getStatusLabel(supplier_idurl)
r['contact_state'] = online_status.getCurrentState(supplier_idurl)
# if contact_status.isKnown(supplier_idurl):
# cur_state = contact_status.getInstance(supplier_idurl).state
# r['contact_status'] = contact_status.stateToLabel(cur_state)
# r['contact_state'] = cur_state
if verbose:
_files, _total, _report = backup_matrix.GetSupplierStats(pos, customer_idurl=customer_idurl)
r['listfiles'] = misc.readSupplierData(supplier_idurl, 'listfiles', customer_idurl)
r['listfiles'] = misc.readSupplierData(supplier_idurl, 'listfiles', customer_idurl).split('\n')
r['fragments'] = {
'items': _files,
'files': _total,
'details': _report,
}
r['contract'] = None if not sc else sc.storage_contract
results.append(r)
return RESULT(results)

Expand Down Expand Up @@ -4642,6 +4646,10 @@ def customers_list(verbose=False):
if driver.is_on('service_customer_support'):
service_customer_support_on = True
from bitdust.supplier import customer_assistant
service_supplier_contracts_on = False
if driver.is_on('service_supplier_contracts'):
service_supplier_contracts_on = True
from bitdust.supplier import storage_contract
from bitdust.contacts import contactsdb
from bitdust.p2p import online_status
from bitdust.userid import global_id
Expand All @@ -4652,27 +4660,30 @@ def customers_list(verbose=False):
'position': pos,
'global_id': '',
'idurl': '',
'contact_status': 'offline',
# 'contact_status': 'offline',
'contact_state': 'OFFLINE',
'customer_assistant_state': 'OFFLINE',
# 'customer_assistant_state': 'OFFLINE',
}
results.append(r)
continue
r = {
'position': pos,
'global_id': global_id.UrlToGlobalID(customer_idurl),
'idurl': customer_idurl,
'contact_status': 'offline',
# 'contact_status': 'offline',
'contact_state': 'OFFLINE',
'customer_assistant_state': 'OFFLINE',
# 'customer_assistant_state': 'OFFLINE',
}
if online_status.isKnown(customer_idurl):
r['contact_status'] = online_status.getStatusLabel(customer_idurl)
# r['contact_status'] = online_status.getStatusLabel(customer_idurl)
r['contact_state'] = online_status.getCurrentState(customer_idurl)
if service_customer_support_on:
assistant = customer_assistant.by_idurl(customer_idurl)
if assistant:
r['customer_assistant_state'] = assistant.state
if verbose:
if service_customer_support_on:
assistant = customer_assistant.by_idurl(customer_idurl)
if assistant:
r['customer_assistant_state'] = assistant.state
if service_supplier_contracts_on:
r['contract'] = storage_contract.get_current_customer_contract(customer_idurl)
results.append(r)
return RESULT(results)

Expand Down
5 changes: 4 additions & 1 deletion bitdust/storage/accounting.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,10 @@ def verify_storage_contract(json_data):
int(json_data['allocated_bytes'])
int(json_data['duration_hours'])
if json_data.get('my_position'):
int(json_data['my_position'])
# TODO: remove later...
json_data['ecc_position'] = json_data.pop('my_position')
if json_data.get('ecc_position'):
int(json_data['ecc_position'])
if json_data.get('ecc_map'):
str(json_data['ecc_map'])
float(json_data['raise_factor'])
Expand Down
Loading

0 comments on commit 364bcac

Please sign in to comment.