mirror of
https://gitlab.com/0xDEAD10CC/pycoindroid
synced 2025-07-06 04:51:08 -07:00
Initial commit
This commit is contained in:
commit
310b1ae5e4
6 changed files with 346 additions and 0 deletions
25
src/CoindroidAPI.py
Normal file
25
src/CoindroidAPI.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import logging, requests
|
||||||
|
from gevent import Greenlet
|
||||||
|
|
||||||
|
|
||||||
|
class CoindroidAPITask(Greenlet):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
Greenlet.__init__(self)
|
||||||
|
self.eventsEvent = kwargs.get("eventsEvent")
|
||||||
|
self.eventsEvent.clear()
|
||||||
|
self.logger = logging.getLogger(self.__class__.__name__)
|
||||||
|
self.apiSession = requests.Session()
|
||||||
|
self.lastTransaction = None
|
||||||
|
self.currentTransaction = None
|
||||||
|
self.apiUrl = kwargs.get("apiUrl")
|
||||||
|
self.pause = kwargs.get("pause")
|
||||||
|
if not self.apiUrl:
|
||||||
|
self.logger.debug("apiUrl not set. Setting to https://api.coindroids.com/")
|
||||||
|
self.apiUrl = "https://api.coindroids.com/"
|
||||||
|
else:
|
||||||
|
self.logger.debug("Setting apiUrl to {}".format(self.apiUrl))
|
||||||
|
if not self.pause:
|
||||||
|
self.logger.debug("pause not set. Setting to 10...")
|
||||||
|
self.pause = 10
|
||||||
|
else:
|
||||||
|
self.logger.debug("Setting pause to {}...".format(self.pause))
|
96
src/Currency.py
Normal file
96
src/Currency.py
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
import logging
|
||||||
|
from CoindroidAPI import CoindroidAPITask
|
||||||
|
from collections import namedtuple
|
||||||
|
from gevent import sleep
|
||||||
|
|
||||||
|
|
||||||
|
class CurrencyTask(CoindroidAPITask):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super(CurrencyTask, self).__init__(**kwargs)
|
||||||
|
self.logger = logging.getLogger(self.__class__.__name__)
|
||||||
|
self.currencyComparisonTuple = namedtuple("currencyComparison",
|
||||||
|
["added", "removed", "modified", "same"])
|
||||||
|
self.updateCurrency()
|
||||||
|
self.eventsEvent.set()
|
||||||
|
|
||||||
|
def dictCompare(self, d1, d2):
|
||||||
|
d1_keys = set(d1.keys())
|
||||||
|
d2_keys = set(d2.keys())
|
||||||
|
intersect_keys = d1_keys.intersection(d2_keys)
|
||||||
|
added = d1_keys - d2_keys
|
||||||
|
removed = d2_keys - d1_keys
|
||||||
|
modified = {o: (d1[o], d2[o]) for o in intersect_keys if d1[o] != d2[o]}
|
||||||
|
same = set(o for o in intersect_keys if d1[o] == d2[o])
|
||||||
|
return added, removed, modified, same
|
||||||
|
|
||||||
|
def updateCurrency(self):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
request = self.apiSession.get(self.apiUrl + "currency",
|
||||||
|
params={"id": "eq.2"})
|
||||||
|
except:
|
||||||
|
self.logger.exception("Unable to get currency!")
|
||||||
|
self.logger.error("Waiting for update...")
|
||||||
|
sleep(self.pause)
|
||||||
|
continue
|
||||||
|
if self.currentTransaction:
|
||||||
|
self.lastTransaction = self.currentTransaction.copy()
|
||||||
|
self.currentTransaction = request.json()[0]
|
||||||
|
self.logger.info("Retrieved currency from Coindroids...")
|
||||||
|
self.logger.debug("{}".format(self.currentTransaction.get("last_ingested")))
|
||||||
|
if not self.lastTransaction:
|
||||||
|
self.logger.info("No previous currency available... Waiting for update...")
|
||||||
|
self.lastTransaction = self.currentTransaction.copy()
|
||||||
|
self.currentTransaction = None
|
||||||
|
sleep(self.pause)
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
|
||||||
|
def compareCurrency(self):
|
||||||
|
currencyComparison = self.currencyComparisonTuple(
|
||||||
|
*self.dictCompare(self.lastTransaction, self.currentTransaction))
|
||||||
|
for name, value in currencyComparison._asdict().items():
|
||||||
|
if "same" in name:
|
||||||
|
continue
|
||||||
|
if value:
|
||||||
|
self.logger.debug("currency {}: {}".format(name, value))
|
||||||
|
eventUpdate = False
|
||||||
|
if currencyComparison.modified:
|
||||||
|
if "overall_purse_sum" in currencyComparison.modified:
|
||||||
|
self.logger.info("overall_purse_sum updated from {0[0]} to {0[1]}...".format(
|
||||||
|
currencyComparison.modified["overall_purse_sum"]))
|
||||||
|
if "total_number_of_attacks" in currencyComparison.modified:
|
||||||
|
self.logger.info("total_number_of_attacks updated from {0[0]} to {0[1]}...".format(
|
||||||
|
currencyComparison.modified["total_number_of_attacks"]))
|
||||||
|
eventUpdate = True
|
||||||
|
if "total_amount_of_attacks" in currencyComparison.modified:
|
||||||
|
self.logger.info("total_amount_of_attacks updated from {0[0]} to {0[1]}...".format(
|
||||||
|
currencyComparison.modified["total_amount_of_attacks"]))
|
||||||
|
eventUpdate = True
|
||||||
|
if "total_number_of_item_purchases" in currencyComparison.modified:
|
||||||
|
self.logger.info("total_number_of_item_purchases updated from {0[0]} to {0[1]}...".format(
|
||||||
|
currencyComparison.modified["total_number_of_item_purchases"]))
|
||||||
|
if "total_droids" in currencyComparison.modified:
|
||||||
|
self.logger.info("total_droids updated from {0[0]} to {0[1]}...".format(
|
||||||
|
currencyComparison.modified["total_droids"]))
|
||||||
|
if "percentage_of_droids" in currencyComparison.modified:
|
||||||
|
self.logger.info("percentage_of_droids updated from {0[0]} to {0[1]}...".format(
|
||||||
|
currencyComparison.modified["percentage_of_droids"]))
|
||||||
|
if "pending_payouts" in currencyComparison.modified:
|
||||||
|
self.logger.info("pending_payouts updated from {0[0]} to {0[1]}...".format(
|
||||||
|
currencyComparison.modified["pending_payouts"]))
|
||||||
|
if eventUpdate:
|
||||||
|
self.logger.info("Need to update events...")
|
||||||
|
return eventUpdate
|
||||||
|
|
||||||
|
def _run(self):
|
||||||
|
self.logger.info("Running {}".format(self.__class__.__name__))
|
||||||
|
while True:
|
||||||
|
update = self.compareCurrency()
|
||||||
|
if update:
|
||||||
|
self.eventsEvent.set()
|
||||||
|
sleep(self.pause)
|
||||||
|
else:
|
||||||
|
sleep(self.pause)
|
||||||
|
self.logger.debug("Updating currency...")
|
||||||
|
self.updateCurrency()
|
92
src/Droid.py
Normal file
92
src/Droid.py
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
import logging
|
||||||
|
from CoindroidAPI import CoindroidAPITask
|
||||||
|
from gevent import sleep
|
||||||
|
|
||||||
|
# todo Flesh out getting events to Droids and having them act accordingly
|
||||||
|
|
||||||
|
class DroidTask(CoindroidAPITask):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
"""
|
||||||
|
This is a DroidTask
|
||||||
|
It performs actions on events received from:w
|
||||||
|
|
||||||
|
:param \**kwargs:
|
||||||
|
See below
|
||||||
|
:Keyword Arguments:
|
||||||
|
* *apiUrl* (``str``) --
|
||||||
|
Coindroids API URL.
|
||||||
|
Default is ``https://api.coindroids.com/``
|
||||||
|
* *pause* (``int``) --
|
||||||
|
Time to wait between requests
|
||||||
|
"""
|
||||||
|
super(EventTask, self).__init__(**kwargs)
|
||||||
|
self.logger = logging.getLogger(__name__)
|
||||||
|
self.updateEvents()
|
||||||
|
|
||||||
|
def updateEvents(self):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
request = self.apiSession.get(self.apiUrl + "event",
|
||||||
|
params={"order" : "block_height.desc",
|
||||||
|
"currency_id": "eq.2"})
|
||||||
|
# "involved_droids": ""}).json()
|
||||||
|
except:
|
||||||
|
self.logger.exception("Unable to get events!")
|
||||||
|
self.logger.error("Waiting for update...")
|
||||||
|
sleep(self.pause)
|
||||||
|
continue
|
||||||
|
self.currentTransaction = request.json()
|
||||||
|
self.logger.info("Retrieved events from Coindroids...")
|
||||||
|
self.logger.debug("{} events found...".format(len(self.currentTransaction)))
|
||||||
|
if not self.lastTransaction:
|
||||||
|
self.logger.info("No previous events available... Waiting for update...")
|
||||||
|
self.lastTransaction = self.currentTransaction.copy()
|
||||||
|
self.currentTransaction = None
|
||||||
|
sleep(self.pause)
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
|
||||||
|
def compareEvents(self):
|
||||||
|
"""
|
||||||
|
Compares old events to new events
|
||||||
|
:return: list of events
|
||||||
|
"""
|
||||||
|
setLastEventsIDs = set([x.get("action_id") for x in self.lastTransaction])
|
||||||
|
setEventsIDs = set([x.get("action_id") for x in self.currentTransaction])
|
||||||
|
setRemovedEvents = setLastEventsIDs - setEventsIDs
|
||||||
|
setAddedEvents = setEventsIDs - setLastEventsIDs
|
||||||
|
ret = []
|
||||||
|
if setRemovedEvents:
|
||||||
|
self.logger.debug("Events removed from this update: {}".format(setRemovedEvents))
|
||||||
|
if setAddedEvents:
|
||||||
|
self.logger.debug("Added events:")
|
||||||
|
for event_id in setAddedEvents:
|
||||||
|
for event in self.currentTransaction:
|
||||||
|
if event:
|
||||||
|
if event["action_id"] == event_id:
|
||||||
|
ret.append(event)
|
||||||
|
self.logger.debug("At block_height {}, action_id {} - {}({}):{}({}) did {} on {}".format(
|
||||||
|
*(event.get(i) for i in ("block_height",
|
||||||
|
"action_id", "player_username", "player_id",
|
||||||
|
"droid_name", "droidID", "action_type",
|
||||||
|
"target"))))
|
||||||
|
else:
|
||||||
|
self.logger.error("Found empty event!")
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def _run(self):
|
||||||
|
self.logger.info("Running {}".format(self.__class__.__name__))
|
||||||
|
while True:
|
||||||
|
if self.eventsEvent.ready():
|
||||||
|
self.logger.debug("{} woken up...".format(self.__class__.__name__))
|
||||||
|
for _ in range(5):
|
||||||
|
self.logger.debug("Trying to get updated events ({}/5)".format(_))
|
||||||
|
update = self.compareEvents()
|
||||||
|
if update:
|
||||||
|
self.logger.debug("TODO: Send events to queue for worker threads")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.logger.debug("No events detected")
|
||||||
|
sleep(5)
|
||||||
|
sleep(self.pause)
|
||||||
|
continue
|
103
src/Event.py
Normal file
103
src/Event.py
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
import logging
|
||||||
|
from CoindroidAPI import CoindroidAPITask
|
||||||
|
from gevent import sleep
|
||||||
|
from twilio.rest import Client as TwilioClient
|
||||||
|
|
||||||
|
|
||||||
|
class EventTask(CoindroidAPITask):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super(EventTask, self).__init__(**kwargs)
|
||||||
|
self.logger = logging.getLogger(self.__class__.__name__)
|
||||||
|
twilioAccount = "ACdfcd2b529db83954e8a0041796072960"
|
||||||
|
twilioToken = "ab9b98a0b3da8a728d14774192773af2"
|
||||||
|
self.twilioClient = TwilioClient(twilioAccount, twilioToken)
|
||||||
|
self.updateEvents()
|
||||||
|
|
||||||
|
def updateEvents(self, updateLast=True):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
request = self.apiSession.get(self.apiUrl + "event",
|
||||||
|
params={"order" : "block_height.desc",
|
||||||
|
"currency_id": "eq.2"})
|
||||||
|
# "involved_droids": ""}).json()
|
||||||
|
except:
|
||||||
|
self.logger.exception("Unable to get events!")
|
||||||
|
self.logger.error("Waiting for update...")
|
||||||
|
sleep(self.pause)
|
||||||
|
continue
|
||||||
|
if not updateLast:
|
||||||
|
self.logger.debug("Not updating last transaction...")
|
||||||
|
if (self.currentTransaction and updateLast):
|
||||||
|
self.logger.debug("Updating previous transaction...")
|
||||||
|
self.lastTransaction = self.currentTransaction.copy()
|
||||||
|
self.currentTransaction = request.json()
|
||||||
|
self.logger.info("Retrieved events from Coindroids...")
|
||||||
|
self.logger.debug("{} events found...".format(len(self.currentTransaction)))
|
||||||
|
if not self.lastTransaction:
|
||||||
|
self.logger.info("No previous events available... Waiting for update...")
|
||||||
|
self.lastTransaction = self.currentTransaction.copy()
|
||||||
|
self.currentTransaction = None
|
||||||
|
sleep(self.pause)
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
|
||||||
|
def compareEvents(self):
|
||||||
|
setLastEventsIDs = set([x.get("action_id") for x in self.lastTransaction])
|
||||||
|
setEventsIDs = set([x.get("action_id") for x in self.currentTransaction])
|
||||||
|
setAddedEvents = setEventsIDs - setLastEventsIDs
|
||||||
|
ret = []
|
||||||
|
if setAddedEvents:
|
||||||
|
self.logger.debug("Added events:")
|
||||||
|
for event_id in setAddedEvents:
|
||||||
|
for event in self.currentTransaction:
|
||||||
|
if event:
|
||||||
|
if event["action_id"] == event_id:
|
||||||
|
ret.append(event)
|
||||||
|
keys = ["block_height", "action_id", "player_username", "player_id", "droid_name",
|
||||||
|
"droid_id", "action_type"]
|
||||||
|
message_args = [event.get(i) for i in keys]
|
||||||
|
if event.get("target"):
|
||||||
|
message_args.extend([event["target"].get("name"), event["target"].get("id")])
|
||||||
|
if (event["target"].get("name") == "bob") or (event["target"].get("id") == 160):
|
||||||
|
self.logger.debug("TEMP - bob's got an action!!! sending sms!!")
|
||||||
|
try:
|
||||||
|
self.twilioClient.messages.create(
|
||||||
|
to="+14088963912",
|
||||||
|
from_="+14159037708",
|
||||||
|
body="At block_height {}, action_id {} - {}({}):{}({}) did {} on {}({})".format(
|
||||||
|
*message_args)
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
self.logger.exception("Unable to send SMS!!")
|
||||||
|
else:
|
||||||
|
self.logger.warning("Event has no target!")
|
||||||
|
message_args.extend([None, None])
|
||||||
|
self.logger.debug(
|
||||||
|
"At block_height {}, action_id {} - {}({}):{}({}) did {} on {}({})".format(
|
||||||
|
*message_args))
|
||||||
|
else:
|
||||||
|
self.logger.error("Found empty event!")
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def _run(self):
|
||||||
|
self.logger.info("Running {}".format(self.__class__.__name__))
|
||||||
|
while True:
|
||||||
|
if self.eventsEvent.ready():
|
||||||
|
self.logger.debug("{} woken up...".format(self.__class__.__name__))
|
||||||
|
for _ in range(5):
|
||||||
|
self.logger.debug("Trying to get updated events ({}/5)".format(_))
|
||||||
|
self.updateEvents(updateLast=False)
|
||||||
|
update = self.compareEvents()
|
||||||
|
if update:
|
||||||
|
self.eventsEvent.clear()
|
||||||
|
self.logger.debug("TODO: Send events to queue for worker threads")
|
||||||
|
self.updateEvents()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.logger.debug("No events detected")
|
||||||
|
sleep(5)
|
||||||
|
self.updateEvents(updateLast=False)
|
||||||
|
else:
|
||||||
|
self.logger.error("No events detected after 5 rounds!")
|
||||||
|
sleep(self.pause)
|
||||||
|
continue
|
0
src/__init__.py
Normal file
0
src/__init__.py
Normal file
30
src/main.py
Normal file
30
src/main.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# pycoindroid v0.1
|
||||||
|
# © 2017 DEAD10CC <0x@DEAD10.CC>
|
||||||
|
# a dumb hack on Coindroids
|
||||||
|
|
||||||
|
import gevent, logging
|
||||||
|
from gevent.event import Event
|
||||||
|
from Currency import CurrencyTask
|
||||||
|
from Event import EventTask
|
||||||
|
|
||||||
|
formatter = logging.Formatter('%(asctime)s - %(name)s %(funcName)s():%(lineno)d - %(levelname)s - %(message)s')
|
||||||
|
logger = logging.getLogger()
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
ch = logging.StreamHandler()
|
||||||
|
ch.setLevel(logging.DEBUG)
|
||||||
|
ch.setFormatter(formatter)
|
||||||
|
logger.addHandler(ch)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
while True:
|
||||||
|
logger.info("Starting main loop...")
|
||||||
|
eventsEvent = Event()
|
||||||
|
currencyTask = CurrencyTask.spawn(eventsEvent=eventsEvent)
|
||||||
|
eventTask = EventTask.spawn(eventsEvent=eventsEvent)
|
||||||
|
gevent.joinall([currencyTask, eventsEvent])
|
||||||
|
logger.error("Main loop ended... This shouldn't happen?")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Add table
Add a link
Reference in a new issue