d_id, d, n, s, url = test_data[i] rc = put_immutable_handler(hash_data(d), d, "unused") if not rc: raise Exception("put_immutable_handler('%s') failed" % d) # put_mutable_handler print "put_mutable_handler" for i in xrange(0, len(test_data)): d_id, d, n, s, url = test_data[i] data_url = make_mutable_url(d_id) data = mutable_data(d_id, d, n, sig=s) data_json = json_stable_serialize(data) rc = put_mutable_handler(d_id, n, "unused", data_json) if not rc: raise Exception("put_mutable_handler('%s', '%s') failed" % (d_id, d)) test_data[i][4] = data_url # get_immutable_handler print "get_immutable_handler" for i in xrange(0, len(test_data)): d_id, d, n, s, url = test_data[i]
def put_mutable(name, data_id, data_text, privatekey, proxy=None, create=True, txid=None, ver=None, make_ver=None, conf=None ): """ put_mutable ** Consistency ** ver, if given, is the version to include in the data. make_ver, if given, is a callback that takes the data_id, data_text, and current version as arguments, and generates the version to be included in the data record uploaded. If ver is not given, but make_ver is, then make_ver will be used to generate the version. If neither ver nor make_ver are given, the mutable data (if it already exists) is fetched, and the version is calculated as the larget known version + 1. ** Durability ** Replication is best-effort. If one storage provider driver succeeds, the put_mutable succeeds. If they all fail, then put_mutable fails. More complex behavior can be had by creating a "meta-driver" that calls existing drivers' methods in the desired manner. """ if proxy is None: proxy = get_default_proxy() result = {} user = get_name_record(name, create_if_absent=create) if 'error' in user: return {'error': "Unable to load user record: %s" % user['error']} route = None exists = user_db.has_mutable_data_route(user, data_id) old_hash = None cur_hash = None new_ver = ver if ver is None: if exists: # mutable record already exists. # generate one automatically. # use the existing locally-stored version, # and fall back to using the last-known version # from the existing mutable data record. new_ver = load_mutable_data_version( config.get_config(), name, data_id, try_remote=True ) if new_ver is None: # data exists, but we couldn't figure out the version return {'error': "Unable to determine version"} if make_ver is not None: # generate version new_ver = make_ver( data_id, data_text, new_ver ) else: # no version known, and no way to generate it. # by default, start at 1. we'll manage it ourselves. if new_ver is None: new_ver = 1 else: new_ver += 1 # do we have a route for this data yet? if not exists: if not create: # won't create; expect it to exist return {'error': 'No such route'} # need to put one urls = storage.make_mutable_urls(data_id) if len(urls) == 0: return {"error": "No routes constructed"} writer_pubkey = pybitcointools.privkey_to_pubkey(privatekey) route = storage.mutable_data_route(data_id, urls, writer_pubkey=writer_pubkey) user_db.add_mutable_data_route(user, route) user_json = user_db.serialize_user(user) # update the user record with the new route update_result = update(name, user_json, privatekey, txid=txid, proxy=proxy) if 'error' in update_result: # update failed; caller should try again return update_result txid = update_result['transaction_hash'] cur_hash = update_result['value_hash'] else: route = user_db.get_mutable_data_route(user, data_id) if route is None: return {"error": "No such route"} # generate the data data = storage.mutable_data(data_id, data_text, new_ver, privkey=privatekey) if data is None: return {"error": "Failed to generate data record"} # serialize... data_json = parsing.json_stable_serialize(data) # replicate... store_rc = storage.put_mutable_data( data, privatekey ) if not store_rc: result['error'] = "Failed to store mutable data" else: result['status'] = True result['transaction_hash'] = txid if cur_hash: # propagate result['value_hash'] = cur_hash # cache new version store_mutable_data_version( conf, data_id, new_ver ) return result
def put_mutable(name, data_id, data_text, privatekey, proxy=None, create=True, txid=None, ver=None, make_ver=None, conf=None): """ put_mutable ** Consistency ** ver, if given, is the version to include in the data. make_ver, if given, is a callback that takes the data_id, data_text, and current version as arguments, and generates the version to be included in the data record uploaded. If ver is not given, but make_ver is, then make_ver will be used to generate the version. If neither ver nor make_ver are given, the mutable data (if it already exists) is fetched, and the version is calculated as the larget known version + 1. ** Durability ** Replication is best-effort. If one storage provider driver succeeds, the put_mutable succeeds. If they all fail, then put_mutable fails. More complex behavior can be had by creating a "meta-driver" that calls existing drivers' methods in the desired manner. """ if proxy is None: proxy = get_default_proxy() result = {} user = get_name_record(name, create_if_absent=create) if 'error' in user: return {'error': "Unable to load user record: %s" % user['error']} route = None exists = user_db.has_mutable_data_route(user, data_id) old_hash = None cur_hash = None new_ver = ver if ver is None: if exists: # mutable record already exists. # generate one automatically. # use the existing locally-stored version, # and fall back to using the last-known version # from the existing mutable data record. new_ver = load_mutable_data_version(config.get_config(), name, data_id, try_remote=True) if new_ver is None: # data exists, but we couldn't figure out the version return {'error': "Unable to determine version"} if make_ver is not None: # generate version new_ver = make_ver(data_id, data_text, new_ver) else: # no version known, and no way to generate it. # by default, start at 1. we'll manage it ourselves. if new_ver is None: new_ver = 1 else: new_ver += 1 # do we have a route for this data yet? if not exists: if not create: # won't create; expect it to exist return {'error': 'No such route'} # need to put one urls = storage.make_mutable_urls(data_id) if len(urls) == 0: return {"error": "No routes constructed"} writer_pubkey = pybitcointools.privkey_to_pubkey(privatekey) route = storage.mutable_data_route(data_id, urls, writer_pubkey=writer_pubkey) user_db.add_mutable_data_route(user, route) user_json = user_db.serialize_user(user) # update the user record with the new route update_result = update(name, user_json, privatekey, txid=txid, proxy=proxy) if 'error' in update_result: # update failed; caller should try again return update_result txid = update_result['transaction_hash'] cur_hash = update_result['value_hash'] else: route = user_db.get_mutable_data_route(user, data_id) if route is None: return {"error": "No such route"} # generate the data data = storage.mutable_data(data_id, data_text, new_ver, privkey=privatekey) if data is None: return {"error": "Failed to generate data record"} # serialize... data_json = parsing.json_stable_serialize(data) # replicate... store_rc = storage.put_mutable_data(data, privatekey) if not store_rc: result['error'] = "Failed to store mutable data" else: result['status'] = True result['transaction_hash'] = txid if cur_hash: # propagate result['value_hash'] = cur_hash # cache new version store_mutable_data_version(conf, data_id, new_ver) return result