Add price policy class to determine sell price (#1785)

This commit is contained in:
Jonathan Zernik 2021-11-07 04:40:17 -08:00 committed by GitHub
parent 581ef4f226
commit c96f7c7f7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 163 additions and 10 deletions

View file

@ -0,0 +1,65 @@
# MIT License
#
# Copyright (c) 2020 Jonathan Zernik
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import logging
from typing import Optional
from squeak.core import CSqueak
from squeaknode.config.config import SqueaknodeConfig
from squeaknode.core.peer_address import PeerAddress
from squeaknode.core.squeak_peer import SqueakPeer
from squeaknode.core.squeak_profile import SqueakProfile
from squeaknode.db.squeak_db import SqueakDb
logger = logging.getLogger(__name__)
class PricePolicy:
def __init__(self, squeak_db: SqueakDb, config: SqueaknodeConfig):
self.squeak_db = squeak_db
self.config = config
def get_price(self, squeak: CSqueak, peer_address: PeerAddress) -> int:
"""Get the price to sell this squeak to this peer.
"""
# Return zero for price if peer is configured to be share for free.
peer = self.get_peer(peer_address)
if peer is not None and peer.share_for_free:
return 0
# Return custom price if address is configured with custom price.
squeak_address = str(squeak.GetAddress())
squeak_profile = self.get_profile(squeak_address)
if squeak_profile is not None and squeak_profile.use_custom_price:
return squeak_profile.custom_price_msat
return self.get_default_price()
def get_peer(self, peer_address: PeerAddress) -> Optional[SqueakPeer]:
return self.squeak_db.get_peer_by_address(peer_address)
def get_profile(self, address: str) -> Optional[SqueakProfile]:
return self.squeak_db.get_profile_by_address(address)
def get_default_price(self) -> int:
return self.config.node.price_msat

View file

@ -65,6 +65,7 @@ from squeaknode.core.update_twitter_stream_event import UpdateTwitterStreamEvent
from squeaknode.core.user_config import UserConfig
from squeaknode.node.active_download_manager import ActiveDownload
from squeaknode.node.listener_subscription_client import EventListener
from squeaknode.node.price_policy import PricePolicy
from squeaknode.node.received_payments_subscription_client import ReceivedPaymentsSubscriptionClient
@ -232,16 +233,8 @@ class SqueakController:
return sent_offer
def get_price_for_squeak(self, squeak: CSqueak, peer_address: PeerAddress) -> int:
# Return zero for price if peer is configured to be share for free.
peer = self.squeak_db.get_peer_by_address(peer_address)
if peer is not None and peer.share_for_free:
return 0
# Return custom price if address is configured with custom price.
squeak_address = str(squeak.GetAddress())
squeak_profile = self.get_squeak_profile_by_address(squeak_address)
if squeak_profile is not None and squeak_profile.use_custom_price:
return squeak_profile.custom_price_msat
return self.config.node.price_msat
price_policy = PricePolicy(self.squeak_db, self.config)
return price_policy.get_price(squeak, peer_address)
def create_signing_profile(self, profile_name: str) -> int:
squeak_profile = create_signing_profile(

View file

@ -0,0 +1,95 @@
# MIT License
#
# Copyright (c) 2020 Jonathan Zernik
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import mock
import pytest
from squeaknode.node.price_policy import PricePolicy
@pytest.fixture()
def price_policy():
yield PricePolicy(None, None)
def test_get_price(price_policy, squeak, peer_address):
with mock.patch.object(price_policy, 'get_peer', autospec=True) as mock_get_peer, \
mock.patch.object(price_policy, 'get_profile', autospec=True) as mock_get_profile, \
mock.patch.object(price_policy, 'get_default_price', autospec=True) as mock_get_default_price:
mock_get_peer.return_value = None
mock_get_profile.return_value = None
mock_get_default_price.return_value = 555
assert price_policy.get_price(squeak, peer_address) == 555
def test_get_price_profile_custom_price(price_policy, squeak, peer_address, signing_profile):
with mock.patch.object(price_policy, 'get_peer', autospec=True) as mock_get_peer, \
mock.patch.object(price_policy, 'get_profile', autospec=True) as mock_get_profile, \
mock.patch.object(price_policy, 'get_default_price', autospec=True) as mock_get_default_price:
mock_get_peer.return_value = None
mock_get_profile.return_value = signing_profile._replace(
use_custom_price=True,
custom_price_msat=54321,
)
mock_get_default_price.return_value = 555
assert price_policy.get_price(squeak, peer_address) == 54321
def test_get_price_profile_no_custom_price(price_policy, squeak, peer_address, signing_profile):
with mock.patch.object(price_policy, 'get_peer', autospec=True) as mock_get_peer, \
mock.patch.object(price_policy, 'get_profile', autospec=True) as mock_get_profile, \
mock.patch.object(price_policy, 'get_default_price', autospec=True) as mock_get_default_price:
mock_get_peer.return_value = None
mock_get_profile.return_value = signing_profile._replace(
use_custom_price=False,
custom_price_msat=54321,
)
mock_get_default_price.return_value = 555
assert price_policy.get_price(squeak, peer_address) == 555
def test_get_price_profile_share_free_peer(price_policy, squeak, peer_address, peer):
with mock.patch.object(price_policy, 'get_peer', autospec=True) as mock_get_peer, \
mock.patch.object(price_policy, 'get_profile', autospec=True) as mock_get_profile, \
mock.patch.object(price_policy, 'get_default_price', autospec=True) as mock_get_default_price:
mock_get_peer.return_value = peer._replace(
share_for_free=True,
)
mock_get_profile.return_value = None
mock_get_default_price.return_value = 555
assert price_policy.get_price(squeak, peer_address) == 0
def test_get_price_profile_no_share_free_peer(price_policy, squeak, peer_address, peer):
with mock.patch.object(price_policy, 'get_peer', autospec=True) as mock_get_peer, \
mock.patch.object(price_policy, 'get_profile', autospec=True) as mock_get_profile, \
mock.patch.object(price_policy, 'get_default_price', autospec=True) as mock_get_default_price:
mock_get_peer.return_value = peer._replace(
share_for_free=False,
)
mock_get_profile.return_value = None
mock_get_default_price.return_value = 555
assert price_policy.get_price(squeak, peer_address) == 555