-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient.py
187 lines (136 loc) · 5.4 KB
/
client.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#!/usr/bin/env python3
import signal
from autobahn.asyncio.component import Component
from autobahn.asyncio.component import run
import txaio
from demo_config import create_autobahn_component_config
from demo_config import MARKET_BIDDER_ADD
from demo_config import MARKET_BIDDER_GONE
from demo_config import MARKET_GET
from demo_config import MARKET_ITEM_BID
from demo_config import MARKET_ITEM_SELL
from item import Item
class Client:
def __init__(self):
ab_component_config = create_autobahn_component_config()
self._component = Component(**ab_component_config)
self._component.on("join", self._on_join)
self._session = None
self._name = None
def run(self):
run([self._component])
async def _identify(self):
while not self._name:
self._name = input("Enter your name: ")
while not await self._session.call(MARKET_BIDDER_ADD, self._name):
self._name = input("Name already taken, please enter a different one: ")
async def _print_help(self, *args):
print(
"""
Commands are represented by a word or its first letter.
Arguments can be provided (whitespace separated) otherwise they will be queried.
[h]help Print this help message.
[q]uit
[e]xit Exit the marketplace
[l]ist
[g]et Print all the currently listed items with their details.
[s]ell [ITEM_NAME INITIAL_PRICE DEADLINE]
Add a new item for sale at a given price. Bids are accepted within
the given DEADLINE minutes. PRICE and DEALINE are floating numbers.
[b]id [ITEM_NAME PRICE]
Bid on an item at a given price and tell if the offer was accepted.
Bids are rejected if the price is an invalid number, a lower number
than the current price or highest bid, or the bid happend after the
deadline.
"""
)
async def _list_items(self, *args):
result = await self._session.call(MARKET_GET)
items = [Item.wamp_unpack(i) for i in result]
names = [item.name for item in items]
len_name = max(map(len, names), default=len("Item"))
len_name = max(len_name, len("Item"))
prices_str = [str(item.price) for item in items]
len_price = max(map(len, prices_str), default=len("Price"))
len_price = max(len_price, len("Price"))
deadlines = map(lambda i: i.deadline_as_HMS(), items)
winners = map(lambda i: i.winner if i.winner else "-", items)
line = f"{{0:{len_name}}} {{1:>{len_price}}} {{2}} {{3}}"
print(line.format("Item", "Price", "Deadline", "Winner"))
print(line.format(len_name * "-", len_price * "-", 8 * "-", 6 * "-"))
for line_args in zip(names, prices_str, deadlines, winners):
print(line.format(*line_args))
print()
async def _sell(self, *args):
if 2 < len(args):
name = " ".join(args[:-2])
price = args[-2]
deadline = args[-1]
else:
name = " ".join(args) or input("Item name: ")
price = float(input("Asking price: "))
deadline = float(input("Deadline in minutes: "))
item = Item(name, price, deadline)
if await self._session.call(MARKET_ITEM_SELL, **item.wamp_pack()):
print(f"Item '{item.name}' added.\n")
else:
print(f"Unable to add item '{item.name}'.\n")
async def _bid(self, *args):
if 1 < len(args):
name = " ".join(args[:-1])
price = args[-1]
else:
name = " ".join(args) or input("Item name: ")
price = float(input("Bid: "))
print("Bid accepted\n") if await self._session.call(
MARKET_ITEM_BID, name, price, self._name
) else print("Bid rejected\n")
async def _on_join(self, session, details):
self._session = session
print(f"\nWelcome to '{session.realm}' marketplace")
await self._identify()
await self._print_help()
try:
await self._prompt_user()
except:
pass
print("Bye.")
try:
await self._session.call(MARKET_BIDDER_GONE, self._name)
except:
pass
session.leave()
async def _prompt_user(self):
action = ""
args = None
while action not in ("q", "quit", "e", "exit"):
functions = {
"h": self._print_help,
"help": self._print_help,
"l": self._list_items,
"list": self._list_items,
"g": self._list_items,
"get": self._list_items,
"s": self._sell,
"sell": self._sell,
"b": self._bid,
"bid": self._bid,
}
function = functions.get(action.lower())
if function:
try:
await function(*args)
except BaseException as error:
print(f"Invalid input: {error}")
user_input = input("> ").strip().split()
action, *args = user_input if 0 < len(user_input) else ("",)
if __name__ == "__main__":
# Handle Ctrl+C gracefully
def signal_handler(sig, frame):
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
# Only log warnings and errors from autobahn
txaio.use_asyncio()
txaio.start_logging(level="warn")
client = Client()
client.run()