Add multi-env support
This commit is contained in:
parent
26f23a1354
commit
37ac7dbb0c
4 changed files with 147 additions and 12 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -181,5 +181,6 @@ cython_debug/
|
||||||
.cursorindexingignore
|
.cursorindexingignore
|
||||||
|
|
||||||
# Custom stuff
|
# Custom stuff
|
||||||
gacha_game.db
|
gacha_game*.db
|
||||||
config.ini
|
gacha_game*.db.*
|
||||||
|
config*.ini
|
||||||
|
|
|
@ -1,7 +1,26 @@
|
||||||
'''Essentials for the bot to function'''
|
'''Essentials for the bot to function'''
|
||||||
import configparser
|
import configparser
|
||||||
|
from os import environ, path
|
||||||
|
|
||||||
|
class ConfigError(Exception):
|
||||||
|
'''Could not find config file'''
|
||||||
|
|
||||||
|
def get_config_file() -> str:
|
||||||
|
'''Gets the path to the config file in the current environment'''
|
||||||
|
env: str | None = environ.get('KEMOVERSE_ENV')
|
||||||
|
if not env:
|
||||||
|
raise ConfigError('Error: KEMOVERSE_ENV is unset')
|
||||||
|
if not (env in ['prod', 'dev']):
|
||||||
|
raise ConfigError(f'Error: Invalid environment: {env}')
|
||||||
|
|
||||||
|
config_path: str = f'config_{env}.ini'
|
||||||
|
|
||||||
|
if not path.isfile(config_path):
|
||||||
|
raise ConfigError(f'Could not find {config_path}')
|
||||||
|
return config_path
|
||||||
|
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
config.read('config.ini')
|
config.read(get_config_file())
|
||||||
|
|
||||||
# Username for the bot
|
# Username for the bot
|
||||||
USER = config['credentials']['User']
|
USER = config['credentials']['User']
|
||||||
|
|
99
readme.md
99
readme.md
|
@ -1,6 +1,10 @@
|
||||||
# Kemoverse
|
# Kemoverse
|
||||||
|
|
||||||
A gacha-style bot for the Fediverse built with Python. Users can roll for characters, trade, duel, and perhaps engage with popularity-based mechanics. Currently designed for use with Misskey. Name comes from Kemonomimi and Fediverse.
|
A gacha-style bot for the Fediverse built with Python. Users can roll for characters, trade, duel, and perhaps engage with popularity-based mechanics. Currently designed for use with Misskey. Name comes from Kemonomimi and Fediverse.
|
||||||
|
=======
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -11,18 +15,23 @@ A gacha-style bot for the Fediverse built with Python. Users can roll for charac
|
||||||
- 🎴 Cards stats system
|
- 🎴 Cards stats system
|
||||||
- 🧠 Core database structure for characters and stats
|
- 🧠 Core database structure for characters and stats
|
||||||
- 📦 Basic support for storing pulls per user
|
- 📦 Basic support for storing pulls per user
|
||||||
|
- ⏱️ Time-based limitations on rolls
|
||||||
|
|
||||||
### 🧩 In Progress
|
### 🧩 In Progress
|
||||||
- 📝 Whitelist system to limit access
|
- 📝 Whitelist system to limit access
|
||||||
- ⏱️ Time-based limitations on rolls
|
- ⚠️ Explicit account creation/deletion
|
||||||
- ⚔️ Dueling system
|
|
||||||
|
|
||||||
## 🧠 Planned Features (Long Term)
|
## 🧠 Roadmap
|
||||||
|
|
||||||
|
[See our v2.0 board for more details](https://git.waifuism.life/waifu/kemoverse/projects/3)
|
||||||
|
|
||||||
### 🛒 Gameplay & Collection
|
### 🛒 Gameplay & Collection
|
||||||
- 🔁 **Trading system** between users
|
- 🔁 **Trading system** between users
|
||||||
- ⭐ **Favorite characters** (pin them or set profiles)
|
- ⭐ **Favorite characters** (pin them or set profiles)
|
||||||
- 📢 **Public post announcements** for rare card pulls
|
- 📢 **Public post announcements** for rare card pulls
|
||||||
|
- 📊 **Stats** for cards
|
||||||
|
- 🎮 **Games** to play
|
||||||
|
- ⚔️ Dueling
|
||||||
- 🧮 **Leaderboards**
|
- 🧮 **Leaderboards**
|
||||||
- Most traded Characters
|
- Most traded Characters
|
||||||
- Most owned Characters
|
- Most owned Characters
|
||||||
|
@ -39,7 +48,7 @@ A gacha-style bot for the Fediverse built with Python. Users can roll for charac
|
||||||
|
|
||||||
## 🗃️ Tech Stack
|
## 🗃️ Tech Stack
|
||||||
|
|
||||||
- Python (3.11+)
|
- Python (3.12+)
|
||||||
- SQLite
|
- SQLite
|
||||||
- Fediverse API integration (via Misskey endpoints)
|
- Fediverse API integration (via Misskey endpoints)
|
||||||
- Flask
|
- Flask
|
||||||
|
@ -49,10 +58,88 @@ A gacha-style bot for the Fediverse built with Python. Users can roll for charac
|
||||||
|
|
||||||
The bot is meant to feel *light, fun, and competitive*. Mixing social, gacha and duel tactics.
|
The bot is meant to feel *light, fun, and competitive*. Mixing social, gacha and duel tactics.
|
||||||
|
|
||||||
## 🧪 Getting Started (coming soon)
|
## 🧪 Installation
|
||||||
|
|
||||||
Instructions on installing dependencies, initializing the database, and running the bot locally will go here.
|
1. Download and install dependencies
|
||||||
|
|
||||||
|
Clone the repo
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://git.waifuism.life/waifu/kemoverse.git
|
||||||
|
cd kemoverse
|
||||||
|
```
|
||||||
|
|
||||||
|
Setup a virtual environment (Optional, recommended)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
```
|
||||||
|
|
||||||
|
Install project dependencies via pip
|
||||||
|
|
||||||
|
```sh
|
||||||
|
python3 -m pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Setup config file
|
||||||
|
|
||||||
|
A sample config file is included with the project as a template: `example_config.ini`
|
||||||
|
|
||||||
|
Create a copy of this file and replace its' values with your own. Consult the
|
||||||
|
template for more information about individual config values and their meaning.
|
||||||
|
|
||||||
|
Config files are environment-specific. Use `config_dev.ini` for development and
|
||||||
|
`config_prod.ini` for production. Switch between environments using the
|
||||||
|
`KEMOVERSE_ENV` environment variable.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cp example_config.ini config_dev.ini
|
||||||
|
# Edit config_dev.ini
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Setup database
|
||||||
|
|
||||||
|
To set up the database, run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
KEMOVERSE_ENV=dev python3 setup_db.py
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Run the bot
|
||||||
|
|
||||||
|
```sh
|
||||||
|
KEMOVERSE_ENV=dev ./startup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
If all goes well, you should now be able to interact with the bot.
|
||||||
|
|
||||||
|
6. Running in production
|
||||||
|
|
||||||
|
To run the the in a production environment, use `KEMOVERSE_ENV=prod`. You will
|
||||||
|
also need to create a `config_prod.ini` file and run the database setup step
|
||||||
|
again if pointing prod to a different database. (you are pointing dev and prod
|
||||||
|
to different databases, right? 🤨)
|
||||||
|
|
||||||
|
7. Updating
|
||||||
|
|
||||||
|
To update the bot, first pull new changes from upstream:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git pull
|
||||||
|
```
|
||||||
|
|
||||||
|
Then run any database migrations. We recommend testing in dev beforehand to
|
||||||
|
make sure nothing breaks in the update process.
|
||||||
|
|
||||||
|
**Always backup your prod database before running any migrations!**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Backup database file
|
||||||
|
cp gacha_game_dev.db gacha_game_dev.db.bak
|
||||||
|
# Run migrations
|
||||||
|
KEMOVERSE_ENV=dev python3 setup_db.py
|
||||||
|
```
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart TD
|
flowchart TD
|
||||||
|
|
32
setup_db.py
32
setup_db.py
|
@ -11,6 +11,12 @@ class DBNotFoundError(Exception):
|
||||||
class InvalidMigrationError(Exception):
|
class InvalidMigrationError(Exception):
|
||||||
'''Migration file has an invalid name'''
|
'''Migration file has an invalid name'''
|
||||||
|
|
||||||
|
class KemoverseEnvUnset(Exception):
|
||||||
|
'''KEMOVERSE_ENV is not set or has an invalid value'''
|
||||||
|
|
||||||
|
class ConfigError(Exception):
|
||||||
|
'''Could not find the config file for the current environment'''
|
||||||
|
|
||||||
def get_migrations() -> List[Tuple[int, str]] | InvalidMigrationError:
|
def get_migrations() -> List[Tuple[int, str]] | InvalidMigrationError:
|
||||||
'''Returns a list of migration files in numeric order.'''
|
'''Returns a list of migration files in numeric order.'''
|
||||||
# Store transaction id and filename separately
|
# Store transaction id and filename separately
|
||||||
|
@ -50,11 +56,22 @@ def perform_migration(cursor: sqlite3.Cursor, migration: tuple[int, str]) -> Non
|
||||||
|
|
||||||
def get_db_path() -> str | DBNotFoundError:
|
def get_db_path() -> str | DBNotFoundError:
|
||||||
'''Gets the DB path from config.ini'''
|
'''Gets the DB path from config.ini'''
|
||||||
|
env = os.environ.get('KEMOVERSE_ENV')
|
||||||
|
if not (env and env in ['prod', 'dev']):
|
||||||
|
raise KemoverseEnvUnset
|
||||||
|
|
||||||
|
print(f'Running in "{env}" mode')
|
||||||
|
|
||||||
|
config_path = f'config_{env}.ini'
|
||||||
|
|
||||||
|
if not os.path.isfile(config_path):
|
||||||
|
raise ConfigError(f'Could not find {config_path}')
|
||||||
|
|
||||||
config = ConfigParser()
|
config = ConfigParser()
|
||||||
config.read('config.ini')
|
config.read(config_path)
|
||||||
db_path = config['application']['DatabaseLocation']
|
db_path = config['application']['DatabaseLocation']
|
||||||
if not db_path:
|
if not db_path:
|
||||||
raise DBNotFoundError
|
raise DBNotFoundError()
|
||||||
return db_path
|
return db_path
|
||||||
|
|
||||||
def get_current_migration(cursor: sqlite3.Cursor) -> int:
|
def get_current_migration(cursor: sqlite3.Cursor) -> int:
|
||||||
|
@ -71,7 +88,18 @@ def get_current_migration(cursor: sqlite3.Cursor) -> int:
|
||||||
def main():
|
def main():
|
||||||
'''Does the thing'''
|
'''Does the thing'''
|
||||||
# Connect to the DB
|
# Connect to the DB
|
||||||
|
db_path = ''
|
||||||
|
try:
|
||||||
db_path = get_db_path()
|
db_path = get_db_path()
|
||||||
|
except ConfigError as ex:
|
||||||
|
print(ex)
|
||||||
|
return
|
||||||
|
except KemoverseEnvUnset:
|
||||||
|
print('Error: KEMOVERSE_ENV is either not set or has an invalid value.')
|
||||||
|
print('Please set KEMOVERSE_ENV to either "dev" or "prod" before running.')
|
||||||
|
print(traceback.format_exc())
|
||||||
|
return
|
||||||
|
|
||||||
conn = sqlite3.connect(db_path, autocommit=False)
|
conn = sqlite3.connect(db_path, autocommit=False)
|
||||||
conn.row_factory = sqlite3.Row
|
conn.row_factory = sqlite3.Row
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
Loading…
Add table
Reference in a new issue