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