Browse Source

Initial commit

JoostSijm 4 years ago
commit
df90bab1c1
11 changed files with 497 additions and 0 deletions
  1. 8 0
      .gitignore
  2. 17 0
      Pipfile
  3. 171 0
      Pipfile.lock
  4. 55 0
      app/__init__.py
  5. 21 0
      app/__main__.py
  6. 10 0
      app/api.py
  7. 10 0
      app/app.py
  8. 86 0
      app/database.py
  9. 16 0
      app/jobs.py
  10. 100 0
      app/models.py
  11. 3 0
      example.env

+ 8 - 0
.gitignore

@@ -0,0 +1,8 @@
+rival_regions_wrapper/
+.venv/
+.env
+__pycache__
+*.html
+*.log
+*.png
+jobs.json

+ 17 - 0
Pipfile

@@ -0,0 +1,17 @@
+[[source]]
+name = "pypi"
+url = "https://pypi.org/simple"
+verify_ssl = true
+
+[dev-packages]
+
+[packages]
+requests = "*"
+beautifulsoup4 = "*"
+sqlalchemy = "*"
+psycopg2-binary = "*"
+python-dotenv = "*"
+apscheduler = "*"
+
+[requires]
+python_version = "3"

+ 171 - 0
Pipfile.lock

@@ -0,0 +1,171 @@
+{
+    "_meta": {
+        "hash": {
+            "sha256": "dfc866db4a7e79933532497f154755e037f8ef5947733a821745397d78893acf"
+        },
+        "pipfile-spec": 6,
+        "requires": {
+            "python_version": "3"
+        },
+        "sources": [
+            {
+                "name": "pypi",
+                "url": "https://pypi.org/simple",
+                "verify_ssl": true
+            }
+        ]
+    },
+    "default": {
+        "apscheduler": {
+            "hashes": [
+                "sha256:3bb5229eed6fbbdafc13ce962712ae66e175aa214c69bed35a06bffcf0c5e244",
+                "sha256:e8b1ecdb4c7cb2818913f766d5898183c7cb8936680710a4d3a966e02262e526"
+            ],
+            "index": "pypi",
+            "version": "==3.6.3"
+        },
+        "beautifulsoup4": {
+            "hashes": [
+                "sha256:594ca51a10d2b3443cbac41214e12dbb2a1cd57e1a7344659849e2e20ba6a8d8",
+                "sha256:a4bbe77fd30670455c5296242967a123ec28c37e9702a8a81bd2f20a4baf0368",
+                "sha256:d4e96ac9b0c3a6d3f0caae2e4124e6055c5dcafde8e2f831ff194c104f0775a0"
+            ],
+            "index": "pypi",
+            "version": "==4.9.0"
+        },
+        "certifi": {
+            "hashes": [
+                "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304",
+                "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519"
+            ],
+            "version": "==2020.4.5.1"
+        },
+        "chardet": {
+            "hashes": [
+                "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
+                "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
+            ],
+            "version": "==3.0.4"
+        },
+        "idna": {
+            "hashes": [
+                "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb",
+                "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"
+            ],
+            "version": "==2.9"
+        },
+        "psycopg2-binary": {
+            "hashes": [
+                "sha256:008da3ab51adc70a5f1cfbbe5db3a22607ab030eb44bcecf517ad11a0c2b3cac",
+                "sha256:07cf82c870ec2d2ce94d18e70c13323c89f2f2a2628cbf1feee700630be2519a",
+                "sha256:08507efbe532029adee21b8d4c999170a83760d38249936038bd0602327029b5",
+                "sha256:107d9be3b614e52a192719c6bf32e8813030020ea1d1215daa86ded9a24d8b04",
+                "sha256:17a0ea0b0eabf07035e5e0d520dabc7950aeb15a17c6d36128ba99b2721b25b1",
+                "sha256:3286541b9d85a340ee4ed42732d15fc1bb441dc500c97243a768154ab8505bb5",
+                "sha256:3939cf75fc89c5e9ed836e228c4a63604dff95ad19aed2bbf71d5d04c15ed5ce",
+                "sha256:40abc319f7f26c042a11658bf3dd3b0b3bceccf883ec1c565d5c909a90204434",
+                "sha256:51f7823f1b087d2020d8e8c9e6687473d3d239ba9afc162d9b2ab6e80b53f9f9",
+                "sha256:6bb2dd006a46a4a4ce95201f836194eb6a1e863f69ee5bab506673e0ca767057",
+                "sha256:702f09d8f77dc4794651f650828791af82f7c2efd8c91ae79e3d9fe4bb7d4c98",
+                "sha256:7036ccf715925251fac969f4da9ad37e4b7e211b1e920860148a10c0de963522",
+                "sha256:7b832d76cc65c092abd9505cc670c4e3421fd136fb6ea5b94efbe4c146572505",
+                "sha256:8f74e631b67482d504d7e9cf364071fc5d54c28e79a093ff402d5f8f81e23bfa",
+                "sha256:930315ac53dc65cbf52ab6b6d27422611f5fb461d763c531db229c7e1af6c0b3",
+                "sha256:96d3038f5bd061401996614f65d27a4ecb62d843eb4f48e212e6d129171a721f",
+                "sha256:a20299ee0ea2f9cca494396ac472d6e636745652a64a418b39522c120fd0a0a4",
+                "sha256:a34826d6465c2e2bbe9d0605f944f19d2480589f89863ed5f091943be27c9de4",
+                "sha256:a69970ee896e21db4c57e398646af9edc71c003bc52a3cc77fb150240fefd266",
+                "sha256:b9a8b391c2b0321e0cd7ec6b4cfcc3dd6349347bd1207d48bcb752aa6c553a66",
+                "sha256:ba13346ff6d3eb2dca0b6fa0d8a9d999eff3dcd9b55f3a890f12b0b6362b2b38",
+                "sha256:bb0608694a91db1e230b4a314e8ed00ad07ed0c518f9a69b83af2717e31291a3",
+                "sha256:c8830b7d5f16fd79d39b21e3d94f247219036b29b30c8270314c46bf8b732389",
+                "sha256:cac918cd7c4c498a60f5d2a61d4f0a6091c2c9490d81bc805c963444032d0dab",
+                "sha256:cc30cb900f42c8a246e2cb76539d9726f407330bc244ca7729c41a44e8d807fb",
+                "sha256:ccdc6a87f32b491129ada4b87a43b1895cf2c20fdb7f98ad979647506ffc41b6",
+                "sha256:d1a8b01f6a964fec702d6b6dac1f91f2b9f9fe41b310cbb16c7ef1fac82df06d",
+                "sha256:e004db88e5a75e5fdab1620fb9f90c9598c2a195a594225ac4ed2a6f1c23e162",
+                "sha256:eb2f43ae3037f1ef5e19339c41cf56947021ac892f668765cd65f8ab9814192e",
+                "sha256:fa466306fcf6b39b8a61d003123d442b23707d635a5cb05ac4e1b62cc79105cd"
+            ],
+            "index": "pypi",
+            "version": "==2.8.5"
+        },
+        "python-dotenv": {
+            "hashes": [
+                "sha256:25c0ff1a3e12f4bde8d592cc254ab075cfe734fc5dd989036716fd17ee7e5ec7",
+                "sha256:3b9909bc96b0edc6b01586e1eed05e71174ef4e04c71da5786370cebea53ad74"
+            ],
+            "index": "pypi",
+            "version": "==0.13.0"
+        },
+        "pytz": {
+            "hashes": [
+                "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed",
+                "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"
+            ],
+            "version": "==2020.1"
+        },
+        "requests": {
+            "hashes": [
+                "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee",
+                "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"
+            ],
+            "index": "pypi",
+            "version": "==2.23.0"
+        },
+        "six": {
+            "hashes": [
+                "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
+                "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"
+            ],
+            "version": "==1.14.0"
+        },
+        "soupsieve": {
+            "hashes": [
+                "sha256:e914534802d7ffd233242b785229d5ba0766a7f487385e3f714446a07bf540ae",
+                "sha256:fcd71e08c0aee99aca1b73f45478549ee7e7fc006d51b37bec9e9def7dc22b69"
+            ],
+            "version": "==2.0"
+        },
+        "sqlalchemy": {
+            "hashes": [
+                "sha256:083e383a1dca8384d0ea6378bd182d83c600ed4ff4ec8247d3b2442cf70db1ad",
+                "sha256:0a690a6486658d03cc6a73536d46e796b6570ac1f8a7ec133f9e28c448b69828",
+                "sha256:114b6ace30001f056e944cebd46daef38fdb41ebb98f5e5940241a03ed6cad43",
+                "sha256:128f6179325f7597a46403dde0bf148478f868df44841348dfc8d158e00db1f9",
+                "sha256:13d48cd8b925b6893a4e59b2dfb3e59a5204fd8c98289aad353af78bd214db49",
+                "sha256:211a1ce7e825f7142121144bac76f53ac28b12172716a710f4bf3eab477e730b",
+                "sha256:2dc57ee80b76813759cccd1a7affedf9c4dbe5b065a91fb6092c9d8151d66078",
+                "sha256:3e625e283eecc15aee5b1ef77203bfb542563fa4a9aa622c7643c7b55438ff49",
+                "sha256:43078c7ec0457387c79b8d52fff90a7ad352ca4c7aa841c366238c3e2cf52fdf",
+                "sha256:5b1bf3c2c2dca738235ce08079783ef04f1a7fc5b21cf24adaae77f2da4e73c3",
+                "sha256:6056b671aeda3fc451382e52ab8a753c0d5f66ef2a5ccc8fa5ba7abd20988b4d",
+                "sha256:68d78cf4a9dfade2e6cf57c4be19f7b82ed66e67dacf93b32bb390c9bed12749",
+                "sha256:7025c639ce7e170db845e94006cf5f404e243e6fc00d6c86fa19e8ad8d411880",
+                "sha256:7224e126c00b8178dfd227bc337ba5e754b197a3867d33b9f30dc0208f773d70",
+                "sha256:7d98e0785c4cd7ae30b4a451416db71f5724a1839025544b4edbd92e00b91f0f",
+                "sha256:8d8c21e9d4efef01351bf28513648ceb988031be4159745a7ad1b3e28c8ff68a",
+                "sha256:bbb545da054e6297242a1bb1ba88e7a8ffb679f518258d66798ec712b82e4e07",
+                "sha256:d00b393f05dbd4ecd65c989b7f5a81110eae4baea7a6a4cdd94c20a908d1456e",
+                "sha256:e18752cecaef61031252ca72031d4d6247b3212ebb84748fc5d1a0d2029c23ea"
+            ],
+            "index": "pypi",
+            "version": "==1.3.16"
+        },
+        "tzlocal": {
+            "hashes": [
+                "sha256:11c9f16e0a633b4b60e1eede97d8a46340d042e67b670b290ca526576e039048",
+                "sha256:949b9dd5ba4be17190a80c0268167d7e6c92c62b30026cf9764caf3e308e5590"
+            ],
+            "version": "==2.0.0"
+        },
+        "urllib3": {
+            "hashes": [
+                "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527",
+                "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"
+            ],
+            "version": "==1.25.9"
+        }
+    },
+    "develop": {}
+}

+ 55 - 0
app/__init__.py

@@ -0,0 +1,55 @@
+"""Deep Exploration Planner"""
+
+import os
+import logging
+
+from sqlalchemy import create_engine
+from sqlalchemy.orm import sessionmaker
+from dotenv import load_dotenv
+from apscheduler.schedulers.background import BackgroundScheduler
+from rival_regions_wrapper import RemoteAuthentication
+
+
+load_dotenv()
+
+# database
+ENGINE = create_engine(os.environ["DATABASE_URI"])
+SESSION = sessionmaker(bind=ENGINE)
+
+# scheduler
+SCHEDULER = BackgroundScheduler(
+    daemon=True,
+    job_defaults={'misfire_grace_time': 300},
+)
+SCHEDULER.start()
+
+# get logger
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.INFO)
+SCHEDULER_LOGGER = logging.getLogger('apscheduler')
+SCHEDULER_LOGGER.setLevel(logging.DEBUG)
+
+# create file handler
+FILE_HANDLER = logging.FileHandler('output.log')
+FILE_HANDLER.setLevel(logging.DEBUG)
+
+# create console handler
+STREAM_HANDLER = logging.StreamHandler()
+STREAM_HANDLER.setLevel(logging.INFO)
+
+# create formatter and add it to the handlers
+FORMATTER = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+STREAM_HANDLER.setFormatter(FORMATTER)
+FILE_HANDLER.setFormatter(FORMATTER)
+
+# add the handlers to logger
+LOGGER.addHandler(STREAM_HANDLER)
+LOGGER.addHandler(FILE_HANDLER)
+SCHEDULER_LOGGER.addHandler(STREAM_HANDLER)
+SCHEDULER_LOGGER.addHandler(FILE_HANDLER)
+
+# api
+MIDDLEWARE = RemoteAuthentication(
+    os.environ["API_URL"],
+    os.environ["AUTHORIZATION"]
+)

+ 21 - 0
app/__main__.py

@@ -0,0 +1,21 @@
+"""Main app"""
+
+import time
+import sys
+
+from app import SCHEDULER, LOGGER, jobs
+
+
+if __name__ == '__main__':
+    LOGGER.info('Starting application')
+    jobs.sync_deep_exploration(4002)
+    # jobs.start_deep_exploration_order(2)
+    sys.exit()
+
+    try:
+        while True:
+            time.sleep(100)
+    except KeyboardInterrupt:
+        LOGGER.info('Exiting application')
+        SCHEDULER.shutdown()
+        sys.exit()

+ 10 - 0
app/api.py

@@ -0,0 +1,10 @@
+"""Main application"""
+
+from app import MIDDLEWARE
+
+
+def download_deep_explorations(region_id):
+    """Download the deep explorations list"""
+    # return read_deep_explorations()
+    result = MIDDLEWARE.get('listed/upgrades/{}'.format(region_id))
+    return result

+ 10 - 0
app/app.py

@@ -0,0 +1,10 @@
+"""General function module"""
+
+from app import LOGGER, api
+
+
+def sync_deep_exploration(region_id):
+    """Check resources and refill if necessary"""
+    LOGGER.info('Sync deep exploration history for %s', region_id)
+    result = api.download_deep_explorations(region_id)
+    print(result)

+ 86 - 0
app/database.py

@@ -0,0 +1,86 @@
+"""Main application"""
+
+from datetime import datetime, timedelta, timezone
+
+from sqlalchemy import or_
+
+from app import SESSION, RESOURCE_MAX
+from app.models import State, Region, DeepExploration, DeepExplorationOrder, StateRegion
+
+
+def save_deep_explorations(region_id, deep_explorations):
+    """Save resources to database"""
+    session = SESSION()
+    for deep_exploration_id, deep_exploration_dict in deep_explorations.items():
+        deep_exploration = session.query(DeepExploration).get(deep_exploration_id)
+        if deep_exploration:
+            break
+        deep_exploration = DeepExploration()
+        deep_exploration.id = deep_exploration_id
+        region = session.query(Region).get(region_id)
+        if not region:
+            region = save_region(session, region_id)
+        deep_exploration.region_id = region_id
+        deep_exploration.resource_type = deep_exploration_dict['resource_type']
+        deep_exploration.until_date_time = deep_exploration_dict['until_date_time']
+        session.add(deep_exploration)
+    session.commit()
+    session.close()
+
+def get_active_deep_exploration(region_id):
+    """Get active deep exploration in a region"""
+    session = SESSION()
+    deep_exploration = session.query(DeepExploration) \
+        .filter(DeepExploration.region_id == region_id) \
+        .filter(DeepExploration.until_date_time >= datetime.now()) \
+        .first()
+    session.close()
+    return deep_exploration
+
+
+def save_region(session, region_id):
+    """Save player to database"""
+    region = Region()
+    region.id = region_id
+    region.name = 'UNKNOWN'
+    session.add(region)
+    return region
+
+def get_orders():
+    """Get deep exploration orders"""
+    session = SESSION()
+    date_time_now = datetime.now()
+    orders = session.query(DeepExplorationOrder) \
+        .filter(DeepExplorationOrder.from_date_time <= date_time_now) \
+        .filter(or_(
+            DeepExplorationOrder.until_date_time >= date_time_now,
+            DeepExplorationOrder.until_date_time == None
+        )) \
+        .all()
+    session.close()
+    return orders
+
+def get_order(order_id):
+    """Get order by id"""
+    session = SESSION()
+    order = session.query(DeepExplorationOrder).get(order_id)
+    session.close()
+    return order
+
+def get_region(region_id):
+    """Get region by id"""
+    session = SESSION()
+    region = session.query(Region).get(region_id)
+    session.close()
+    return region
+
+def get_state(region_id):
+    """Get state from region"""
+    session = SESSION()
+    state = session.query(State) \
+        .join(State.state_regions) \
+        .filter(StateRegion.region_id == region_id) \
+        .filter(StateRegion.until_date_time == None) \
+        .first()
+    session.close()
+    return state

+ 16 - 0
app/jobs.py

@@ -0,0 +1,16 @@
+"""Jobs for scheduler module"""
+
+from app import app, api
+
+
+def sync_deep_exploration(region_id):
+    """Check resources and refill if necessary"""
+    app.sync_deep_exploration(region_id)
+
+def schedule_orders():
+    """Schedule deep exploration orders"""
+    app.schedule_orders()
+
+def start_deep_exploration_order(order_id):
+    """Start deep exploration"""
+    app.start_deep_exploration(order_id)

+ 100 - 0
app/models.py

@@ -0,0 +1,100 @@
+"""Database models"""
+
+import datetime
+
+from sqlalchemy import Column, ForeignKey, Integer, String, SmallInteger, DateTime
+from sqlalchemy.orm import relationship, backref
+from sqlalchemy.ext.declarative import declarative_base
+
+
+Base = declarative_base()
+
+class State(Base):
+    """Model for state"""
+    __tablename__ = 'state'
+    id = Column(Integer, primary_key=True)
+    name = Column(String)
+
+class Region(Base):
+    """Model for region"""
+    __tablename__ = 'region'
+    id = Column(Integer, primary_key=True)
+    name = Column(String)
+    gold_limit = Column(SmallInteger)
+    oil_limit = Column(SmallInteger)
+    ore_limit = Column(SmallInteger)
+    uranium_limit = Column(SmallInteger)
+    diamond_limit = Column(SmallInteger)
+
+    def get_limit(self, resource_type):
+        """get limit for resoruce type"""
+        limit = {
+            0: self.gold_limit,
+            3: self.oil_limit,
+            4: self.ore_limit,
+            11: self.uranium_limit,
+            15: self.diamond_limit,
+        }
+        return limit[resource_type] if resource_type in limit else None
+
+
+class StateRegion(Base):
+    """Model for state region"""
+    __tablename__ = 'state_region'
+    state_id = Column(Integer, ForeignKey('state.id'), primary_key=True)
+    region_id = Column(Integer, ForeignKey('region.id'), primary_key=True)
+    from_date_time = Column(DateTime, primary_key=True)
+    until_date_time = Column(DateTime)
+
+    region = relationship(
+        'Region',
+        backref=backref('state_regions', lazy='dynamic')
+    )
+    state = relationship(
+        'State',
+        backref=backref('state_regions', lazy='dynamic')
+    )
+
+
+class DeepExploration(Base):
+    """Model for deep exploration"""
+    __tablename__ = 'deep_exploration'
+    id = Column(Integer, primary_key=True)
+    until_date_time = Column(DateTime)
+    points = Column(Integer)
+    resource_type = Column(SmallInteger)
+    region_id = Column(Integer, ForeignKey('region.id'))
+    region = relationship(
+        'Region',
+        backref=backref('deep_explorations', lazy='dynamic')
+    )
+
+
+class DeepExplorationOrder(Base):
+    """Model for deep exploration order"""
+    __tablename__ = 'deep_exploration_order'
+    id = Column(Integer, primary_key=True)
+    resource_type = Column(SmallInteger, nullable=False)
+    order_type = Column(SmallInteger, nullable=False)
+    amount = Column(Integer)
+    from_date_time = Column(DateTime)
+    until_date_time = Column(DateTime)
+
+    region_id = Column(Integer, ForeignKey('region.id'))
+    region = relationship(
+        'Region',
+        backref=backref('resource_stats', lazy='dynamic')
+    )
+
+    order_types = {
+        0: 'max',
+        1: 'fixed',
+        2: 'percentage',
+        3: 'auto',
+    }
+
+    def order_type_name(self):
+        """Type name"""
+        if self.order_type in self.order_types:
+            return self.order_types[self.type]
+        return 'unknown'

+ 3 - 0
example.env

@@ -0,0 +1,3 @@
+AUTHORIZATION=PLACEHOLDER
+DATABASE_URI='postgresql://hvs@localhost/hvs'
+API_URL='http://localhost:5000/api/request/'