Additional loading functions.
This commit is contained in:
@@ -8,31 +8,31 @@ except ImportError:
|
||||
|
||||
|
||||
class Access:
|
||||
def __init__(self, connection):
|
||||
self.host = connection.get('host')
|
||||
self.port = connection.get('port')
|
||||
self.buffer = connection.get('buffer_size')
|
||||
self.auth_key = connection.get('auth_key')
|
||||
self.socket = socket.socket()
|
||||
def __init__(self, conn_dict):
|
||||
self.host = conn_dict.get('host')
|
||||
self.port = conn_dict.get('port')
|
||||
self.buffer = conn_dict.get('buffer_size')
|
||||
self.auth_token = conn_dict.get('auth_token')
|
||||
|
||||
def send_request(self, action: str, *args):
|
||||
request = {'auth_key': self.auth_key,
|
||||
request = {'auth_token': self.auth_token,
|
||||
'action': action,
|
||||
'args': args}
|
||||
request = pickle.dumps(request)
|
||||
soc = socket.socket()
|
||||
try:
|
||||
self.socket.connect((self.host, self.port))
|
||||
util.send_msg(self.socket, request)
|
||||
response = util.recv_msg(self.socket)
|
||||
response = pickle.loads(response)
|
||||
if not response.get('success'):
|
||||
raise Exception(response.get('message'))
|
||||
soc.connect((self.host, self.port))
|
||||
util.send_msg(soc, request)
|
||||
message = util.recv_msg(soc)
|
||||
message = pickle.loads(message)
|
||||
if not message.get('success'):
|
||||
raise Exception(message.get('message'))
|
||||
finally:
|
||||
self.socket.close()
|
||||
return response.get('data')
|
||||
soc.close()
|
||||
return message.get('data')
|
||||
|
||||
if __name__ == '__main__':
|
||||
access = Access({'host': 'europa', 'port': 12345, 'buffer_size': 1024, 'auth_key': 'a'})
|
||||
access = Access({'host': 'europa', 'port': 12345, 'buffer_size': 1024, 'auth_token': 'a'})
|
||||
action = 'load_seasons'
|
||||
response = access.send_request(action)
|
||||
pp = pprint.PrettyPrinter(indent=1)
|
||||
|
||||
@@ -5,7 +5,7 @@ import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from dsst_gtk3.handlers import handlers
|
||||
from dsst_gtk3 import util, reload
|
||||
from dsst_gtk3 import util, reload, client
|
||||
import sql_func
|
||||
import sql
|
||||
|
||||
@@ -26,27 +26,41 @@ class GtkUi:
|
||||
self.ui.connect_signals(self.handlers)
|
||||
# Show all widgets
|
||||
self.ui.get_object('main_window').show_all()
|
||||
db_config = config['sql_connections'][0]
|
||||
# Initialize the database
|
||||
sql.db.init(db_config['db_name'], host=db_config['host'], port=db_config['port'],
|
||||
user=db_config['user'], password=db_config['password'])
|
||||
# Show database info in status bar
|
||||
self.set_db_status_label(db_config)
|
||||
# Create database if not exists
|
||||
sql_func.create_tables()
|
||||
self.reload()
|
||||
# Connect to data server
|
||||
config = config['servers'][0]
|
||||
self.data_client = client.Access(config)
|
||||
self.data = {}
|
||||
# Load base data and seasons
|
||||
self.initial_load()
|
||||
|
||||
def initial_load(self):
|
||||
with util.handle_exception(Exception):
|
||||
self.data['players'] = self.data_client.send_request('load_players')
|
||||
self.data['drinks'] = self.data_client.send_request('load_drinks')
|
||||
self.data['seasons'] = self.data_client.send_request('load_seasons')
|
||||
reload.reload_base_data(self.ui, self)
|
||||
|
||||
def reload(self):
|
||||
reload.reload_base_data(self.ui, self)
|
||||
season_id = self.get_selected_season_id()
|
||||
if season_id:
|
||||
reload.reload_episodes(self.ui, self, season_id)
|
||||
reload.reload_season_stats(self.ui, self, season_id)
|
||||
else:
|
||||
return
|
||||
episode_id = self.get_selected_episode_id()
|
||||
if episode_id:
|
||||
reload.reload_episode_stats(self.ui, self, episode_id)
|
||||
with util.handle_exception(Exception):
|
||||
self.data['episodes'] = self.data_client.send_request('load_episodes', self.get_selected_season_id())
|
||||
reload.reload_episodes(self.ui, self)
|
||||
pass
|
||||
# reload.reload_base_data(self.ui, self)
|
||||
# season_id = self.get_selected_season_id()
|
||||
# if season_id:
|
||||
# reload.reload_episodes(self.ui, self, season_id)
|
||||
# reload.reload_season_stats(self.ui, self, season_id)
|
||||
# else:
|
||||
# return
|
||||
# episode_id = self.get_selected_episode_id()
|
||||
# if episode_id:
|
||||
# reload.reload_episode_stats(self.ui, self, episode_id)
|
||||
|
||||
def load(self, data_dict: dict, value_field: str, request_name: str):
|
||||
try:
|
||||
data_dict[value_field] = self.data_client.send_request('request_name')
|
||||
except Exception as e:
|
||||
print()
|
||||
|
||||
def set_db_status_label(self, db_conf: dict):
|
||||
self.ui.get_object('connection_label').set_text(f'{db_conf["user"]}@{db_conf["host"]}')
|
||||
|
||||
@@ -29,7 +29,6 @@ class Handlers(SeasonHandlers, BaseDataHandlers, DialogHandlers, DeathHandlers,
|
||||
""" Signal will be sent when app should close
|
||||
:param _: Arguments to the delete event
|
||||
"""
|
||||
sql.db.close()
|
||||
Gtk.main_quit()
|
||||
|
||||
# DEBUG Functions ##################################################################################################
|
||||
|
||||
@@ -3,21 +3,21 @@ from collections import Counter
|
||||
from gi.repository import Gtk
|
||||
|
||||
from data_access import sql, sql_func
|
||||
from dsst_gtk3 import util
|
||||
from dsst_gtk3 import util, gtk_ui
|
||||
|
||||
|
||||
def reload_base_data(builder: Gtk.Builder, app: 'gtk_ui.GtkUi'):
|
||||
def reload_base_data(builder: Gtk.Builder, app: 'gtk_ui.GtkUi',):
|
||||
"""Reload function for all base data witch is not dependant on a selected season or episode
|
||||
:param app: GtkUi instance
|
||||
:param builder: Gtk.Builder with loaded UI
|
||||
"""
|
||||
# Rebuild all players store
|
||||
builder.get_object('all_players_store').clear()
|
||||
for player in sql.Player.select():
|
||||
for player in app.data['players']:
|
||||
builder.get_object('all_players_store').append([player.id, player.name, player.hex_id])
|
||||
# Rebuild drink store
|
||||
builder.get_object('drink_store').clear()
|
||||
for drink in sql.Drink.select():
|
||||
for drink in app.data['drinks']:
|
||||
builder.get_object('drink_store').append([drink.id, drink.name, '{:.2f}%'.format(drink.vol)])
|
||||
# Rebuild seasons store
|
||||
combo = builder.get_object('season_combo_box') # type: Gtk.ComboBox
|
||||
@@ -25,23 +25,22 @@ def reload_base_data(builder: Gtk.Builder, app: 'gtk_ui.GtkUi'):
|
||||
with util.block_handler(combo, app.handlers.do_season_selected):
|
||||
store = builder.get_object('seasons_store')
|
||||
store.clear()
|
||||
for season in sql.Season.select().order_by(sql.Season.number):
|
||||
for season in app.data['seasons']:
|
||||
store.append([season.id, season.game_name])
|
||||
combo.set_active(active)
|
||||
|
||||
|
||||
def reload_episodes(builder: Gtk.Builder, app: 'gtk_ui.GtkUi', season_id: int):
|
||||
def reload_episodes(builder: Gtk.Builder, app: 'gtk_ui.GtkUi'):
|
||||
"""Reload all data that is dependant on a selected season
|
||||
:param app: GtkUi instance
|
||||
:param builder: Gtk.Builder with loaded UI
|
||||
:param season_id: ID of the season for witch to load data
|
||||
"""
|
||||
# Rebuild episodes store
|
||||
selection = builder.get_object('episodes_tree_view').get_selection()
|
||||
with util.block_handler(selection, app.handlers.on_selected_episode_changed):
|
||||
model, selected_paths = selection.get_selected_rows()
|
||||
model.clear()
|
||||
for episode in sql_func.get_episodes_for_season(season_id):
|
||||
for episode in app.data['episodes']:
|
||||
model.append([episode.id, episode.name, str(episode.date), episode.number])
|
||||
if selected_paths:
|
||||
selection.select_path(selected_paths[0])
|
||||
|
||||
@@ -5,18 +5,17 @@ import json
|
||||
import os
|
||||
from contextlib import contextmanager
|
||||
from gi.repository import Gtk
|
||||
from typing import Callable
|
||||
from typing import Callable, Type
|
||||
from zipfile import ZipFile
|
||||
|
||||
CONFIG_PATH = os.path.join(os.path.expanduser('~'), '.config', 'dsst', 'config.json')
|
||||
DEFAULT_CONFIG = {
|
||||
'auto_connect': False,
|
||||
'sql_connections': [{
|
||||
'servers': [{
|
||||
'host': 'localhost',
|
||||
'port': 3306,
|
||||
'db_name': 'dsst',
|
||||
'user': 'dsst',
|
||||
'password': 'dsst'}
|
||||
'port': 12345,
|
||||
'buffer_size': 1024,
|
||||
'auth_token': 'a'}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -32,6 +31,17 @@ def block_handler(widget: 'Gtk.Widget', handler_func: Callable):
|
||||
widget.handler_unblock_by_func(handler_func)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def handle_exception(exception: 'Type[Exception]'):
|
||||
"""Run operation in try/except block and display exception in a dialog
|
||||
:param exception:
|
||||
"""
|
||||
try:
|
||||
yield
|
||||
except exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def get_combo_value(combo, index: int):
|
||||
""" Retrieve the selected value of a combo box at the selected index in the model
|
||||
:param combo: Any Gtk Widget that supports 'get_active_iter()'
|
||||
|
||||
@@ -10,20 +10,46 @@ def map_base_fields(cls, db_model):
|
||||
return model
|
||||
|
||||
|
||||
def db_to_drink(drink: 'sql.Drink'):
|
||||
return map_base_fields(models.Drink, drink)
|
||||
|
||||
|
||||
def db_to_enemy(enemy: 'sql.Enemy'):
|
||||
return map_base_fields(models.Enemy, enemy)
|
||||
|
||||
|
||||
def db_to_player(player: 'sql.Player'):
|
||||
model = map_base_fields(models.Player, player)
|
||||
return map_base_fields(models.Player, player)
|
||||
|
||||
|
||||
def db_to_penalty(penalty: 'sql.Penalty'):
|
||||
model = map_base_fields(models.Penalty, penalty)
|
||||
model.drink = db_to_drink(penalty.drink)
|
||||
model.player = db_to_player(penalty.player)
|
||||
return model
|
||||
|
||||
|
||||
def db_to_death(death: 'sql.Death'):
|
||||
model = map_base_fields(models.Death, death)
|
||||
model.player = db_to_player(death.player)
|
||||
model.enemy = db_to_enemy(death.enemy)
|
||||
model.penalties = [db_to_penalty(penalty) for penalty in death.penalties]
|
||||
return model
|
||||
|
||||
|
||||
def db_to_victory(victory: 'sql.Victory'):
|
||||
model = map_base_fields(models.Victory, victory)
|
||||
model.player = db_to_player(victory.player)
|
||||
model.enemy = db_to_enemy(victory.enemy)
|
||||
return model
|
||||
|
||||
|
||||
def db_to_episode(episode: 'sql.Episode'):
|
||||
model = map_base_fields(models.Episode, episode)
|
||||
model.players = [db_to_player(player) for player in episode.players]
|
||||
model.deaths = []
|
||||
model.victories = []
|
||||
model.deaths = [db_to_death(death) for death in episode.deaths]
|
||||
model.victories = [db_to_victory(victory) for victory in episode.victories]
|
||||
return model
|
||||
|
||||
|
||||
def db_to_season(season: 'sql.Season'):
|
||||
|
||||
@@ -13,7 +13,16 @@ class ReadFunctions:
|
||||
def load_seasons_all(*_):
|
||||
return [shortcuts.model_to_dict(season, backrefs=True, max_depth=2) for season in sql.Season.select()]
|
||||
|
||||
@staticmethod
|
||||
def load_episodes(season_id, *_):
|
||||
if not season_id:
|
||||
raise Exception('Exception: Missing argument (season_id)')
|
||||
return [mapping.db_to_episode(ep) for ep in sql.Season.get(sql.Season.id == season_id).episodes]
|
||||
|
||||
@staticmethod
|
||||
def load_players(*_):
|
||||
return [mapping.db_to_player(player) for player in sql.Player.select()]
|
||||
|
||||
@staticmethod
|
||||
def load_drinks(*_):
|
||||
return [mapping.db_to_drink(drink) for drink in sql.Drink.select()]
|
||||
@@ -6,7 +6,7 @@ import sys
|
||||
import os
|
||||
|
||||
from common import util, models
|
||||
from dsst_server import read_functions, write_functions
|
||||
from dsst_server import read_functions, write_functions, tokens
|
||||
from dsst_server.func_proxy import FunctionProxy
|
||||
from dsst_server.data_access import sql
|
||||
|
||||
@@ -23,12 +23,19 @@ class DsstServer:
|
||||
self.socket_server.bind((HOST, PORT))
|
||||
print(f'Bound socket to {PORT} on host {HOST}')
|
||||
|
||||
self.read_actions = util.list_class_methods(read_functions.ReadFunctions)
|
||||
self.write_actions = util.list_class_methods(write_functions.WriteFunctions)
|
||||
# Initialize database
|
||||
sql.db.init('dsst', user='dsst', password='dsst')
|
||||
print(f'Database initialized ({sql.db.database})')
|
||||
|
||||
self.key_access = {'a': self.read_actions,
|
||||
'b': self.read_actions + self.write_actions}
|
||||
# Load access tokens and map them to their allowed methods
|
||||
read_actions = util.list_class_methods(read_functions.ReadFunctions)
|
||||
write_actions = util.list_class_methods(write_functions.WriteFunctions)
|
||||
parm_access = {
|
||||
'r': read_actions,
|
||||
'rw': read_actions + write_actions
|
||||
}
|
||||
self.tokens = {token: parm_access[perms] for token, perms in tokens.TOKENS}
|
||||
print(f'Loaded auth tokens: {self.tokens.keys()}')
|
||||
|
||||
def run(self):
|
||||
self.socket_server.listen(5)
|
||||
@@ -41,17 +48,22 @@ class DsstServer:
|
||||
data = util.recv_msg(client)
|
||||
request = pickle.loads(data)
|
||||
print(f'Request: {request}')
|
||||
# Validate auth key in request
|
||||
key = request.get('auth_key')
|
||||
if key not in self.key_access:
|
||||
util.send_msg(client, pickle.dumps({'success': False, 'message': 'Auth Key invalid'}))
|
||||
print(f'Rejected request from {address}. Auth key invalid ({key})')
|
||||
# Validate auth token in request
|
||||
token = request.get('auth_token')
|
||||
if token not in self.tokens:
|
||||
util.send_msg(client, pickle.dumps({'success': False, 'message': 'Auth token invalid'}))
|
||||
print(f'Rejected request from {address}. Auth token invalid ({token})')
|
||||
continue
|
||||
# Check read functions
|
||||
action_name = request.get('action')
|
||||
if action_name in self.key_access[key]:
|
||||
if action_name in self.tokens[token]:
|
||||
action = getattr(FunctionProxy, action_name)
|
||||
try:
|
||||
value = action(request.get('args'))
|
||||
except Exception as e:
|
||||
response = {'success': False, 'message': f'Exception was thrown on server.\n{e}'}
|
||||
util.send_msg(client, pickle.dumps(response))
|
||||
raise
|
||||
response = {'success': True, 'data': value}
|
||||
util.send_msg(client, pickle.dumps(response))
|
||||
continue
|
||||
|
||||
5
dsst/dsst_server/tokens.py
Normal file
5
dsst/dsst_server/tokens.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# Define access tokens here
|
||||
# i.E: { 'read': ['a', 'b''],
|
||||
# 'write': ['a']
|
||||
# }
|
||||
TOKENS = [('a', 'rw'), ('b', 'r')]
|
||||
Reference in New Issue
Block a user