Browse Source

WIP. Might be useful, might be overkill

Kirk Trombley 4 years ago
parent
commit
87371947ab
2 changed files with 95 additions and 38 deletions
  1. 61 4
      lib/rollbot/plugins/decorators/arg_wiring.py
  2. 34 34
      src/plugins/rollcoin.py

+ 61 - 4
lib/rollbot/plugins/decorators/arg_wiring.py

@@ -1,3 +1,5 @@
+import inspect
+
 from ...messaging import RollbotMessage
 
 
@@ -15,13 +17,68 @@ Subcommand = ArgConverter(lambda _, __, msg: RollbotMessage.from_subcommand(msg)
 
 
 class Config(ArgConverter):
-    def __init__(self, key):
-        super().__init__(lambda cmd, _, __, key=key: cmd.bot.config.get(key))
+    def __init__(self, key=None):
+        if key is None:
+            super().__init__(lambda cmd, _, __: cmd.bot.config)
+        else:
+            super().__init__(lambda cmd, _, __, key=key: cmd.bot.config.get(key))
+
+
+def run_converter_function(fn, cmd, db, msg):
+    return fn(*[fn.__annotations__[param].conv(cmd, db, msg) for param in inspect.signature(fn).parameters])
 
 
 class Singleton(ArgConverter):
-    def __init__(self, cls):
-        super().__init__(lambda _, db, msg, cls=cls: cls.get_or_create(db, msg)) 
+    def __init__(self, model_cls):
+        super().__init__(lambda _, db, msg, model_cls=model_cls: model_cls.get_or_create(db, msg)) 
+        self.model_cls = model_cls
+
+    def by(self, fn):
+        def do_get(cmd, db, msg):
+            key = run_converter_function(fn, cmd, db, msg)
+            return db.query(self.model_cls).get(key) or self.model_cls.create_from_key(key)
+        return ArgConverter(do_get)
+
+    def by_all(self, fn):
+        def do_get(cmd, db, msg):
+            return [db.query(self.model_cls).get(x) or self.model_cls.create_from_key(x) for x in run_converter_function(fn, cmd, db, msg)]
+        return ArgConverter(do_get)
+
+
+class Query(ArgConverter):
+    def __init__(self, model_cls):
+        super().__init__(self._convert)
+        self.model_cls = model_cls
+        self.filters = []
+
+    def filter(self, fn):
+        self.filters.append(fn)
+        return self
+
+    def _convert(self, cmd, db, msg):
+        query = db.query(self.model_cls)
+        for fn in self.filters:
+            query = query.filter(run_converter_function(fn, cmd, db, msg))
+        return query.all()
+
+
+class Lazy(ArgConverter):
+    def __init__(self, child):
+        super().__init__(self._convert)
+        self.child = child
+        self.result = None
+        self.run = False
+
+    def _convert(self, cmd, db, msg):
+        self.cmd = cmd
+        self.db = db
+        self.msg = msg
+        return self
+
+    def get(self):
+        if not self.run:
+            self.result = self.child.conv(self.cmd, self.db, self.msg)
+        return self.result
 
 
 def get_converters(parameters, annotations):

+ 34 - 34
src/plugins/rollcoin.py

@@ -5,7 +5,7 @@ import pickle
 from sudoku_py import SudokuGenerator, Sudoku
 
 from rollbot import as_plugin, with_help, with_startup, as_sender_singleton, as_group_singleton, RollbotFailure
-from rollbot.plugins.decorators.arg_wiring import Database, Config, ArgList, Singleton, Message
+from rollbot.plugins.decorators.arg_wiring import Database, Config, ArgList, Singleton, Message, Lazy, Query
 
 @as_sender_singleton
 class RollcoinWallet:
@@ -93,17 +93,23 @@ def fractional_part(number):
     return float("0." + str(float(number)).split(".")[1])
 
 
+def lookup_target(args: ArgList, wallets: Config("rollcoin.wallets")):
+    target_id = wallets.get(args[0].lower(), None)
+    if target_id is None:
+        RollbotFailure.INVALID_ARGUMENTS.with_reason(f"Could not find wallet-holder {target}").raise_exc()
+    
+    return target_id
+
+
 @with_help("Tip someone else some Rollcoins: !tip target amount")
 @as_plugin
 def tip(args: ArgList, 
-        db: Database, 
         sender_wallet: Singleton(RollcoinWallet), 
-        wallets: Config("rollcoin.wallets")):
+        target_wallet: Lazy(Singleton(RollcoinWallet).by(lookup_target))):
     if len(args) < 2:
         RollbotFailure.INVALID_ARGUMENTS.with_reason("Tip requires 2 arguments - target and amount").raise_exc()
 
-    target, *rest = args
-    amount, _ = pop_amount_arg(rest)
+    amount, _ = pop_amount_arg(args[1:])
     if amount in SPECIAL_AMOUNTS:
         if amount == "ALL":
             amount = sender_wallet.balance
@@ -113,31 +119,27 @@ def tip(args: ArgList,
             amount = -1
     assert_positive(amount)
 
-    target_id = wallets.get(target.lower(), None)
-    if target_id is None:
-        RollbotFailure.INVALID_ARGUMENTS.with_reason(f"Could not find wallet-holder {target}").raise_exc()
-    if target_id == sender_wallet.sender_id:
-        return f"You can't tip yourself!"
-
     if sender_wallet.balance < amount:
         return f"Insufficient funds! You need {round(amount - sender_wallet.balance, 2)} more Rollcoins. Have you tried to !mine, !beg, or !gamble?"
-    
-    target_wallet = db.query(RollcoinWallet).get(target_id)
-    if target_wallet is None:
-        target_wallet = RollcoinWallet.create_from_key(target_id)
-        db.add(target_wallet)
+
+    target_wallet = target_wallet.get()
+    if target_wallet.sender_id == sender_wallet.sender_id:
+        return f"You can't tip yourself!"
 
     sender_wallet.balance = sender_wallet.balance - amount
     target_wallet.balance = target_wallet.balance + amount
-    return f"Done! {target} now has {target_wallet.balance} Rollcoins"
+    return f"Done! {args[0]} now has {target_wallet.balance} Rollcoins"
+
+
+def get_non_sender_ids(wallets: Config("rollcoin.wallets"), msg: Message):
+    return [w for w in wallets.values() if w != msg.sender_id]
 
 
 @with_help("Donate money to be distributed evenly among all wallets")
 @as_plugin
 def donate(args: ArgList, 
-           db: Database, 
-           sender_wallet: Singleton(RollcoinWallet), 
-           wallets: Config("rollcoin.wallets")):
+           sender_wallet: Singleton(RollcoinWallet),
+           other_wallets: Lazy(Singleton(RollcoinWallet).by_all(get_non_sender_ids))):
     if len(args) < 1:
         return RollbotFailure.INVALID_ARGUMENTS.with_reason("Need an amount to donate")
 
@@ -154,17 +156,13 @@ def donate(args: ArgList,
     if sender_wallet.balance < amount:
         return f"Insufficient funds! You need {round(amount - sender_wallet.balance, 2)} more Rollcoins"
 
-    wallets = [w for w in wallets.values() if w != sender_wallet.sender_id]
-    per_person = amount / (len(wallets))
-    for w in wallets:
-        target_wallet = db.query(RollcoinWallet).get(w)
-        if target_wallet is None:
-            target_wallet = RollcoinWallet.create_from_key(w)
-            db.add(target_wallet)
+    other_wallets = other_wallets.get()
+    per_person = amount / (len(other_wallets))
+    for target_wallet in other_wallets:
         target_wallet.balance = target_wallet.balance + per_person
     sender_wallet.balance = sender_wallet.balance - amount
 
-    return f"Done! You have donated {per_person} to each of the {len(wallets)} other wallet(s)"
+    return f"Done! You have donated {per_person} to each of the {len(other_wallets)} other wallet(s)"
 
 
 @with_help("Receive a mining question you can answer to receive Rollcoins")
@@ -253,14 +251,18 @@ def beg(wallet: Singleton(RollcoinWallet),
     return f"Fine, I've given you {increase} Rollcoins, which brings your balance to {wallet.balance}"
 
 
+def not_sender_gambling_wallet(msg: Message):
+    return RollcoinGamblingWallet.sender_id != msg.sender_id
+
+
 @with_help("Gamble some Rollcoins")
 @as_plugin
-def gamble(db: Database, 
-           args: ArgList, 
+def gamble(args: ArgList, 
            sender_wallet: Singleton(RollcoinWallet), 
            sender_holdings: Singleton(RollcoinGamblingWallet), 
            market: Singleton(RollcoinMarket), 
-           transitions: Config("rollcoin.market")):
+           transitions: Config("rollcoin.market"),
+           other_holdings: Lazy(Query(RollcoinGamblingWallet).filter(not_sender_gambling_wallet))):
     # pos moves money wallet -> gambling, neg moves money gambling -> wallet
     # market has a current state (neutral, bull, bear, boom, bust, collapse, etc.)
     # after a transfer is made, the market evolves based on
@@ -301,9 +303,7 @@ def gamble(db: Database,
     sender_wallet.balance = sender_wallet.balance - amount
     sender_holdings.balance = multiplier * (sender_holdings.balance + amount)
 
-    for holdings in db.query(RollcoinGamblingWallet
-                            ).filter(RollcoinGamblingWallet.sender_id != sender_holdings.sender_id
-                            ).all():
+    for holdings in other_holdings.get():
         holdings.balance = multiplier * holdings.balance
 
     return f"{transition['message']}\nYour current holdings: {sender_holdings.balance}"