Skip to content

Commit

Permalink
Cleanup config module
Browse files Browse the repository at this point in the history
Remove code repetition by putting variables in class attributes so they
are set automatically from environment based on their names and types.

Signed-off-by: alfred richardsn <rchrdsn@protonmail.ch>
  • Loading branch information
r4rdsn committed Nov 22, 2019
1 parent e921d9e commit 71e5238
Show file tree
Hide file tree
Showing 13 changed files with 85 additions and 72 deletions.
10 changes: 5 additions & 5 deletions src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
from aiogram.utils import executor

from src import bot
from src import config
from src import handlers # noqa: F401
from src import notifications
from src.bot import dp
from src.bot import tg
from src.config import Config
from src.escrow import connect_to_blockchains


Expand All @@ -34,7 +34,7 @@ async def on_startup(webhook_path, *args):
Set webhook and run background tasks.
"""
await tg.delete_webhook()
await tg.set_webhook("https://" + config.SERVER_HOST + webhook_path)
await tg.set_webhook("https://" + Config.SERVER_HOST + webhook_path)
asyncio.create_task(notifications.run_loop())
asyncio.create_task(connect_to_blockchains())

Expand All @@ -45,15 +45,15 @@ def main():
Bot's main entry point.
"""
url_token = secrets.token_urlsafe()
webhook_path = config.WEBHOOK_PATH + "/" + url_token
webhook_path = Config.WEBHOOK_PATH + "/" + url_token

bot.setup()
executor.start_webhook(
dispatcher=dp,
webhook_path=webhook_path,
on_startup=lambda *args: on_startup(webhook_path, *args),
host=config.INTERNAL_HOST,
port=config.SERVER_PORT,
host=Config.INTERNAL_HOST,
port=Config.SERVER_PORT,
)
print() # Executor stopped with ^C

Expand Down
8 changes: 4 additions & 4 deletions src/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from aiogram.contrib.middlewares.logging import LoggingMiddleware
from aiogram.dispatcher import Dispatcher

from src import config
from src.config import Config
from src.database import MongoStorage
from src.i18n import i18n

Expand All @@ -33,16 +33,16 @@


def setup():
"""Set API token from config to bot and setup dispatcher."""
with open(config.TOKEN_FILENAME, "r") as token_file:
"""Set API token from Config to bot and setup dispatcher."""
with open(Config.TOKEN_FILENAME, "r") as token_file:
tg._ctx_token.set(token_file.read().strip())

dp.storage = MongoStorage()

i18n.reload()
dp.middleware.setup(i18n)

logging.basicConfig(level=config.LOGGER_LEVEL)
logging.basicConfig(level=Config.LOGGER_LEVEL)
dp.middleware.setup(LoggingMiddleware())


Expand Down
59 changes: 37 additions & 22 deletions src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,40 @@ def getenv_bool(key, default=None):
return env == "true" if env in ("true", "false") else default


TOKEN_FILENAME = getenv("TOKEN_FILENAME")
INTERNAL_HOST = getenv("INTERNAL_HOST", "127.0.0.1")
SERVER_HOST = getenv("SERVER_HOST")
SERVER_PORT = getenv_int("SERVER_PORT")
WEBHOOK_PATH = getenv("WEBHOOK_PATH")
DATABASE_NAME = getenv("DATABASE_NAME", "tellerbot")
DATABASE_HOST = getenv("DATABASE_HOST", "127.0.0.1")
DATABASE_USERNAME = getenv("DATABASE_USERNAME")
DATABASE_PASSWORD_FILENAME = getenv("DATABASE_PASSWORD_FILENAME")

LOGGER_LEVEL = getenv("LOGGER_LEVEL")
LOG_FILENAME = getenv("LOG_FILENAME")

SUPPORT_CHAT_ID = getenv_int("SUPPORT_CHAT_ID")
EXCEPTIONS_CHAT_ID = getenv_int("EXCEPTIONS_CHAT_ID")

ORDERS_COUNT = getenv_int("ORDERS_COUNT")
ORDERS_LIMIT_HOURS = getenv_int("ORDERS_LIMIT_HOURS")
ORDERS_LIMIT_COUNT = getenv_int("ORDERS_LIMIT_COUNT")

ESCROW_ENABLED = getenv_bool("ESCROW_ENABLED")
WIF_FILENAME = getenv("WIF_FILENAME")
class Config:
"""Data holder for configuration values."""

TOKEN_FILENAME: str
INTERNAL_HOST: str = "127.0.0.1"
SERVER_HOST: str
SERVER_PORT: int
WEBHOOK_PATH: str
DATABASE_NAME: str = "tellerbot"
DATABASE_HOST: str = "127.0.0.1"
DATABASE_USERNAME: str
DATABASE_PASSWORD_FILENAME: str

LOGGER_LEVEL: str
LOG_FILENAME: str

SUPPORT_CHAT_ID: int
EXCEPTIONS_CHAT_ID: int

ORDERS_COUNT: int
ORDERS_LIMIT_HOURS: int
ORDERS_LIMIT_COUNT: int

ESCROW_ENABLED: bool
WIF_FILENAME: str
OP_CHECK_TIMEOUT_HOURS: int


for name, annotation in Config.__annotations__.items():
if annotation == int:
value = getenv_int(name)
elif annotation == bool:
value = getenv_bool(name)
else:
value = getenv(name)
if value:
setattr(Config, name, value)
16 changes: 8 additions & 8 deletions src/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@
from aiogram.dispatcher.storage import BaseStorage
from motor.motor_asyncio import AsyncIOMotorClient

from src import config
from src.config import Config


if config.DATABASE_USERNAME and config.DATABASE_PASSWORD_FILENAME:
with open(config.DATABASE_PASSWORD_FILENAME, "r") as password_file:
try:
with open(Config.DATABASE_PASSWORD_FILENAME, "r") as password_file:
client = AsyncIOMotorClient(
config.DATABASE_HOST,
username=config.DATABASE_USERNAME,
Config.DATABASE_HOST,
username=Config.DATABASE_USERNAME,
password=password_file.read(),
)
else:
client = AsyncIOMotorClient(config.DATABASE_HOST)
database = client[config.DATABASE_NAME]
except (AttributeError, FileNotFoundError):
client = AsyncIOMotorClient(Config.DATABASE_HOST)
database = client[Config.DATABASE_NAME]

STATE_KEY = "state"

Expand Down
4 changes: 2 additions & 2 deletions src/escrow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with TellerBot. If not, see <https://www.gnu.org/licenses/>.
from src import config
from src.config import Config


if config.ESCROW_ENABLED:
if Config.ESCROW_ENABLED:
from src.escrow.blockchain.golos_blockchain import GolosBlockchain

SUPPORTED_BLOCKCHAINS = [GolosBlockchain()]
Expand Down
2 changes: 2 additions & 0 deletions src/escrow/blockchain/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ async def check_transaction(
amount_without_fee: Decimal,
asset: str,
memo: str,
transaction_time: float,
):
"""Add transaction in ``self._queue`` to be checked."""
self._queue.append(
Expand All @@ -120,6 +121,7 @@ async def check_transaction(
"amount_without_fee": amount_without_fee,
"asset": asset,
"memo": memo,
"transaction_time": transaction_time,
}
)
# Start streaming if not already streaming
Expand Down
9 changes: 3 additions & 6 deletions src/escrow/blockchain/golos_blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from golos.exceptions import TransactionNotFound
from golos.ws_client import error_handler

from src import config
from src.config import Config
from src.database import database
from src.escrow.blockchain import BaseBlockchain
from src.escrow.blockchain import BlockchainConnectionError
Expand Down Expand Up @@ -115,10 +115,7 @@ async def get_limits(self, asset: str):
return limits.get(asset)

async def transfer(self, to: str, amount: Decimal, asset: str):
if not config.WIF_FILENAME:
raise Exception("WIF_FILENAME is not set")

with open(config.WIF_FILENAME) as wif_file:
with open(Config.WIF_FILENAME) as wif_file:
transaction = await get_running_loop().run_in_executor(
None,
self._golos.transfer,
Expand Down Expand Up @@ -201,7 +198,7 @@ async def _check_operation(
op_amount, asset = op["amount"].split()
amount = Decimal(op_amount)
for req in queue:
if "transaction_time" in req and "timestamp" in op:
if "timestamp" in op:
date = datetime.strptime(op["timestamp"], "%Y-%m-%dT%H:%M:%S")
if timegm(date.timetuple()) < req["transaction_time"]:
continue
Expand Down
4 changes: 2 additions & 2 deletions src/handlers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

from src.bot import dp
from src.bot import tg
from src.config import EXCEPTIONS_CHAT_ID
from src.config import Config
from src.handlers import start_menu # noqa: F401, noreorder
from src.handlers import creation # noqa: F401
from src.handlers import escrow # noqa: F401
Expand Down Expand Up @@ -84,7 +84,7 @@ async def errors_handler(update: types.Update, exception: Exception):

if chat_id is not None:
await tg.send_message(
EXCEPTIONS_CHAT_ID,
Config.EXCEPTIONS_CHAT_ID,
"Error handling {} {} from {} ({}) in chat {}\n{}".format(
update_type,
update.update_id,
Expand Down
16 changes: 8 additions & 8 deletions src/handlers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from aiogram.utils.emoji import emojize
from pymongo.cursor import Cursor

from src import config
from src.config import Config

from src.bot import ( # noqa: F401, noreorder
dp,
Expand Down Expand Up @@ -97,19 +97,19 @@ async def orders_list(
:param message_id: Telegram ID of message to edit.
:param invert: Invert all prices.
"""
keyboard = types.InlineKeyboardMarkup(row_width=min(config.ORDERS_COUNT // 2, 8))
keyboard = types.InlineKeyboardMarkup(row_width=min(Config.ORDERS_COUNT // 2, 8))

inline_orders_buttons = (
types.InlineKeyboardButton(
emojize(":arrow_left:"),
callback_data="{} {} {}".format(
buttons_data, start - config.ORDERS_COUNT, int(invert)
buttons_data, start - Config.ORDERS_COUNT, int(invert)
),
),
types.InlineKeyboardButton(
emojize(":arrow_right:"),
callback_data="{} {} {}".format(
buttons_data, start + config.ORDERS_COUNT, int(invert)
buttons_data, start + Config.ORDERS_COUNT, int(invert)
),
),
)
Expand All @@ -123,7 +123,7 @@ async def orders_list(
await tg.edit_message_text(text, chat_id, message_id, reply_markup=keyboard)
return

all_orders = await cursor.to_list(length=start + config.ORDERS_COUNT)
all_orders = await cursor.to_list(length=start + Config.ORDERS_COUNT)
orders = all_orders[start:]

lines = []
Expand Down Expand Up @@ -179,7 +179,7 @@ async def orders_list(
types.InlineKeyboardButton(
_("Invert"),
callback_data="{} {} {}".format(
buttons_data, start - config.ORDERS_COUNT, int(not invert)
buttons_data, start - Config.ORDERS_COUNT, int(not invert)
),
)
)
Expand All @@ -189,8 +189,8 @@ async def orders_list(
text = (
"\\["
+ _("Page {} of {}").format(
math.ceil(start / config.ORDERS_COUNT) + 1,
math.ceil(quantity / config.ORDERS_COUNT),
math.ceil(start / Config.ORDERS_COUNT) + 1,
math.ceil(quantity / Config.ORDERS_COUNT),
)
+ "]\n"
+ "\n".join(lines)
Expand Down
4 changes: 2 additions & 2 deletions src/handlers/escrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from src import states
from src.bot import dp
from src.bot import tg
from src.config import SUPPORT_CHAT_ID
from src.config import Config
from src.database import database
from src.escrow import get_escrow_instance
from src.escrow import SUPPORTED_BANKS
Expand Down Expand Up @@ -876,7 +876,7 @@ async def validate_offer(call: types.CallbackQuery, offer: EscrowOffer):
"""Ask support for manual verification of exchange."""
escrow_instance = get_escrow_instance(offer[offer.type])
await tg.send_message(
SUPPORT_CHAT_ID,
Config.SUPPORT_CHAT_ID,
"Unconfirmed escrow.\nTransaction: {}\nMemo: {}".format(
escrow_instance.trx_url(offer.trx_id), markdown.code(offer.memo),
),
Expand Down
4 changes: 2 additions & 2 deletions src/handlers/order.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
from bson.objectid import ObjectId
from motor.core import AgnosticBaseCursor as Cursor

from src import config
from src import states
from src.bot import dp
from src.bot import tg
from src.config import Config
from src.database import database
from src.database import STATE_KEY
from src.escrow.escrow_offer import EscrowOffer
Expand Down Expand Up @@ -299,7 +299,7 @@ async def match_button(call: types.CallbackQuery, order: OrderType):
@order_handler
async def escrow_button(call: types.CallbackQuery, order: OrderType):
"""React to "Escrow" button by starting escrow exchange."""
if not config.ESCROW_ENABLED:
if not Config.ESCROW_ENABLED:
await call.answer(
_("Escrow is temporarily unavailable. Sorry for the inconvenience.")
)
Expand Down
9 changes: 4 additions & 5 deletions src/handlers/start_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@

from src import states
from src.bot import tg
from src.config import ORDERS_LIMIT_COUNT
from src.config import ORDERS_LIMIT_HOURS
from src.config import Config
from src.database import database
from src.handlers.base import help_message
from src.handlers.base import inline_control_buttons
Expand Down Expand Up @@ -79,14 +78,14 @@ async def handle_create(message: types.Message, state: FSMContext):
user_orders = await database.orders.count_documents(
{
"user_id": message.from_user.id,
"start_time": {"$gt": current_time - ORDERS_LIMIT_HOURS * 3600},
"start_time": {"$gt": current_time - Config.ORDERS_LIMIT_HOURS * 3600},
}
)
if user_orders >= ORDERS_LIMIT_COUNT:
if user_orders >= Config.ORDERS_LIMIT_COUNT:
await tg.send_message(
message.chat.id,
_("You can't create more than {} orders in {} hours.").format(
ORDERS_LIMIT_COUNT, ORDERS_LIMIT_HOURS
Config.ORDERS_LIMIT_COUNT, Config.ORDERS_LIMIT_HOURS
),
)
return
Expand Down

0 comments on commit 71e5238

Please sign in to comment.