1
0
mirror of synced 2025-01-18 22:24:04 +01:00

Make Config a real class instead of a Dict, for safer access and defaults.

This commit is contained in:
Jennifer Taylor 2021-08-20 04:43:59 +00:00
parent 628828ed12
commit 40dbf1d6b9
58 changed files with 544 additions and 351 deletions

View File

@ -9,12 +9,12 @@ from bemani.api.exceptions import APIException
from bemani.api.objects import RecordsObject, ProfileObject, StatisticsObject, CatalogObject from bemani.api.objects import RecordsObject, ProfileObject, StatisticsObject, CatalogObject
from bemani.api.types import g from bemani.api.types import g
from bemani.common import GameConstants, APIConstants, VersionConstants from bemani.common import GameConstants, APIConstants, VersionConstants
from bemani.data import Data from bemani.data import Config, Data
app = Flask( app = Flask(
__name__ __name__
) )
config: Dict[str, Any] = {} config = Config()
SUPPORTED_VERSIONS = ['v1'] SUPPORTED_VERSIONS = ['v1']
@ -172,8 +172,8 @@ def info() -> Dict[str, Any]:
return { return {
'versions': SUPPORTED_VERSIONS, 'versions': SUPPORTED_VERSIONS,
'name': g.config.get('name', 'e-AMUSEMENT Network'), 'name': g.config.name,
'email': g.config.get('email', 'nobody@nowhere.com'), 'email': g.config.email,
} }
@ -209,7 +209,7 @@ def lookup(protoversion: str, requestgame: str, requestversion: str) -> Dict[str
('reflecbeat', GameConstants.REFLEC_BEAT), ('reflecbeat', GameConstants.REFLEC_BEAT),
('soundvoltex', GameConstants.SDVX), ('soundvoltex', GameConstants.SDVX),
]: ]:
if constant in g.config['support']: if constant in g.config.support:
gamemapping[gameid] = constant gamemapping[gameid] = constant
game = gamemapping.get(requestgame) game = gamemapping.get(requestgame)
if game is None: if game is None:

View File

@ -1,13 +1,13 @@
from typing import Any, Dict, TYPE_CHECKING from typing import TYPE_CHECKING
if TYPE_CHECKING: if TYPE_CHECKING:
from flask.ctx import _AppCtxGlobals from flask.ctx import _AppCtxGlobals
from bemani.data import Data from bemani.data import Config, Data
class RequestGlobals(_AppCtxGlobals): class RequestGlobals(_AppCtxGlobals):
config: Dict[str, Any] config: Config
data: Data data: Data
authorized: bool authorized: bool

View File

@ -3,7 +3,7 @@ import traceback
from typing import Any, Dict, Iterator, List, Optional, Set, Tuple, Type from typing import Any, Dict, Iterator, List, Optional, Set, Tuple, Type
from bemani.common import Model, ValidatedDict, Profile, GameConstants, Time from bemani.common import Model, ValidatedDict, Profile, GameConstants, Time
from bemani.data import Data, UserID, RemoteUser from bemani.data import Config, Data, UserID, RemoteUser
class ProfileCreationException(Exception): class ProfileCreationException(Exception):
@ -41,7 +41,7 @@ class Factory:
raise Exception('Override this in subclass!') raise Exception('Override this in subclass!')
@classmethod @classmethod
def run_scheduled_work(cls, data: Data, config: Dict[str, Any]) -> None: def run_scheduled_work(cls, data: Data, config: Config) -> None:
""" """
Subclasses of this class should use this function to run any scheduled Subclasses of this class should use this function to run any scheduled
work on classes which it is a factory for. This is usually used for work on classes which it is a factory for. This is usually used for
@ -84,7 +84,7 @@ class Factory:
yield (game.game, game.version, game.get_settings()) yield (game.game, game.version, game.get_settings())
@classmethod @classmethod
def create(cls, data: Data, config: Dict[str, Any], model: Model, parentmodel: Optional[Model]=None) -> Optional['Base']: def create(cls, data: Data, config: Config, model: Model, parentmodel: Optional[Model]=None) -> Optional['Base']:
""" """
Given a modelstring and an optional parent model, return an instantiated game class that can handle a packet. Given a modelstring and an optional parent model, return an instantiated game class that can handle a packet.
@ -129,13 +129,13 @@ class Base(ABC):
""" """
name: str name: str
def __init__(self, data: Data, config: Dict[str, Any], model: Model) -> None: def __init__(self, data: Data, config: Config, model: Model) -> None:
self.data = data self.data = data
self.config = config self.config = config
self.model = model self.model = model
@classmethod @classmethod
def create(cls, data: Data, config: Dict[str, Any], model: Model, parentmodel: Optional[Model]=None) -> Optional['Base']: def create(cls, data: Data, config: Config, model: Model, parentmodel: Optional[Model]=None) -> Optional['Base']:
""" """
Given a modelstring and an optional parent model, return an instantiated game class that can handle a packet. Given a modelstring and an optional parent model, return an instantiated game class that can handle a packet.
@ -179,7 +179,7 @@ class Base(ABC):
cls.__registered_handlers.add(handler) cls.__registered_handlers.add(handler)
@classmethod @classmethod
def run_scheduled_work(cls, data: Data, config: Dict[str, Any]) -> List[Tuple[str, Dict[str, Any]]]: def run_scheduled_work(cls, data: Data, config: Config) -> List[Tuple[str, Dict[str, Any]]]:
""" """
Run any out-of-band scheduled work that is applicable to this game. Run any out-of-band scheduled work that is applicable to this game.
""" """
@ -387,23 +387,23 @@ class Base(ABC):
self.data.local.game.put_settings(self.game, userid, settings) self.data.local.game.put_settings(self.game, userid, settings)
def get_machine_id(self) -> int: def get_machine_id(self) -> int:
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
return machine.id return machine.id
def update_machine_name(self, newname: Optional[str]) -> None: def update_machine_name(self, newname: Optional[str]) -> None:
if newname is None: if newname is None:
return return
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
machine.name = newname machine.name = newname
self.data.local.machine.put_machine(machine) self.data.local.machine.put_machine(machine)
def update_machine_data(self, newdata: Dict[str, Any]) -> None: def update_machine_data(self, newdata: Dict[str, Any]) -> None:
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
machine.data.update(newdata) machine.data.update(newdata)
self.data.local.machine.put_machine(machine) self.data.local.machine.put_machine(machine)
def get_game_config(self) -> ValidatedDict: def get_game_config(self) -> ValidatedDict:
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
settings = self.data.local.machine.get_settings(machine.arcade, self.game, self.version, 'game_config') settings = self.data.local.machine.get_settings(machine.arcade, self.game, self.version, 'game_config')
else: else:

View File

@ -1,9 +1,9 @@
from typing import Dict, Optional, Any from typing import Optional
from bemani.backend.base import Base, Factory from bemani.backend.base import Base, Factory
from bemani.backend.bishi.bishi import TheStarBishiBashi from bemani.backend.bishi.bishi import TheStarBishiBashi
from bemani.common import Model from bemani.common import Model
from bemani.data import Data from bemani.data import Config, Data
class BishiBashiFactory(Factory): class BishiBashiFactory(Factory):
@ -18,7 +18,7 @@ class BishiBashiFactory(Factory):
Base.register(gamecode, BishiBashiFactory) Base.register(gamecode, BishiBashiFactory)
@classmethod @classmethod
def create(cls, data: Data, config: Dict[str, Any], model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]: def create(cls, data: Data, config: Config, model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]:
if model.gamecode == 'IBB': if model.gamecode == 'IBB':
return TheStarBishiBashi(data, config, model) return TheStarBishiBashi(data, config, model)

View File

@ -49,7 +49,7 @@ class CardManagerHandler(Base):
expired = True expired = True
refid = self.data.local.user.get_refid(self.game, self.version, userid) refid = self.data.local.user.get_refid(self.game, self.version, userid)
paseli_enabled = self.supports_paseli() and self.config['paseli']['enabled'] paseli_enabled = self.supports_paseli() and self.config.paseli.enabled
root = Node.void('cardmng') root = Node.void('cardmng')
root.set_attribute('refid', refid) root.set_attribute('refid', refid)

View File

@ -22,7 +22,7 @@ class CoreHandler(Base):
node.set_attribute('url', url) node.set_attribute('url', url)
return node return node
url = f'{"https" if self.config["server"]["https"] else "http"}://{self.config["server"]["address"]}:{self.config["server"]["port"]}/' url = f'{"https" if self.config.server.https else "http"}://{self.config.server.address}:{self.config.server.port}/'
root = Node.void('services') root = Node.void('services')
root.set_attribute('expire', '600') root.set_attribute('expire', '600')
# This can be set to 'operation', 'debug', 'test', and 'factory'. # This can be set to 'operation', 'debug', 'test', and 'factory'.
@ -45,13 +45,9 @@ class CoreHandler(Base):
root.add_child(item(srv, url)) root.add_child(item(srv, url))
root.add_child(item('ntp', 'ntp://pool.ntp.org/')) root.add_child(item('ntp', 'ntp://pool.ntp.org/'))
# Look up keepalive override if exists, otherwise use the server address
if 'keepalive' in self.config['server']: # Translate keepalive to a raw IP because we can't give out a host here
keepalive = self.config['server']['keepalive'] keepalive = socket.gethostbyname(self.config.server.keepalive)
else:
keepalive = self.config['server']['address']
# Translate to a raw IP because we can't give out a host here
keepalive = socket.gethostbyname(keepalive)
root.add_child(item( root.add_child(item(
'keepalive', 'keepalive',
f'http://{keepalive}/core/keepalive?pa={keepalive}&ia={keepalive}&ga={keepalive}&ma={keepalive}&t1=2&t2=10', f'http://{keepalive}/core/keepalive?pa={keepalive}&ia={keepalive}&ga={keepalive}&ma={keepalive}&t1=2&t2=10',
@ -65,7 +61,7 @@ class CoreHandler(Base):
""" """
# Reports that a machine is booting. Overloaded to enable/disable paseli # Reports that a machine is booting. Overloaded to enable/disable paseli
root = Node.void('pcbtracker') root = Node.void('pcbtracker')
root.set_attribute('ecenable', '1' if (self.supports_paseli() and self.config['paseli']['enabled']) else '0') root.set_attribute('ecenable', '1' if (self.supports_paseli() and self.config.paseli.enabled) else '0')
root.set_attribute('expire', '600') root.set_attribute('expire', '600')
return root return root
@ -84,8 +80,8 @@ class CoreHandler(Base):
'name': name, 'name': name,
'value': value, 'value': value,
'model': str(self.model), 'model': str(self.model),
'pcbid': self.config['machine']['pcbid'], 'pcbid': self.config.machine.pcbid,
'ip': self.config['client']['address'], 'ip': self.config.client.address,
}, },
timestamp=timestamp, timestamp=timestamp,
) )
@ -124,7 +120,7 @@ class CoreHandler(Base):
which expects to return a bunch of information about the arcade this which expects to return a bunch of information about the arcade this
cabinet is in, as well as some settings for URLs and the name of the cab. cabinet is in, as well as some settings for URLs and the name of the cab.
""" """
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
root = Node.void('facility') root = Node.void('facility')
root.set_attribute('expire', '600') root.set_attribute('expire', '600')
@ -140,7 +136,7 @@ class CoreHandler(Base):
line.add_child(Node.u8('class', 0)) line.add_child(Node.u8('class', 0))
portfw = Node.void('portfw') portfw = Node.void('portfw')
portfw.add_child(Node.ipv4('globalip', self.config['client']['address'])) portfw.add_child(Node.ipv4('globalip', self.config.client.address))
portfw.add_child(Node.u16('globalport', machine.port)) portfw.add_child(Node.u16('globalport', machine.port))
portfw.add_child(Node.u16('privateport', machine.port)) portfw.add_child(Node.u16('privateport', machine.port))
@ -160,11 +156,11 @@ class CoreHandler(Base):
eapass.add_child(Node.u16('valid', 365)) eapass.add_child(Node.u16('valid', 365))
url = Node.void('url') url = Node.void('url')
url.add_child(Node.string('eapass', self.config['server']['uri'] or 'www.ea-pass.konami.net')) url.add_child(Node.string('eapass', self.config.server.uri or 'www.ea-pass.konami.net'))
url.add_child(Node.string('arcadefan', self.config['server']['uri'] or 'www.konami.jp/am')) url.add_child(Node.string('arcadefan', self.config.server.uri or 'www.konami.jp/am'))
url.add_child(Node.string('konaminetdx', self.config['server']['uri'] or 'http://am.573.jp')) url.add_child(Node.string('konaminetdx', self.config.server.uri or 'http://am.573.jp'))
url.add_child(Node.string('konamiid', self.config['server']['uri'] or 'https://id.konami.net')) url.add_child(Node.string('konamiid', self.config.server.uri or 'https://id.konami.net'))
url.add_child(Node.string('eagate', self.config['server']['uri'] or 'http://eagate.573.jp')) url.add_child(Node.string('eagate', self.config.server.uri or 'http://eagate.573.jp'))
share.add_child(eacoin) share.add_child(eacoin)
share.add_child(url) share.add_child(url)

View File

@ -27,7 +27,7 @@ class PASELIHandler(Base):
""" """
method = request.attribute('method') method = request.attribute('method')
if not self.config['paseli']['enabled']: if not self.config.paseli.enabled:
# Refuse to respond, we don't have PASELI enabled # Refuse to respond, we don't have PASELI enabled
print("PASELI not enabled, ignoring eacoin request") print("PASELI not enabled, ignoring eacoin request")
root = Node.void('eacoin') root = Node.void('eacoin')
@ -61,15 +61,15 @@ class PASELIHandler(Base):
session = self.data.local.user.create_session(userid) session = self.data.local.user.create_session(userid)
if self.config['paseli']['infinite']: if self.config.paseli.infinite:
balance = PASELIHandler.INFINITE_PASELI_AMOUNT balance = PASELIHandler.INFINITE_PASELI_AMOUNT
else: else:
if self.config['machine']['arcade'] is None: if self.config.machine.arcade is None:
# There's no arcade for this machine, but infinite is not # There's no arcade for this machine, but infinite is not
# enabled, so there's no way to find a balance. # enabled, so there's no way to find a balance.
balance = 0 balance = 0
else: else:
balance = self.data.local.user.get_balance(userid, self.config['machine']['arcade']) balance = self.data.local.user.get_balance(userid, self.config.machine.arcade)
root.add_child(Node.s16('sequence', 0)) root.add_child(Node.s16('sequence', 0))
root.add_child(Node.u8('acstatus', 0)) root.add_child(Node.u8('acstatus', 0))
@ -89,13 +89,13 @@ class PASELIHandler(Base):
root.set_attribute('status', str(Status.NO_PROFILE)) root.set_attribute('status', str(Status.NO_PROFILE))
return root return root
if self.config['machine']['arcade'] is None: if self.config.machine.arcade is None:
# Machine doesn't belong to an arcade # Machine doesn't belong to an arcade
print("Machine doesn't belong to an arcade") print("Machine doesn't belong to an arcade")
root.set_attribute('status', str(Status.NO_PROFILE)) root.set_attribute('status', str(Status.NO_PROFILE))
return root return root
arcade = self.data.local.machine.get_arcade(self.config['machine']['arcade']) arcade = self.data.local.machine.get_arcade(self.config.machine.arcade)
if arcade is None: if arcade is None:
# Refuse to do anything # Refuse to do anything
print("No arcade for operator checkin request") print("No arcade for operator checkin request")
@ -136,10 +136,10 @@ class PASELIHandler(Base):
print("Invalid session for eacoin consume request") print("Invalid session for eacoin consume request")
return make_resp(2, 0) return make_resp(2, 0)
if self.config['paseli']['infinite']: if self.config.paseli.infinite:
balance = PASELIHandler.INFINITE_PASELI_AMOUNT - payment balance = PASELIHandler.INFINITE_PASELI_AMOUNT - payment
else: else:
if self.config['machine']['arcade'] is None: if self.config.machine.arcade is None:
# There's no arcade for this machine, but infinite is not # There's no arcade for this machine, but infinite is not
# enabled, so there's no way to find a balance, assume failed # enabled, so there's no way to find a balance, assume failed
# consume payment. # consume payment.
@ -147,11 +147,11 @@ class PASELIHandler(Base):
else: else:
# Look up the new balance based on this delta. If there isn't enough, # Look up the new balance based on this delta. If there isn't enough,
# we will end up returning None here and exit without performing. # we will end up returning None here and exit without performing.
balance = self.data.local.user.update_balance(userid, self.config['machine']['arcade'], -payment) balance = self.data.local.user.update_balance(userid, self.config.machine.arcade, -payment)
if balance is None: if balance is None:
print("Not enough balance for eacoin consume request") print("Not enough balance for eacoin consume request")
return make_resp(1, self.data.local.user.get_balance(userid, self.config['machine']['arcade'])) return make_resp(1, self.data.local.user.get_balance(userid, self.config.machine.arcade))
else: else:
self.data.local.network.put_event( self.data.local.network.put_event(
'paseli_transaction', 'paseli_transaction',
@ -160,10 +160,10 @@ class PASELIHandler(Base):
'balance': balance, 'balance': balance,
'service': -service, 'service': -service,
'reason': details, 'reason': details,
'pcbid': self.config['machine']['pcbid'], 'pcbid': self.config.machine.pcbid,
}, },
userid=userid, userid=userid,
arcadeid=self.config['machine']['arcade'], arcadeid=self.config.machine.arcade,
) )
return make_resp(0, balance) return make_resp(0, balance)
@ -191,7 +191,7 @@ class PASELIHandler(Base):
# If we're a user session, also look up the current arcade # If we're a user session, also look up the current arcade
# so we display only entries that happened on this arcade. # so we display only entries that happened on this arcade.
if userid is not None: if userid is not None:
arcade = self.data.local.machine.get_arcade(self.config['machine']['arcade']) arcade = self.data.local.machine.get_arcade(self.config.machine.arcade)
if arcade is None: if arcade is None:
print("Machine doesn't belong to an arcade") print("Machine doesn't belong to an arcade")
return root return root
@ -394,13 +394,13 @@ class PASELIHandler(Base):
root.set_attribute('status', str(Status.NO_PROFILE)) root.set_attribute('status', str(Status.NO_PROFILE))
return root return root
if self.config['machine']['arcade'] is None: if self.config.machine.arcade is None:
# Machine doesn't belong to an arcade # Machine doesn't belong to an arcade
print("Machine doesn't belong to an arcade") print("Machine doesn't belong to an arcade")
root.set_attribute('status', str(Status.NO_PROFILE)) root.set_attribute('status', str(Status.NO_PROFILE))
return root return root
arcade = self.data.local.machine.get_arcade(self.config['machine']['arcade']) arcade = self.data.local.machine.get_arcade(self.config.machine.arcade)
if arcade is None: if arcade is None:
# Refuse to do anything # Refuse to do anything
print("No arcade for operator pass change request") print("No arcade for operator pass change request")

View File

@ -1,10 +1,10 @@
# vim: set fileencoding=utf-8 # vim: set fileencoding=utf-8
from typing import Optional, Dict, List, Any from typing import Optional, List
from bemani.backend.base import Base from bemani.backend.base import Base
from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler
from bemani.common import Model, Profile, ValidatedDict, GameConstants, DBConstants, Time from bemani.common import Model, Profile, ValidatedDict, GameConstants, DBConstants, Time
from bemani.data import Data, Score, UserID, ScoreSaveException from bemani.data import Config, Data, Score, UserID, ScoreSaveException
from bemani.protocol import Node from bemani.protocol import Node
@ -51,7 +51,7 @@ class DDRBase(CoreHandler, CardManagerHandler, PASELIHandler, Base):
CHART_DOUBLE_EXPERT = 8 CHART_DOUBLE_EXPERT = 8
CHART_DOUBLE_CHALLENGE = 9 CHART_DOUBLE_CHALLENGE = 9
def __init__(self, data: Data, config: Dict[str, Any], model: Model) -> None: def __init__(self, data: Data, config: Config, model: Model) -> None:
super().__init__(data, config, model) super().__init__(data, config, model)
if model.rev == 'X': if model.rev == 'X':
self.omnimix = True self.omnimix = True

View File

@ -466,7 +466,7 @@ class DDRAce(
response.add_child(data) response.add_child(data)
data.add_child(Node.s32('recordtype', requestdata.child_value('loadflag'))) data.add_child(Node.s32('recordtype', requestdata.child_value('loadflag')))
thismachine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) thismachine = self.data.local.machine.get_machine(self.config.machine.pcbid)
machines_by_id: Dict[int, Optional[Machine]] = {thismachine.id: thismachine} machines_by_id: Dict[int, Optional[Machine]] = {thismachine.id: thismachine}
loadkind = requestdata.child_value('loadflag') loadkind = requestdata.child_value('loadflag')
@ -559,7 +559,7 @@ class DDRAce(
if userid is None: if userid is None:
raise Exception('Expecting valid UserID to create new profile!') raise Exception('Expecting valid UserID to create new profile!')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
profile = Profile( profile = Profile(
self.game, self.game,
self.version, self.version,

View File

@ -1,4 +1,4 @@
from typing import Dict, Optional, Any from typing import Optional
from bemani.backend.base import Base, Factory from bemani.backend.base import Base, Factory
from bemani.backend.ddr.stubs import ( from bemani.backend.ddr.stubs import (
@ -21,7 +21,7 @@ from bemani.backend.ddr.ddr2014 import DDR2014
from bemani.backend.ddr.ddrace import DDRAce from bemani.backend.ddr.ddrace import DDRAce
from bemani.backend.ddr.ddra20 import DDRA20 from bemani.backend.ddr.ddra20 import DDRA20
from bemani.common import Model, VersionConstants from bemani.common import Model, VersionConstants
from bemani.data import Data from bemani.data import Config, Data
class DDRFactory(Factory): class DDRFactory(Factory):
@ -52,7 +52,7 @@ class DDRFactory(Factory):
Base.register(gamecode, DDRFactory) Base.register(gamecode, DDRFactory)
@classmethod @classmethod
def create(cls, data: Data, config: Dict[str, Any], model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]: def create(cls, data: Data, config: Config, model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]:
def version_from_date(date: int) -> Optional[int]: def version_from_date(date: int) -> Optional[int]:
if date < 2014051200: if date < 2014051200:

View File

@ -1,9 +1,8 @@
import copy from typing import Optional, Any
from typing import Optional, Dict, Any
from bemani.backend.base import Model, Base, Status from bemani.backend.base import Model, Base, Status
from bemani.protocol import Node from bemani.protocol import Node
from bemani.data import Data from bemani.data import Config, Data
class UnrecognizedPCBIDException(Exception): class UnrecognizedPCBIDException(Exception):
@ -20,7 +19,7 @@ class Dispatch:
class and then returning a response. class and then returning a response.
""" """
def __init__(self, config: Dict[str, Any], data: Data, verbose: bool) -> None: def __init__(self, config: Config, data: Data, verbose: bool) -> None:
""" """
Initialize the Dispatch object. Initialize the Dispatch object.
@ -77,9 +76,9 @@ class Dispatch:
# If we are enforcing, bail out if we don't recognize thie ID # If we are enforcing, bail out if we don't recognize thie ID
pcb = self.__data.local.machine.get_machine(pcbid) pcb = self.__data.local.machine.get_machine(pcbid)
if self.__config['server']['enforce_pcbid'] and pcb is None: if self.__config.server.enforce_pcbid and pcb is None:
self.log("Unrecognized PCBID {}", pcbid) self.log("Unrecognized PCBID {}", pcbid)
raise UnrecognizedPCBIDException(pcbid, modelstring, self.__config['client']['address']) raise UnrecognizedPCBIDException(pcbid, modelstring, self.__config.client.address)
# If we don't have a Machine, but we aren't enforcing, we must create it # If we don't have a Machine, but we aren't enforcing, we must create it
if pcb is None: if pcb is None:
@ -87,7 +86,7 @@ class Dispatch:
request = tree.children[0] request = tree.children[0]
config = copy.copy(self.__config) config = self.__config.clone()
config['machine'] = { config['machine'] = {
'pcbid': pcbid, 'pcbid': pcbid,
'arcade': pcb.arcade, 'arcade': pcb.arcade,
@ -103,9 +102,6 @@ class Dispatch:
if arcade.data.get_bool('mask_services_url'): if arcade.data.get_bool('mask_services_url'):
# Mask the address, no matter what the server settings are # Mask the address, no matter what the server settings are
config['server']['uri'] = None config['server']['uri'] = None
# If we don't have a server URI, we should add the default
if 'uri' not in config['server']:
config['server']['uri'] = None
game = Base.create(self.__data, config, model) game = Base.create(self.__data, config, model)
method = request.attribute('method') method = request.attribute('method')
@ -113,10 +109,10 @@ class Dispatch:
# If we are enforcing, make sure the PCBID isn't specified to be # If we are enforcing, make sure the PCBID isn't specified to be
# game-specific # game-specific
if self.__config['server']['enforce_pcbid'] and pcb.game is not None: if config.server.enforce_pcbid and pcb.game is not None:
if pcb.game != game.game: if pcb.game != game.game:
self.log("PCBID {} assigned to game {}, but connected from game {}", pcbid, pcb.game, game.game) self.log("PCBID {} assigned to game {}, but connected from game {}", pcbid, pcb.game, game.game)
raise UnrecognizedPCBIDException(pcbid, modelstring, self.__config['client']['address']) raise UnrecognizedPCBIDException(pcbid, modelstring, config.client.address)
if pcb.version is not None: if pcb.version is not None:
if pcb.version > 0 and pcb.version != game.version: if pcb.version > 0 and pcb.version != game.version:
self.log( self.log(
@ -127,7 +123,7 @@ class Dispatch:
game.game, game.game,
game.version, game.version,
) )
raise UnrecognizedPCBIDException(pcbid, modelstring, self.__config['client']['address']) raise UnrecognizedPCBIDException(pcbid, modelstring, config.client.address)
if pcb.version < 0 and (-pcb.version) < game.version: if pcb.version < 0 and (-pcb.version) < game.version:
self.log( self.log(
"PCBID {} assigned to game {} maximum version {}, but connected from game {} version {}", "PCBID {} assigned to game {} maximum version {}, but connected from game {} version {}",
@ -137,7 +133,7 @@ class Dispatch:
game.game, game.game,
game.version, game.version,
) )
raise UnrecognizedPCBIDException(pcbid, modelstring, self.__config['client']['address']) raise UnrecognizedPCBIDException(pcbid, modelstring, config.client.address)
# First, try to handle with specific service/method function # First, try to handle with specific service/method function
try: try:

View File

@ -5,7 +5,7 @@ from typing import Optional, Dict, Any, List, Tuple
from bemani.backend.base import Base from bemani.backend.base import Base
from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler
from bemani.common import Profile, ValidatedDict, Model, GameConstants, DBConstants, Parallel from bemani.common import Profile, ValidatedDict, Model, GameConstants, DBConstants, Parallel
from bemani.data import Data, Score, Machine, UserID from bemani.data import Config, Data, Score, Machine, UserID
from bemani.protocol import Node from bemani.protocol import Node
@ -75,7 +75,7 @@ class IIDXBase(CoreHandler, CardManagerHandler, PASELIHandler, Base):
GHOST_TYPE_RIVAL_TOP = 800 GHOST_TYPE_RIVAL_TOP = 800
GHOST_TYPE_RIVAL_AVERAGE = 900 GHOST_TYPE_RIVAL_AVERAGE = 900
def __init__(self, data: Data, config: Dict[str, Any], model: Model) -> None: def __init__(self, data: Data, config: Config, model: Model) -> None:
super().__init__(data, config, model) super().__init__(data, config, model)
if model.rev == 'X': if model.rev == 'X':
self.omnimix = True self.omnimix = True
@ -189,7 +189,7 @@ class IIDXBase(CoreHandler, CardManagerHandler, PASELIHandler, Base):
return None return None
def machine_joined_arcade(self) -> bool: def machine_joined_arcade(self) -> bool:
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
return machine.arcade is not None return machine.arcade is not None
def get_clear_rates( def get_clear_rates(

View File

@ -288,7 +288,7 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase):
raise Exception('Invalid cltype!') raise Exception('Invalid cltype!')
def handle_IIDX25shop_getname_request(self, request: Node) -> Node: def handle_IIDX25shop_getname_request(self, request: Node) -> Node:
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine is not None: if machine is not None:
machine_name = machine.name machine_name = machine.name
close = machine.data.get_bool('close') close = machine.data.get_bool('close')
@ -333,7 +333,7 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase):
def handle_IIDX25shop_getconvention_request(self, request: Node) -> Node: def handle_IIDX25shop_getconvention_request(self, request: Node) -> Node:
root = Node.void('IIDX25shop') root = Node.void('IIDX25shop')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course') course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course')
else: else:
@ -350,7 +350,7 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase):
return root return root
def handle_IIDX25shop_setconvention_request(self, request: Node) -> Node: def handle_IIDX25shop_setconvention_request(self, request: Node) -> Node:
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = ValidatedDict() course = ValidatedDict()
course.replace_int('music_0', request.child_value('music_0')) course.replace_int('music_0', request.child_value('music_0'))
@ -376,7 +376,7 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase):
# Chart type 6 is presumably beginner mode, but it crashes the game # Chart type 6 is presumably beginner mode, but it crashes the game
return root return root
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course') course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course')
else: else:
@ -677,7 +677,7 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase):
if self.machine_joined_arcade(): if self.machine_joined_arcade():
game_config = self.get_game_config() game_config = self.get_game_config()
global_scores = game_config.get_bool('global_shop_ranking') global_scores = game_config.get_bool('global_shop_ranking')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
else: else:
# If we aren't in an arcade, we can only show global scores # If we aren't in an arcade, we can only show global scores
global_scores = True global_scores = True
@ -1425,7 +1425,7 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase):
# Look up judge window adjustments # Look up judge window adjustments
judge_dict = profile.get_dict('machine_judge_adjust') judge_dict = profile.get_dict('machine_judge_adjust')
machine_judge = judge_dict.get_dict(self.config['machine']['pcbid']) machine_judge = judge_dict.get_dict(self.config.machine.pcbid)
# Profile data # Profile data
pcdata = Node.void('pcdata') pcdata = Node.void('pcdata')
@ -1921,10 +1921,10 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase):
newprofile.replace_int('rtype', int(request.attribute('rtype'))) newprofile.replace_int('rtype', int(request.attribute('rtype')))
# Update judge window adjustments per-machine # Update judge window adjustments per-machine
judge_dict = newprofile.get_dict('machine_judge_adjust') judge_dict = newprofile.get_dict('machine_judge_adjust')
machine_judge = judge_dict.get_dict(self.config['machine']['pcbid']) machine_judge = judge_dict.get_dict(self.config.machine.pcbid)
machine_judge.replace_int('single', int(request.attribute('s_judgeAdj'))) machine_judge.replace_int('single', int(request.attribute('s_judgeAdj')))
machine_judge.replace_int('double', int(request.attribute('d_judgeAdj'))) machine_judge.replace_int('double', int(request.attribute('d_judgeAdj')))
judge_dict.replace_dict(self.config['machine']['pcbid'], machine_judge) judge_dict.replace_dict(self.config.machine.pcbid, machine_judge)
newprofile.replace_dict('machine_judge_adjust', judge_dict) newprofile.replace_dict('machine_judge_adjust', judge_dict)
# Secret flags saving # Secret flags saving

View File

@ -293,7 +293,7 @@ class IIDXCopula(IIDXCourse, IIDXBase):
if method == 'getname': if method == 'getname':
root = Node.void('IIDX23shop') root = Node.void('IIDX23shop')
root.set_attribute('cls_opt', '0') root.set_attribute('cls_opt', '0')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
root.set_attribute('opname', machine.name) root.set_attribute('opname', machine.name)
root.set_attribute('pid', '51') root.set_attribute('pid', '51')
return root return root
@ -309,7 +309,7 @@ class IIDXCopula(IIDXCourse, IIDXBase):
if method == 'getconvention': if method == 'getconvention':
root = Node.void('IIDX23shop') root = Node.void('IIDX23shop')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course') course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course')
else: else:
@ -327,7 +327,7 @@ class IIDXCopula(IIDXCourse, IIDXBase):
if method == 'setconvention': if method == 'setconvention':
root = Node.void('IIDX23shop') root = Node.void('IIDX23shop')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = ValidatedDict() course = ValidatedDict()
course.replace_int('music_0', request.child_value('music_0')) course.replace_int('music_0', request.child_value('music_0'))
@ -364,7 +364,7 @@ class IIDXCopula(IIDXCourse, IIDXBase):
# Chart type 6 is presumably beginner mode, but it crashes the game # Chart type 6 is presumably beginner mode, but it crashes the game
return root return root
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course') course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course')
else: else:
@ -571,7 +571,7 @@ class IIDXCopula(IIDXCourse, IIDXBase):
if self.machine_joined_arcade(): if self.machine_joined_arcade():
game_config = self.get_game_config() game_config = self.get_game_config()
global_scores = game_config.get_bool('global_shop_ranking') global_scores = game_config.get_bool('global_shop_ranking')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
else: else:
# If we aren't in an arcade, we can only show global scores # If we aren't in an arcade, we can only show global scores
global_scores = True global_scores = True
@ -1477,7 +1477,7 @@ class IIDXCopula(IIDXCourse, IIDXBase):
# Look up judge window adjustments # Look up judge window adjustments
judge_dict = profile.get_dict('machine_judge_adjust') judge_dict = profile.get_dict('machine_judge_adjust')
machine_judge = judge_dict.get_dict(self.config['machine']['pcbid']) machine_judge = judge_dict.get_dict(self.config.machine.pcbid)
# Profile data # Profile data
pcdata = Node.void('pcdata') pcdata = Node.void('pcdata')
@ -1925,10 +1925,10 @@ class IIDXCopula(IIDXCourse, IIDXBase):
# Update judge window adjustments per-machine # Update judge window adjustments per-machine
judge_dict = newprofile.get_dict('machine_judge_adjust') judge_dict = newprofile.get_dict('machine_judge_adjust')
machine_judge = judge_dict.get_dict(self.config['machine']['pcbid']) machine_judge = judge_dict.get_dict(self.config.machine.pcbid)
machine_judge.replace_int('single', int(request.attribute('s_judgeAdj'))) machine_judge.replace_int('single', int(request.attribute('s_judgeAdj')))
machine_judge.replace_int('double', int(request.attribute('d_judgeAdj'))) machine_judge.replace_int('double', int(request.attribute('d_judgeAdj')))
judge_dict.replace_dict(self.config['machine']['pcbid'], machine_judge) judge_dict.replace_dict(self.config.machine.pcbid, machine_judge)
newprofile.replace_dict('machine_judge_adjust', judge_dict) newprofile.replace_dict('machine_judge_adjust', judge_dict)
# Secret flags saving # Secret flags saving

View File

@ -1,4 +1,4 @@
from typing import Dict, Optional, Any from typing import Optional
from bemani.backend.base import Base, Factory from bemani.backend.base import Base, Factory
from bemani.backend.iidx.stubs import ( from bemani.backend.iidx.stubs import (
@ -32,7 +32,7 @@ from bemani.backend.iidx.rootage import IIDXRootage
from bemani.backend.iidx.heroicverse import IIDXHeroicVerse from bemani.backend.iidx.heroicverse import IIDXHeroicVerse
from bemani.backend.iidx.bistrover import IIDXBistrover from bemani.backend.iidx.bistrover import IIDXBistrover
from bemani.common import Model, VersionConstants from bemani.common import Model, VersionConstants
from bemani.data import Data from bemani.data import Config, Data
class IIDXFactory(Factory): class IIDXFactory(Factory):
@ -74,7 +74,7 @@ class IIDXFactory(Factory):
Base.register(gamecode, IIDXFactory) Base.register(gamecode, IIDXFactory)
@classmethod @classmethod
def create(cls, data: Data, config: Dict[str, Any], model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]: def create(cls, data: Data, config: Config, model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]:
def version_from_date(date: int) -> Optional[int]: def version_from_date(date: int) -> Optional[int]:
if date < 2013100200: if date < 2013100200:

View File

@ -161,7 +161,7 @@ class IIDXPendual(IIDXCourse, IIDXBase):
if method == 'getname': if method == 'getname':
root = Node.void('IIDX22shop') root = Node.void('IIDX22shop')
root.set_attribute('cls_opt', '0') root.set_attribute('cls_opt', '0')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
root.set_attribute('opname', machine.name) root.set_attribute('opname', machine.name)
root.set_attribute('pid', '51') root.set_attribute('pid', '51')
return root return root
@ -177,7 +177,7 @@ class IIDXPendual(IIDXCourse, IIDXBase):
if method == 'getconvention': if method == 'getconvention':
root = Node.void('IIDX22shop') root = Node.void('IIDX22shop')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course') course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course')
else: else:
@ -195,7 +195,7 @@ class IIDXPendual(IIDXCourse, IIDXBase):
if method == 'setconvention': if method == 'setconvention':
root = Node.void('IIDX22shop') root = Node.void('IIDX22shop')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = ValidatedDict() course = ValidatedDict()
course.replace_int('music_0', request.child_value('music_0')) course.replace_int('music_0', request.child_value('music_0'))
@ -227,7 +227,7 @@ class IIDXPendual(IIDXCourse, IIDXBase):
# Chart type 6 is presumably beginner mode, but it crashes the game # Chart type 6 is presumably beginner mode, but it crashes the game
return root return root
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course') course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course')
else: else:
@ -555,7 +555,7 @@ class IIDXPendual(IIDXCourse, IIDXBase):
if self.machine_joined_arcade(): if self.machine_joined_arcade():
game_config = self.get_game_config() game_config = self.get_game_config()
global_scores = game_config.get_bool('global_shop_ranking') global_scores = game_config.get_bool('global_shop_ranking')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
else: else:
# If we aren't in an arcade, we can only show global scores # If we aren't in an arcade, we can only show global scores
global_scores = True global_scores = True
@ -1390,7 +1390,7 @@ class IIDXPendual(IIDXCourse, IIDXBase):
# Look up judge window adjustments # Look up judge window adjustments
judge_dict = profile.get_dict('machine_judge_adjust') judge_dict = profile.get_dict('machine_judge_adjust')
machine_judge = judge_dict.get_dict(self.config['machine']['pcbid']) machine_judge = judge_dict.get_dict(self.config.machine.pcbid)
# Profile data # Profile data
pcdata = Node.void('pcdata') pcdata = Node.void('pcdata')
@ -1771,10 +1771,10 @@ class IIDXPendual(IIDXCourse, IIDXBase):
# Update judge window adjustments per-machine # Update judge window adjustments per-machine
judge_dict = newprofile.get_dict('machine_judge_adjust') judge_dict = newprofile.get_dict('machine_judge_adjust')
machine_judge = judge_dict.get_dict(self.config['machine']['pcbid']) machine_judge = judge_dict.get_dict(self.config.machine.pcbid)
machine_judge.replace_int('single', int(request.attribute('s_judgeAdj'))) machine_judge.replace_int('single', int(request.attribute('s_judgeAdj')))
machine_judge.replace_int('double', int(request.attribute('d_judgeAdj'))) machine_judge.replace_int('double', int(request.attribute('d_judgeAdj')))
judge_dict.replace_dict(self.config['machine']['pcbid'], machine_judge) judge_dict.replace_dict(self.config.machine.pcbid, machine_judge)
newprofile.replace_dict('machine_judge_adjust', judge_dict) newprofile.replace_dict('machine_judge_adjust', judge_dict)
# Secret flags saving # Secret flags saving

View File

@ -289,7 +289,7 @@ class IIDXRootage(IIDXCourse, IIDXBase):
raise Exception('Invalid cltype!') raise Exception('Invalid cltype!')
def handle_IIDX26shop_getname_request(self, request: Node) -> Node: def handle_IIDX26shop_getname_request(self, request: Node) -> Node:
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine is not None: if machine is not None:
machine_name = machine.name machine_name = machine.name
close = machine.data.get_bool('close') close = machine.data.get_bool('close')
@ -334,7 +334,7 @@ class IIDXRootage(IIDXCourse, IIDXBase):
def handle_IIDX26shop_getconvention_request(self, request: Node) -> Node: def handle_IIDX26shop_getconvention_request(self, request: Node) -> Node:
root = Node.void('IIDX26shop') root = Node.void('IIDX26shop')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course') course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course')
else: else:
@ -351,7 +351,7 @@ class IIDXRootage(IIDXCourse, IIDXBase):
return root return root
def handle_IIDX26shop_setconvention_request(self, request: Node) -> Node: def handle_IIDX26shop_setconvention_request(self, request: Node) -> Node:
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = ValidatedDict() course = ValidatedDict()
course.replace_int('music_0', request.child_value('music_0')) course.replace_int('music_0', request.child_value('music_0'))
@ -530,7 +530,7 @@ class IIDXRootage(IIDXCourse, IIDXBase):
if self.machine_joined_arcade(): if self.machine_joined_arcade():
game_config = self.get_game_config() game_config = self.get_game_config()
global_scores = game_config.get_bool('global_shop_ranking') global_scores = game_config.get_bool('global_shop_ranking')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
else: else:
# If we aren't in an arcade, we can only show global scores # If we aren't in an arcade, we can only show global scores
global_scores = True global_scores = True
@ -1100,7 +1100,7 @@ class IIDXRootage(IIDXCourse, IIDXBase):
# Look up judge window adjustments # Look up judge window adjustments
judge_dict = profile.get_dict('machine_judge_adjust') judge_dict = profile.get_dict('machine_judge_adjust')
machine_judge = judge_dict.get_dict(self.config['machine']['pcbid']) machine_judge = judge_dict.get_dict(self.config.machine.pcbid)
# Profile data # Profile data
pcdata = Node.void('pcdata') pcdata = Node.void('pcdata')
@ -1638,10 +1638,10 @@ class IIDXRootage(IIDXCourse, IIDXBase):
# Update judge window adjustments per-machine # Update judge window adjustments per-machine
judge_dict = newprofile.get_dict('machine_judge_adjust') judge_dict = newprofile.get_dict('machine_judge_adjust')
machine_judge = judge_dict.get_dict(self.config['machine']['pcbid']) machine_judge = judge_dict.get_dict(self.config.machine.pcbid)
machine_judge.replace_int('single', int(request.attribute('s_judgeAdj'))) machine_judge.replace_int('single', int(request.attribute('s_judgeAdj')))
machine_judge.replace_int('double', int(request.attribute('d_judgeAdj'))) machine_judge.replace_int('double', int(request.attribute('d_judgeAdj')))
judge_dict.replace_dict(self.config['machine']['pcbid'], machine_judge) judge_dict.replace_dict(self.config.machine.pcbid, machine_judge)
newprofile.replace_dict('machine_judge_adjust', judge_dict) newprofile.replace_dict('machine_judge_adjust', judge_dict)
# Secret flags saving # Secret flags saving

View File

@ -288,7 +288,7 @@ class IIDXSinobuz(IIDXCourse, IIDXBase):
raise Exception('Invalid cltype!') raise Exception('Invalid cltype!')
def handle_IIDX24shop_getname_request(self, request: Node) -> Node: def handle_IIDX24shop_getname_request(self, request: Node) -> Node:
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine is not None: if machine is not None:
machine_name = machine.name machine_name = machine.name
close = machine.data.get_bool('close') close = machine.data.get_bool('close')
@ -333,7 +333,7 @@ class IIDXSinobuz(IIDXCourse, IIDXBase):
def handle_IIDX24shop_getconvention_request(self, request: Node) -> Node: def handle_IIDX24shop_getconvention_request(self, request: Node) -> Node:
root = Node.void('IIDX24shop') root = Node.void('IIDX24shop')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course') course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course')
else: else:
@ -350,7 +350,7 @@ class IIDXSinobuz(IIDXCourse, IIDXBase):
return root return root
def handle_IIDX24shop_setconvention_request(self, request: Node) -> Node: def handle_IIDX24shop_setconvention_request(self, request: Node) -> Node:
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = ValidatedDict() course = ValidatedDict()
course.replace_int('music_0', request.child_value('music_0')) course.replace_int('music_0', request.child_value('music_0'))
@ -376,7 +376,7 @@ class IIDXSinobuz(IIDXCourse, IIDXBase):
# Chart type 6 is presumably beginner mode, but it crashes the game # Chart type 6 is presumably beginner mode, but it crashes the game
return root return root
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course') course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course')
else: else:
@ -675,7 +675,7 @@ class IIDXSinobuz(IIDXCourse, IIDXBase):
if self.machine_joined_arcade(): if self.machine_joined_arcade():
game_config = self.get_game_config() game_config = self.get_game_config()
global_scores = game_config.get_bool('global_shop_ranking') global_scores = game_config.get_bool('global_shop_ranking')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
else: else:
# If we aren't in an arcade, we can only show global scores # If we aren't in an arcade, we can only show global scores
global_scores = True global_scores = True
@ -1449,7 +1449,7 @@ class IIDXSinobuz(IIDXCourse, IIDXBase):
# Look up judge window adjustments # Look up judge window adjustments
judge_dict = profile.get_dict('machine_judge_adjust') judge_dict = profile.get_dict('machine_judge_adjust')
machine_judge = judge_dict.get_dict(self.config['machine']['pcbid']) machine_judge = judge_dict.get_dict(self.config.machine.pcbid)
# Profile data # Profile data
pcdata = Node.void('pcdata') pcdata = Node.void('pcdata')
@ -1936,10 +1936,10 @@ class IIDXSinobuz(IIDXCourse, IIDXBase):
# Update judge window adjustments per-machine # Update judge window adjustments per-machine
judge_dict = newprofile.get_dict('machine_judge_adjust') judge_dict = newprofile.get_dict('machine_judge_adjust')
machine_judge = judge_dict.get_dict(self.config['machine']['pcbid']) machine_judge = judge_dict.get_dict(self.config.machine.pcbid)
machine_judge.replace_int('single', int(request.attribute('s_judgeAdj'))) machine_judge.replace_int('single', int(request.attribute('s_judgeAdj')))
machine_judge.replace_int('double', int(request.attribute('d_judgeAdj'))) machine_judge.replace_int('double', int(request.attribute('d_judgeAdj')))
judge_dict.replace_dict(self.config['machine']['pcbid'], machine_judge) judge_dict.replace_dict(self.config.machine.pcbid, machine_judge)
newprofile.replace_dict('machine_judge_adjust', judge_dict) newprofile.replace_dict('machine_judge_adjust', judge_dict)
# Secret flags saving # Secret flags saving

View File

@ -266,7 +266,7 @@ class IIDXSpada(IIDXBase):
if method == 'getname': if method == 'getname':
root = Node.void('IIDX21shop') root = Node.void('IIDX21shop')
root.set_attribute('cls_opt', '0') root.set_attribute('cls_opt', '0')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
root.set_attribute('opname', machine.name) root.set_attribute('opname', machine.name)
root.set_attribute('pid', '51') root.set_attribute('pid', '51')
return root return root
@ -282,7 +282,7 @@ class IIDXSpada(IIDXBase):
if method == 'getconvention': if method == 'getconvention':
root = Node.void('IIDX21shop') root = Node.void('IIDX21shop')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course') course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course')
else: else:
@ -300,7 +300,7 @@ class IIDXSpada(IIDXBase):
if method == 'setconvention': if method == 'setconvention':
root = Node.void('IIDX21shop') root = Node.void('IIDX21shop')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = ValidatedDict() course = ValidatedDict()
course.replace_int('music_0', request.child_value('music_0')) course.replace_int('music_0', request.child_value('music_0'))
@ -332,7 +332,7 @@ class IIDXSpada(IIDXBase):
# Chart type 6 is presumably beginner mode, but it crashes the game # Chart type 6 is presumably beginner mode, but it crashes the game
return root return root
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course') course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course')
else: else:
@ -503,7 +503,7 @@ class IIDXSpada(IIDXBase):
if self.machine_joined_arcade(): if self.machine_joined_arcade():
game_config = self.get_game_config() game_config = self.get_game_config()
global_scores = game_config.get_bool('global_shop_ranking') global_scores = game_config.get_bool('global_shop_ranking')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
else: else:
# If we aren't in an arcade, we can only show global scores # If we aren't in an arcade, we can only show global scores
global_scores = True global_scores = True
@ -1089,7 +1089,7 @@ class IIDXSpada(IIDXBase):
# Look up judge window adjustments # Look up judge window adjustments
judge_dict = profile.get_dict('machine_judge_adjust') judge_dict = profile.get_dict('machine_judge_adjust')
machine_judge = judge_dict.get_dict(self.config['machine']['pcbid']) machine_judge = judge_dict.get_dict(self.config.machine.pcbid)
# Profile data # Profile data
pcdata = Node.void('pcdata') pcdata = Node.void('pcdata')
@ -1516,10 +1516,10 @@ class IIDXSpada(IIDXBase):
# Update judge window adjustments per-machine # Update judge window adjustments per-machine
judge_dict = newprofile.get_dict('machine_judge_adjust') judge_dict = newprofile.get_dict('machine_judge_adjust')
machine_judge = judge_dict.get_dict(self.config['machine']['pcbid']) machine_judge = judge_dict.get_dict(self.config.machine.pcbid)
machine_judge.replace_int('single', int(request.attribute('s_judgeAdj'))) machine_judge.replace_int('single', int(request.attribute('s_judgeAdj')))
machine_judge.replace_int('double', int(request.attribute('d_judgeAdj'))) machine_judge.replace_int('double', int(request.attribute('d_judgeAdj')))
judge_dict.replace_dict(self.config['machine']['pcbid'], machine_judge) judge_dict.replace_dict(self.config.machine.pcbid, machine_judge)
newprofile.replace_dict('machine_judge_adjust', judge_dict) newprofile.replace_dict('machine_judge_adjust', judge_dict)
# Secret flags saving # Secret flags saving

View File

@ -265,7 +265,7 @@ class IIDXTricoro(IIDXBase):
if method == 'getname': if method == 'getname':
root = Node.void('shop') root = Node.void('shop')
root.set_attribute('cls_opt', '0') root.set_attribute('cls_opt', '0')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
root.set_attribute('opname', machine.name) root.set_attribute('opname', machine.name)
root.set_attribute('pid', '51') root.set_attribute('pid', '51')
return root return root
@ -281,7 +281,7 @@ class IIDXTricoro(IIDXBase):
if method == 'getconvention': if method == 'getconvention':
root = Node.void('shop') root = Node.void('shop')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course') course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course')
else: else:
@ -299,7 +299,7 @@ class IIDXTricoro(IIDXBase):
if method == 'setconvention': if method == 'setconvention':
root = Node.void('shop') root = Node.void('shop')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = ValidatedDict() course = ValidatedDict()
course.replace_int('music_0', request.child_value('music_0')) course.replace_int('music_0', request.child_value('music_0'))
@ -331,7 +331,7 @@ class IIDXTricoro(IIDXBase):
# Chart type 6 is presumably beginner mode, but it crashes the game # Chart type 6 is presumably beginner mode, but it crashes the game
return root return root
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course') course = self.data.local.machine.get_settings(machine.arcade, self.game, self.music_version, 'shop_course')
else: else:
@ -503,7 +503,7 @@ class IIDXTricoro(IIDXBase):
if self.machine_joined_arcade(): if self.machine_joined_arcade():
game_config = self.get_game_config() game_config = self.get_game_config()
global_scores = game_config.get_bool('global_shop_ranking') global_scores = game_config.get_bool('global_shop_ranking')
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
else: else:
# If we aren't in an arcade, we can only show global scores # If we aren't in an arcade, we can only show global scores
global_scores = True global_scores = True
@ -985,7 +985,7 @@ class IIDXTricoro(IIDXBase):
# Look up judge window adjustments # Look up judge window adjustments
judge_dict = profile.get_dict('machine_judge_adjust') judge_dict = profile.get_dict('machine_judge_adjust')
machine_judge = judge_dict.get_dict(self.config['machine']['pcbid']) machine_judge = judge_dict.get_dict(self.config.machine.pcbid)
# Profile data # Profile data
pcdata = Node.void('pcdata') pcdata = Node.void('pcdata')
@ -1292,9 +1292,9 @@ class IIDXTricoro(IIDXBase):
# Update judge window adjustments per-machine # Update judge window adjustments per-machine
judge_dict = newprofile.get_dict('machine_judge_adjust') judge_dict = newprofile.get_dict('machine_judge_adjust')
machine_judge = judge_dict.get_dict(self.config['machine']['pcbid']) machine_judge = judge_dict.get_dict(self.config.machine.pcbid)
machine_judge.replace_int('adj', int(request.attribute('judgeAdj'))) machine_judge.replace_int('adj', int(request.attribute('judgeAdj')))
judge_dict.replace_dict(self.config['machine']['pcbid'], machine_judge) judge_dict.replace_dict(self.config.machine.pcbid, machine_judge)
newprofile.replace_dict('machine_judge_adjust', judge_dict) newprofile.replace_dict('machine_judge_adjust', judge_dict)
# Secret flags saving # Secret flags saving

View File

@ -1,4 +1,4 @@
from typing import Dict, Optional, Any from typing import Optional
from bemani.backend.base import Base, Factory from bemani.backend.base import Base, Factory
from bemani.backend.jubeat.stubs import ( from bemani.backend.jubeat.stubs import (
@ -17,7 +17,7 @@ from bemani.backend.jubeat.qubell import JubeatQubell
from bemani.backend.jubeat.clan import JubeatClan from bemani.backend.jubeat.clan import JubeatClan
from bemani.backend.jubeat.festo import JubeatFesto from bemani.backend.jubeat.festo import JubeatFesto
from bemani.common import Model from bemani.common import Model
from bemani.data import Data from bemani.data import Config, Data
class JubeatFactory(Factory): class JubeatFactory(Factory):
@ -44,7 +44,7 @@ class JubeatFactory(Factory):
Base.register(gamecode, JubeatFactory) Base.register(gamecode, JubeatFactory)
@classmethod @classmethod
def create(cls, data: Data, config: Dict[str, Any], model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]: def create(cls, data: Data, config: Config, model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]:
if model.gamecode == 'H44': if model.gamecode == 'H44':
return Jubeat(data, config, model) return Jubeat(data, config, model)
if model.gamecode == 'I44': if model.gamecode == 'I44':

View File

@ -1,10 +1,10 @@
# vim: set fileencoding=utf-8 # vim: set fileencoding=utf-8
from typing import Dict, Optional, Any from typing import Dict, Optional
from bemani.backend.base import Base from bemani.backend.base import Base
from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler
from bemani.common import Profile, ValidatedDict, GameConstants, DBConstants, Parallel, Model from bemani.common import Profile, ValidatedDict, GameConstants, DBConstants, Parallel, Model
from bemani.data import UserID, Data from bemani.data import UserID, Config, Data
from bemani.protocol import Node from bemani.protocol import Node
@ -33,7 +33,7 @@ class MusecaBase(CoreHandler, CardManagerHandler, PASELIHandler, Base):
CLEAR_TYPE_CLEARED = DBConstants.MUSECA_CLEAR_TYPE_CLEARED CLEAR_TYPE_CLEARED = DBConstants.MUSECA_CLEAR_TYPE_CLEARED
CLEAR_TYPE_FULL_COMBO = DBConstants.MUSECA_CLEAR_TYPE_FULL_COMBO CLEAR_TYPE_FULL_COMBO = DBConstants.MUSECA_CLEAR_TYPE_FULL_COMBO
def __init__(self, data: Data, config: Dict[str, Any], model: Model) -> None: def __init__(self, data: Data, config: Config, model: Model) -> None:
super().__init__(data, config, model) super().__init__(data, config, model)
if model.rev == 'X': if model.rev == 'X':
self.omnimix = True self.omnimix = True

View File

@ -1,10 +1,10 @@
from typing import Any, Dict, List, Optional, Type from typing import List, Optional, Type
from bemani.backend.base import Base, Factory from bemani.backend.base import Base, Factory
from bemani.backend.museca.museca1 import Museca1 from bemani.backend.museca.museca1 import Museca1
from bemani.backend.museca.museca1plus import Museca1Plus from bemani.backend.museca.museca1plus import Museca1Plus
from bemani.common import Model, VersionConstants from bemani.common import Model, VersionConstants
from bemani.data import Data from bemani.data import Config, Data
class MusecaFactory(Factory): class MusecaFactory(Factory):
@ -20,7 +20,7 @@ class MusecaFactory(Factory):
Base.register(gamecode, MusecaFactory) Base.register(gamecode, MusecaFactory)
@classmethod @classmethod
def create(cls, data: Data, config: Dict[str, Any], model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]: def create(cls, data: Data, config: Config, model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]:
def version_from_date(date: int) -> Optional[int]: def version_from_date(date: int) -> Optional[int]:
if date <= 2016072600: if date <= 2016072600:

View File

@ -1,4 +1,4 @@
from typing import Dict, Optional, Any from typing import Optional
from bemani.backend.base import Base, Factory from bemani.backend.base import Base, Factory
from bemani.backend.popn.stubs import ( from bemani.backend.popn.stubs import (
@ -29,7 +29,7 @@ from bemani.backend.popn.eclale import PopnMusicEclale
from bemani.backend.popn.usaneko import PopnMusicUsaNeko from bemani.backend.popn.usaneko import PopnMusicUsaNeko
from bemani.backend.popn.peace import PopnMusicPeace from bemani.backend.popn.peace import PopnMusicPeace
from bemani.common import Model, VersionConstants from bemani.common import Model, VersionConstants
from bemani.data import Data from bemani.data import Config, Data
class PopnMusicFactory(Factory): class PopnMusicFactory(Factory):
@ -68,7 +68,7 @@ class PopnMusicFactory(Factory):
Base.register(gamecode, PopnMusicFactory) Base.register(gamecode, PopnMusicFactory)
@classmethod @classmethod
def create(cls, data: Data, config: Dict[str, Any], model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]: def create(cls, data: Data, config: Config, model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]:
def version_from_date(date: int) -> Optional[int]: def version_from_date(date: int) -> Optional[int]:
if date <= 2014061900: if date <= 2014061900:

View File

@ -1,4 +1,4 @@
from typing import Any, Dict, List, Optional, Type from typing import List, Optional, Type
from bemani.backend.base import Base, Factory from bemani.backend.base import Base, Factory
from bemani.backend.reflec.reflecbeat import ReflecBeat from bemani.backend.reflec.reflecbeat import ReflecBeat
@ -8,7 +8,7 @@ from bemani.backend.reflec.groovin import ReflecBeatGroovin
from bemani.backend.reflec.volzza import ReflecBeatVolzza from bemani.backend.reflec.volzza import ReflecBeatVolzza
from bemani.backend.reflec.volzza2 import ReflecBeatVolzza2 from bemani.backend.reflec.volzza2 import ReflecBeatVolzza2
from bemani.common import Model, VersionConstants from bemani.common import Model, VersionConstants
from bemani.data import Data from bemani.data import Config, Data
class ReflecBeatFactory(Factory): class ReflecBeatFactory(Factory):
@ -28,7 +28,7 @@ class ReflecBeatFactory(Factory):
Base.register(gamecode, ReflecBeatFactory) Base.register(gamecode, ReflecBeatFactory)
@classmethod @classmethod
def create(cls, data: Data, config: Dict[str, Any], model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]: def create(cls, data: Data, config: Config, model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]:
def version_from_date(date: int) -> Optional[int]: def version_from_date(date: int) -> Optional[int]:
if date < 2014060400: if date < 2014060400:

View File

@ -295,7 +295,7 @@ class ReflecBeatGroovin(ReflecBeatBase):
all_profiles = self.data.local.user.get_all_profiles(self.game, self.version) all_profiles = self.data.local.user.get_all_profiles(self.game, self.version)
all_attempts = self.data.local.music.get_all_attempts(self.game, self.version, timelimit=(Time.beginning_of_today() - Time.SECONDS_IN_DAY)) all_attempts = self.data.local.music.get_all_attempts(self.game, self.version, timelimit=(Time.beginning_of_today() - Time.SECONDS_IN_DAY))
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
lids = [ lids = [
machine.id for machine in self.data.local.machine.get_all_machines(machine.arcade) machine.id for machine in self.data.local.machine.get_all_machines(machine.arcade)

View File

@ -81,7 +81,7 @@ class ReflecBeatVolzzaBase(ReflecBeatBase):
all_profiles = self.data.local.user.get_all_profiles(self.game, self.version) all_profiles = self.data.local.user.get_all_profiles(self.game, self.version)
all_attempts = self.data.local.music.get_all_attempts(self.game, self.version, timelimit=(Time.beginning_of_today() - Time.SECONDS_IN_DAY)) all_attempts = self.data.local.music.get_all_attempts(self.game, self.version, timelimit=(Time.beginning_of_today() - Time.SECONDS_IN_DAY))
machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
if machine.arcade is not None: if machine.arcade is not None:
lids = [ lids = [
machine.id for machine in self.data.local.machine.get_all_machines(machine.arcade) machine.id for machine in self.data.local.machine.get_all_machines(machine.arcade)

View File

@ -1,4 +1,4 @@
from typing import Any, Dict, Optional from typing import Optional
from bemani.backend.base import Base, Factory from bemani.backend.base import Base, Factory
from bemani.backend.sdvx.booth import SoundVoltexBooth from bemani.backend.sdvx.booth import SoundVoltexBooth
@ -8,7 +8,7 @@ from bemani.backend.sdvx.gravitywars_s1 import SoundVoltexGravityWarsSeason1
from bemani.backend.sdvx.gravitywars_s2 import SoundVoltexGravityWarsSeason2 from bemani.backend.sdvx.gravitywars_s2 import SoundVoltexGravityWarsSeason2
from bemani.backend.sdvx.heavenlyhaven import SoundVoltexHeavenlyHaven from bemani.backend.sdvx.heavenlyhaven import SoundVoltexHeavenlyHaven
from bemani.common import Model, VersionConstants from bemani.common import Model, VersionConstants
from bemani.data import Data from bemani.data import Config, Data
class SoundVoltexFactory(Factory): class SoundVoltexFactory(Factory):
@ -26,7 +26,7 @@ class SoundVoltexFactory(Factory):
Base.register(gamecode, SoundVoltexFactory) Base.register(gamecode, SoundVoltexFactory)
@classmethod @classmethod
def create(cls, data: Data, config: Dict[str, Any], model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]: def create(cls, data: Data, config: Config, model: Model, parentmodel: Optional[Model]=None) -> Optional[Base]:
def version_from_date(date: int) -> Optional[int]: def version_from_date(date: int) -> Optional[int]:
if date < 2013060500: if date < 2013060500:

View File

@ -1,3 +1,4 @@
from bemani.data.config import Config
from bemani.data.data import Data, DBCreateException from bemani.data.data import Data, DBCreateException
from bemani.data.exceptions import ScoreSaveException from bemani.data.exceptions import ScoreSaveException
from bemani.data.types import User, Achievement, Machine, Arcade, Score, Attempt, News, Link, Song, Event, Server, Client, UserID, ArcadeID from bemani.data.types import User, Achievement, Machine, Arcade, Score, Attempt, News, Link, Song, Event, Server, Client, UserID, ArcadeID
@ -6,6 +7,7 @@ from bemani.data.triggers import Triggers
__all__ = [ __all__ = [
"Config",
"Data", "Data",
"DBCreateException", "DBCreateException",
"ScoreSaveException", "ScoreSaveException",

195
bemani/data/config.py Normal file
View File

@ -0,0 +1,195 @@
import copy
import os
from sqlalchemy.engine import Engine # type: ignore
from typing import Any, Dict, Optional, Set
from bemani.common.constants import GameConstants
from bemani.data.types import ArcadeID
class Database:
def __init__(self, parent_config: "Config") -> None:
self.__config = parent_config
@property
def address(self) -> str:
return str(self.__config.get('database', {}).get('address', 'localhost'))
@property
def database(self) -> str:
return str(self.__config.get('database', {}).get('database', 'bemani'))
@property
def user(self) -> str:
return str(self.__config.get('database', {}).get('user', 'bemani'))
@property
def password(self) -> str:
return str(self.__config.get('database', {}).get('password', 'bemani'))
@property
def engine(self) -> Engine:
engine = self.__config.get('database', {}).get('engine')
if engine is None:
raise Exception("Config object is not instantiated properly, no SQLAlchemy engine present!")
if not isinstance(engine, Engine):
raise Exception("Config object is not instantiated properly, engine property is not a SQLAlchemy Engine!")
return engine
@property
def read_only(self) -> bool:
return bool(self.__config.get('database', {}).get('read_only', False))
class Server:
def __init__(self, parent_config: "Config") -> None:
self.__config = parent_config
@property
def address(self) -> str:
return str(self.__config.get('server', {}).get('address', '127.0.0.1'))
@property
def keepalive(self) -> str:
return str(self.__config.get('server', {}).get('keepalive', self.address))
@property
def port(self) -> int:
return int(self.__config.get('server', {}).get('port', 80))
@property
def https(self) -> bool:
return bool(self.__config.get('server', {}).get('https', False))
@property
def uri(self) -> Optional[str]:
uri = self.__config.get('server', {}).get('uri')
return str(uri) if uri else None
@property
def redirect(self) -> Optional[str]:
redirect = self.__config.get('server', {}).get('redirect')
return str(redirect) if redirect else None
@property
def enforce_pcbid(self) -> bool:
return bool(self.__config.get('server', {}).get('enforce_pcbid', False))
class Client:
def __init__(self, parent_config: "Config") -> None:
self.__config = parent_config
@property
def address(self) -> str:
address = self.__config.get('client', {}).get('address')
if address is None:
raise Exception("Config object is not instantiated properly, no client address present!")
return str(address)
class Machine:
def __init__(self, parent_config: "Config") -> None:
self.__config = parent_config
@property
def pcbid(self) -> str:
pcbid = self.__config.get('machine', {}).get('pcbid')
if pcbid is None:
raise Exception("Config object is not instantiated properly, no machine pcbid present!")
return str(pcbid)
@property
def arcade(self) -> Optional[ArcadeID]:
return self.__config.get('machine', {}).get('arcade')
class PASELI:
def __init__(self, parent_config: "Config") -> None:
self.__config = parent_config
@property
def enabled(self) -> bool:
return bool(self.__config.get('paseli', {}).get('enabled', False))
@property
def infinite(self) -> bool:
return bool(self.__config.get('paseli', {}).get('infinite', False))
class WebHooks:
def __init__(self, parent_config: "Config") -> None:
self.discord = DiscordWebHooks(parent_config)
class DiscordWebHooks:
def __init__(self, parent_config: "Config") -> None:
self.__config = parent_config
def __getitem__(self, key: GameConstants) -> Optional[str]:
uri = self.__config.get('webhooks', {}).get('discord', {}).get(key.value)
return str(uri) if uri else None
class Config(dict):
def __init__(self, existing_contents: Dict[str, Any] = {}) -> None:
super().__init__(existing_contents or {})
self.database = Database(self)
self.server = Server(self)
self.client = Client(self)
self.paseli = PASELI(self)
self.webhooks = WebHooks(self)
self.machine = Machine(self)
def clone(self) -> "Config":
# Somehow its not possible to clone this object if an instantiated Engine is present,
# so we do a little shenanigans here.
engine = self.get('database', {}).get('engine')
if engine is not None:
self['database']['engine'] = None
clone = Config(copy.deepcopy(self))
if engine is not None:
self['database']['engine'] = engine
clone['database']['engine'] = engine
return clone
@property
def filename(self) -> str:
filename = self.get('filename')
if filename is None:
raise Exception("Config object is not instantiated properly, no filename present!")
return os.path.abspath(str(filename))
@property
def support(self) -> Set[GameConstants]:
support = self.get('support')
if support is None:
raise Exception("Config object is not instantiated properly, no support list present!")
if not isinstance(support, set):
raise Exception("Config object is not instantiated properly, support property is not a Set!")
return support
@property
def secret_key(self) -> str:
return str(self.get('secret_key', 'youdidntchangethisatalldidyou?'))
@property
def name(self) -> str:
return str(self.get('name', 'e-AMUSEMENT Network'))
@property
def email(self) -> str:
return str(self.get('email', 'nobody@nowhere.com'))
@property
def cache_dir(self) -> str:
return os.path.abspath(str(self.get('cache_dir', '/tmp')))
@property
def event_log_duration(self) -> Optional[int]:
duration = self.get('event_log_duration')
return int(duration) if duration else None

View File

@ -1,5 +1,4 @@
import os import os
from typing import Dict, Any
import alembic.config # type: ignore import alembic.config # type: ignore
from alembic.migration import MigrationContext # type: ignore from alembic.migration import MigrationContext # type: ignore
@ -14,6 +13,7 @@ from sqlalchemy.exc import ProgrammingError # type: ignore
from bemani.data.api.user import GlobalUserData from bemani.data.api.user import GlobalUserData
from bemani.data.api.game import GlobalGameData from bemani.data.api.game import GlobalGameData
from bemani.data.api.music import GlobalMusicData from bemani.data.api.music import GlobalMusicData
from bemani.data.config import Config
from bemani.data.mysql.base import metadata from bemani.data.mysql.base import metadata
from bemani.data.mysql.user import UserData from bemani.data.mysql.user import UserData
from bemani.data.mysql.music import MusicData from bemani.data.mysql.music import MusicData
@ -86,7 +86,7 @@ class Data:
and storing data. and storing data.
""" """
def __init__(self, config: Dict[str, Any]) -> None: def __init__(self, config: Config) -> None:
""" """
Initializes the data object. Initializes the data object.
@ -95,7 +95,7 @@ class Data:
to initialize an internal DB connection. to initialize an internal DB connection.
""" """
session_factory = sessionmaker( session_factory = sessionmaker(
bind=config['database']['engine'], bind=config.database.engine,
autoflush=True, autoflush=True,
autocommit=True, autocommit=True,
) )
@ -122,11 +122,11 @@ class Data:
self.triggers = Triggers(config) self.triggers = Triggers(config)
@classmethod @classmethod
def sqlalchemy_url(cls, config: Dict[str, Any]) -> str: def sqlalchemy_url(cls, config: Config) -> str:
return f"mysql://{config['database']['user']}:{config['database']['password']}@{config['database']['address']}/{config['database']['database']}?charset=utf8mb4" return f"mysql://{config.database.user}:{config.database.password}@{config.database.address}/{config.database.database}?charset=utf8mb4"
@classmethod @classmethod
def create_engine(cls, config: Dict[str, Any]) -> Engine: def create_engine(cls, config: Config) -> Engine:
return create_engine( return create_engine(
Data.sqlalchemy_url(config), Data.sqlalchemy_url(config),
pool_recycle=3600, pool_recycle=3600,
@ -164,7 +164,7 @@ class Data:
raise DBCreateException('Tables already created, use upgrade to upgrade schema!') raise DBCreateException('Tables already created, use upgrade to upgrade schema!')
metadata.create_all( metadata.create_all(
self.__config['database']['engine'].connect(), self.__config.database.engine.connect(),
checkfirst=True, checkfirst=True,
) )
@ -182,7 +182,7 @@ class Data:
raise DBCreateException('Tables have not been created yet, use create to create them!') raise DBCreateException('Tables have not been created yet, use create to create them!')
# Verify that there are actual changes, and refuse to create empty migration scripts # Verify that there are actual changes, and refuse to create empty migration scripts
context = MigrationContext.configure(self.__config['database']['engine'].connect(), opts={'compare_type': True}) context = MigrationContext.configure(self.__config.database.engine.connect(), opts={'compare_type': True})
diff = compare_metadata(context, metadata) diff = compare_metadata(context, metadata)
if (not allow_empty) and (len(diff) == 0): if (not allow_empty) and (len(diff) == 0):
raise DBCreateException('There is nothing different between code and the DB, refusing to create migration!') raise DBCreateException('There is nothing different between code and the DB, refusing to create migration!')

View File

@ -3,6 +3,7 @@ import random
from typing import Dict, Any, Optional from typing import Dict, Any, Optional
from bemani.common import Time from bemani.common import Time
from bemani.data.config import Config
from sqlalchemy.engine.base import Connection # type: ignore from sqlalchemy.engine.base import Connection # type: ignore
from sqlalchemy.engine import CursorResult # type: ignore from sqlalchemy.engine import CursorResult # type: ignore
@ -39,7 +40,7 @@ class BaseData:
SESSION_LENGTH = 32 SESSION_LENGTH = 32
def __init__(self, config: Dict[str, Any], conn: Connection) -> None: def __init__(self, config: Config, conn: Connection) -> None:
""" """
Initialize any DB singleton. Initialize any DB singleton.
@ -65,7 +66,7 @@ class BaseData:
Returns: Returns:
A SQLAlchemy CursorResult object. A SQLAlchemy CursorResult object.
""" """
if self.__config['database'].get('read_only', False): if self.__config.database.read_only:
# See if this is an insert/update/delete # See if this is an insert/update/delete
for write_statement in [ for write_statement in [
"insert into ", "insert into ",

View File

@ -1,8 +1,9 @@
from datetime import datetime from datetime import datetime
from discord_webhook import DiscordWebhook, DiscordEmbed # type: ignore from discord_webhook import DiscordWebhook, DiscordEmbed # type: ignore
from typing import Any, Dict from typing import Dict
from bemani.common.constants import GameConstants, BroadcastConstants from bemani.common.constants import GameConstants, BroadcastConstants
from bemani.data.config import Config
from bemani.data.types import Song from bemani.data.types import Song
@ -10,7 +11,7 @@ class Triggers:
""" """
Class for broadcasting data to some outside service Class for broadcasting data to some outside service
""" """
def __init__(self, config: Dict[str, Any]): def __init__(self, config: Config) -> None:
self.config = config self.config = config
def __gameconst_to_series(self, game: GameConstants) -> str: def __gameconst_to_series(self, game: GameConstants) -> str:
@ -28,20 +29,20 @@ class Triggers:
def broadcast_score(self, data: Dict[BroadcastConstants, str], game: GameConstants, song: Song) -> None: def broadcast_score(self, data: Dict[BroadcastConstants, str], game: GameConstants, song: Song) -> None:
# For now we only support discord # For now we only support discord
if self.config.get('webhooks', {}).get('discord', {}).get(game, None) is not None: if self.config.webhooks.discord[game] is not None:
self.broadcast_score_discord(data, game, song) self.broadcast_score_discord(data, game, song)
def broadcast_score_discord(self, data: Dict[BroadcastConstants, str], game: GameConstants, song: Song) -> None: def broadcast_score_discord(self, data: Dict[BroadcastConstants, str], game: GameConstants, song: Song) -> None:
if game == GameConstants.IIDX: if game == GameConstants.IIDX:
now = datetime.now() now = datetime.now()
webhook = DiscordWebhook(url=self.config['webhooks']['discord'][game]) webhook = DiscordWebhook(url=self.config.webhooks.discord[game])
scoreembed = DiscordEmbed(title=f'New {self.__gameconst_to_series(game)} Score!', color='fbba08') scoreembed = DiscordEmbed(title=f'New {self.__gameconst_to_series(game)} Score!', color='fbba08')
scoreembed.set_footer(text=(now.strftime('Score was recorded on %m/%d/%y at %H:%M:%S'))) scoreembed.set_footer(text=(now.strftime('Score was recorded on %m/%d/%y at %H:%M:%S')))
# lets give it an author # lets give it an author
song_url = f"{self.config['server']['uri']}/{game}/topscores/{song.id}" if self.config['server']['uri'] is not None else None song_url = f"{self.config.server.uri}/{game.value}/topscores/{song.id}" if self.config.server.uri is not None else None
scoreembed.set_author(name=self.config['name'], url=song_url) scoreembed.set_author(name=self.config.name, url=song_url)
for item, value in data.items(): for item, value in data.items():
inline = True inline = True
if item in {BroadcastConstants.DJ_NAME, BroadcastConstants.SONG_NAME, BroadcastConstants.ARTIST_NAME, BroadcastConstants.PLAY_STATS_HEADER}: if item in {BroadcastConstants.DJ_NAME, BroadcastConstants.SONG_NAME, BroadcastConstants.ARTIST_NAME, BroadcastConstants.PLAY_STATS_HEADER}:

View File

@ -28,7 +28,7 @@ def login() -> Response:
return Response(render_template('account/login.html', **{'title': 'Log In', 'show_navigation': False, 'username': username})) return Response(render_template('account/login.html', **{'title': 'Log In', 'show_navigation': False, 'username': username}))
if g.data.local.user.validate_password(userid, password): if g.data.local.user.validate_password(userid, password):
aes = AESCipher(g.config['secret_key']) aes = AESCipher(g.config.secret_key)
sessionID = g.data.local.user.create_session(userid, expiration=90 * 86400) sessionID = g.data.local.user.create_session(userid, expiration=90 * 86400)
response = make_response(redirect(url_for('home_pages.viewhome'))) response = make_response(redirect(url_for('home_pages.viewhome')))
response.set_cookie( response.set_cookie(
@ -127,7 +127,7 @@ def register() -> Response:
g.data.local.user.update_password(userid, password1) g.data.local.user.update_password(userid, password1)
# Now, log them into that created account! # Now, log them into that created account!
aes = AESCipher(g.config['secret_key']) aes = AESCipher(g.config.secret_key)
sessionID = g.data.local.user.create_session(userid) sessionID = g.data.local.user.create_session(userid)
success('Successfully registered account!') success('Successfully registered account!')
response = make_response(redirect(url_for('home_pages.viewhome'))) response = make_response(redirect(url_for('home_pages.viewhome')))

View File

@ -156,9 +156,9 @@ def viewevents() -> Response:
'refresh': url_for('admin_pages.listevents', since=-1), 'refresh': url_for('admin_pages.listevents', since=-1),
'backfill': url_for('admin_pages.backfillevents', until=-1), 'backfill': url_for('admin_pages.backfillevents', until=-1),
'viewuser': url_for('admin_pages.viewuser', userid=-1), 'viewuser': url_for('admin_pages.viewuser', userid=-1),
'jubeatsong': url_for('jubeat_pages.viewtopscores', musicid=-1) if GameConstants.JUBEAT in g.config['support'] else None, 'jubeatsong': url_for('jubeat_pages.viewtopscores', musicid=-1) if GameConstants.JUBEAT in g.config.support else None,
'iidxsong': url_for('iidx_pages.viewtopscores', musicid=-1) if GameConstants.IIDX in g.config['support'] else None, 'iidxsong': url_for('iidx_pages.viewtopscores', musicid=-1) if GameConstants.IIDX in g.config.support else None,
'pnmsong': url_for('popn_pages.viewtopscores', musicid=-1) if GameConstants.POPN_MUSIC in g.config['support'] else None, 'pnmsong': url_for('popn_pages.viewtopscores', musicid=-1) if GameConstants.POPN_MUSIC in g.config.support else None,
}, },
) )
@ -214,8 +214,8 @@ def viewarcades() -> Response:
{ {
'arcades': [format_arcade(arcade) for arcade in g.data.local.machine.get_all_arcades()], 'arcades': [format_arcade(arcade) for arcade in g.data.local.machine.get_all_arcades()],
'usernames': g.data.local.user.get_all_usernames(), 'usernames': g.data.local.user.get_all_usernames(),
'paseli_enabled': g.config['paseli']['enabled'], 'paseli_enabled': g.config.paseli.enabled,
'paseli_infinite': g.config['paseli']['infinite'], 'paseli_infinite': g.config.paseli.infinite,
'mask_services_url': False, 'mask_services_url': False,
}, },
{ {
@ -252,7 +252,7 @@ def viewmachines() -> Response:
GameConstants.SDVX.value: 'SDVX', GameConstants.SDVX.value: 'SDVX',
}, },
'games': games, 'games': games,
'enforcing': g.config['server']['enforce_pcbid'], 'enforcing': g.config.server.enforce_pcbid,
}, },
{ {
'generatepcbid': url_for('admin_pages.generatepcbid'), 'generatepcbid': url_for('admin_pages.generatepcbid'),

View File

@ -8,7 +8,7 @@ from flask_caching import Cache # type: ignore
from functools import wraps from functools import wraps
from bemani.common import AESCipher, GameConstants from bemani.common import AESCipher, GameConstants
from bemani.data import Data from bemani.data import Config, Data
from bemani.frontend.types import g from bemani.frontend.types import g
from bemani.frontend.templates import templates_location from bemani.frontend.templates import templates_location
from bemani.frontend.static import static_location from bemani.frontend.static import static_location
@ -18,7 +18,7 @@ app = Flask(
template_folder=templates_location, template_folder=templates_location,
static_folder=static_location, static_folder=static_location,
) )
config: Dict[str, Any] = {} config = Config()
@app.before_request @app.before_request
@ -26,7 +26,7 @@ def before_request() -> None:
global config global config
g.cache = Cache(app, config={ g.cache = Cache(app, config={
'CACHE_TYPE': 'filesystem', 'CACHE_TYPE': 'filesystem',
'CACHE_DIR': config['cache_dir'], 'CACHE_DIR': config.cache_dir,
}) })
if request.endpoint in ['jsx', 'static']: if request.endpoint in ['jsx', 'static']:
# This is just serving cached compiled frontends, skip loading from DB # This is just serving cached compiled frontends, skip loading from DB
@ -37,7 +37,7 @@ def before_request() -> None:
g.sessionID = None g.sessionID = None
g.userID = None g.userID = None
try: try:
aes = AESCipher(config['secret_key']) aes = AESCipher(config.secret_key)
sessionID = aes.decrypt(request.cookies.get('SessionID')) sessionID = aes.decrypt(request.cookies.get('SessionID'))
except Exception: except Exception:
sessionID = None sessionID = None
@ -254,14 +254,24 @@ def navigation() -> Dict[str, Any]:
return False return False
# Look up the logged in user ID. # Look up the logged in user ID.
if g.userID is not None: try:
user = g.data.local.user.get_user(g.userID) if g.userID is not None:
profiles = g.data.local.user.get_games_played(g.userID) user = g.data.local.user.get_user(g.userID)
else: profiles = g.data.local.user.get_games_played(g.userID)
else:
return {
'components': components,
'any': jinja2_any,
}
except AttributeError:
# If we are trying to render a 500 error and we couldn't even run the
# before request, we won't have a userID object on g. So, just give
# up and refuse to render any navigation.
return { return {
'components': components, 'components': components,
'any': jinja2_any, 'any': jinja2_any,
} }
pages: List[Dict[str, Any]] = [] pages: List[Dict[str, Any]] = []
# Landing page # Landing page
@ -272,7 +282,7 @@ def navigation() -> Dict[str, Any]:
}, },
) )
if GameConstants.BISHI_BASHI in g.config['support']: if GameConstants.BISHI_BASHI in g.config.support:
# BishiBashi pages # BishiBashi pages
bishi_entries = [] bishi_entries = []
if len([p for p in profiles if p[0] == GameConstants.BISHI_BASHI]) > 0: if len([p for p in profiles if p[0] == GameConstants.BISHI_BASHI]) > 0:
@ -301,7 +311,7 @@ def navigation() -> Dict[str, Any]:
}, },
) )
if GameConstants.DDR in g.config['support']: if GameConstants.DDR in g.config.support:
# DDR pages # DDR pages
ddr_entries = [] ddr_entries = []
if len([p for p in profiles if p[0] == GameConstants.DDR]) > 0: if len([p for p in profiles if p[0] == GameConstants.DDR]) > 0:
@ -350,7 +360,7 @@ def navigation() -> Dict[str, Any]:
}, },
) )
if GameConstants.IIDX in g.config['support']: if GameConstants.IIDX in g.config.support:
# IIDX pages # IIDX pages
iidx_entries = [] iidx_entries = []
if len([p for p in profiles if p[0] == GameConstants.IIDX]) > 0: if len([p for p in profiles if p[0] == GameConstants.IIDX]) > 0:
@ -399,7 +409,7 @@ def navigation() -> Dict[str, Any]:
}, },
) )
if GameConstants.JUBEAT in g.config['support']: if GameConstants.JUBEAT in g.config.support:
# Jubeat pages # Jubeat pages
jubeat_entries = [] jubeat_entries = []
if len([p for p in profiles if p[0] == GameConstants.JUBEAT]) > 0: if len([p for p in profiles if p[0] == GameConstants.JUBEAT]) > 0:
@ -448,7 +458,7 @@ def navigation() -> Dict[str, Any]:
}, },
) )
if GameConstants.MUSECA in g.config['support']: if GameConstants.MUSECA in g.config.support:
# Museca pages # Museca pages
museca_entries = [] museca_entries = []
if len([p for p in profiles if p[0] == GameConstants.MUSECA]) > 0: if len([p for p in profiles if p[0] == GameConstants.MUSECA]) > 0:
@ -493,7 +503,7 @@ def navigation() -> Dict[str, Any]:
}, },
) )
if GameConstants.POPN_MUSIC in g.config['support']: if GameConstants.POPN_MUSIC in g.config.support:
# Pop'n Music pages # Pop'n Music pages
popn_entries = [] popn_entries = []
if len([p for p in profiles if p[0] == GameConstants.POPN_MUSIC]) > 0: if len([p for p in profiles if p[0] == GameConstants.POPN_MUSIC]) > 0:
@ -542,7 +552,7 @@ def navigation() -> Dict[str, Any]:
}, },
) )
if GameConstants.REFLEC_BEAT in g.config['support']: if GameConstants.REFLEC_BEAT in g.config.support:
# ReflecBeat pages # ReflecBeat pages
reflec_entries = [] reflec_entries = []
if len([p for p in profiles if p[0] == GameConstants.REFLEC_BEAT]) > 0: if len([p for p in profiles if p[0] == GameConstants.REFLEC_BEAT]) > 0:
@ -591,7 +601,7 @@ def navigation() -> Dict[str, Any]:
}, },
) )
if GameConstants.SDVX in g.config['support']: if GameConstants.SDVX in g.config.support:
# SDVX pages # SDVX pages
sdvx_entries = [] sdvx_entries = []
if len([p for p in profiles if p[0] == GameConstants.SDVX]) > 0: if len([p for p in profiles if p[0] == GameConstants.SDVX]) > 0:

View File

@ -153,7 +153,7 @@ def viewarcade(arcadeid: int) -> Response:
'balances': {balance[0]: balance[1] for balance in g.data.local.machine.get_balances(arcadeid)}, 'balances': {balance[0]: balance[1] for balance in g.data.local.machine.get_balances(arcadeid)},
'users': {user.id: user.username for user in g.data.local.user.get_all_users()}, 'users': {user.id: user.username for user in g.data.local.user.get_all_users()},
'events': [format_event(event) for event in g.data.local.network.get_events(arcadeid=arcadeid, event='paseli_transaction')], 'events': [format_event(event) for event in g.data.local.network.get_events(arcadeid=arcadeid, event='paseli_transaction')],
'enforcing': g.config['server']['enforce_pcbid'], 'enforcing': g.config.server.enforce_pcbid,
}, },
{ {
'refresh': url_for('arcade_pages.listarcade', arcadeid=arcadeid), 'refresh': url_for('arcade_pages.listarcade', arcadeid=arcadeid),

View File

@ -1,10 +1,8 @@
from typing import Dict, Any from bemani.data import Config, Data
from bemani.data import Data
class BishiBashiCache: class BishiBashiCache:
@classmethod @classmethod
def preload(cls, data: Data, config: Dict[str, Any]) -> None: def preload(cls, data: Data, config: Config) -> None:
pass pass

View File

@ -1,8 +1,6 @@
from typing import Dict, Any
from flask_caching import Cache # type: ignore from flask_caching import Cache # type: ignore
from bemani.data import Data from bemani.data import Config, Data
from bemani.frontend.app import app from bemani.frontend.app import app
from bemani.frontend.ddr.ddr import DDRFrontend from bemani.frontend.ddr.ddr import DDRFrontend
@ -10,10 +8,10 @@ from bemani.frontend.ddr.ddr import DDRFrontend
class DDRCache: class DDRCache:
@classmethod @classmethod
def preload(cls, data: Data, config: Dict[str, Any]) -> None: def preload(cls, data: Data, config: Config) -> None:
cache = Cache(app, config={ cache = Cache(app, config={
'CACHE_TYPE': 'filesystem', 'CACHE_TYPE': 'filesystem',
'CACHE_DIR': config['cache_dir'], 'CACHE_DIR': config.cache_dir,
}) })
frontend = DDRFrontend(data, config, cache) frontend = DDRFrontend(data, config, cache)
frontend.get_all_songs(force_db_load=True) frontend.get_all_songs(force_db_load=True)

View File

@ -1,8 +1,6 @@
from typing import Dict, Any
from flask_caching import Cache # type: ignore from flask_caching import Cache # type: ignore
from bemani.data import Data from bemani.data import Config, Data
from bemani.frontend.app import app from bemani.frontend.app import app
from bemani.frontend.iidx.iidx import IIDXFrontend from bemani.frontend.iidx.iidx import IIDXFrontend
@ -10,10 +8,10 @@ from bemani.frontend.iidx.iidx import IIDXFrontend
class IIDXCache: class IIDXCache:
@classmethod @classmethod
def preload(cls, data: Data, config: Dict[str, Any]) -> None: def preload(cls, data: Data, config: Config) -> None:
cache = Cache(app, config={ cache = Cache(app, config={
'CACHE_TYPE': 'filesystem', 'CACHE_TYPE': 'filesystem',
'CACHE_DIR': config['cache_dir'], 'CACHE_DIR': config.cache_dir,
}) })
frontend = IIDXFrontend(data, config, cache) frontend = IIDXFrontend(data, config, cache)
frontend.get_all_songs(force_db_load=True) frontend.get_all_songs(force_db_load=True)

View File

@ -1,8 +1,6 @@
from typing import Dict, Any
from flask_caching import Cache # type: ignore from flask_caching import Cache # type: ignore
from bemani.data import Data from bemani.data import Config, Data
from bemani.frontend.app import app from bemani.frontend.app import app
from bemani.frontend.jubeat.jubeat import JubeatFrontend from bemani.frontend.jubeat.jubeat import JubeatFrontend
@ -10,10 +8,10 @@ from bemani.frontend.jubeat.jubeat import JubeatFrontend
class JubeatCache: class JubeatCache:
@classmethod @classmethod
def preload(cls, data: Data, config: Dict[str, Any]) -> None: def preload(cls, data: Data, config: Config) -> None:
cache = Cache(app, config={ cache = Cache(app, config={
'CACHE_TYPE': 'filesystem', 'CACHE_TYPE': 'filesystem',
'CACHE_DIR': config['cache_dir'], 'CACHE_DIR': config.cache_dir,
}) })
frontend = JubeatFrontend(data, config, cache) frontend = JubeatFrontend(data, config, cache)
frontend.get_all_songs(force_db_load=True) frontend.get_all_songs(force_db_load=True)

View File

@ -1,8 +1,6 @@
from typing import Dict, Any
from flask_caching import Cache # type: ignore from flask_caching import Cache # type: ignore
from bemani.data import Data from bemani.data import Config, Data
from bemani.frontend.app import app from bemani.frontend.app import app
from bemani.frontend.museca.museca import MusecaFrontend from bemani.frontend.museca.museca import MusecaFrontend
@ -10,10 +8,10 @@ from bemani.frontend.museca.museca import MusecaFrontend
class MusecaCache: class MusecaCache:
@classmethod @classmethod
def preload(cls, data: Data, config: Dict[str, Any]) -> None: def preload(cls, data: Data, config: Config) -> None:
cache = Cache(app, config={ cache = Cache(app, config={
'CACHE_TYPE': 'filesystem', 'CACHE_TYPE': 'filesystem',
'CACHE_DIR': config['cache_dir'], 'CACHE_DIR': config.cache_dir,
}) })
frontend = MusecaFrontend(data, config, cache) frontend = MusecaFrontend(data, config, cache)
frontend.get_all_songs(force_db_load=True) frontend.get_all_songs(force_db_load=True)

View File

@ -1,8 +1,6 @@
from typing import Dict, Any
from flask_caching import Cache # type: ignore from flask_caching import Cache # type: ignore
from bemani.data import Data from bemani.data import Config, Data
from bemani.frontend.app import app from bemani.frontend.app import app
from bemani.frontend.popn.popn import PopnMusicFrontend from bemani.frontend.popn.popn import PopnMusicFrontend
@ -10,10 +8,10 @@ from bemani.frontend.popn.popn import PopnMusicFrontend
class PopnMusicCache: class PopnMusicCache:
@classmethod @classmethod
def preload(cls, data: Data, config: Dict[str, Any]) -> None: def preload(cls, data: Data, config: Config) -> None:
cache = Cache(app, config={ cache = Cache(app, config={
'CACHE_TYPE': 'filesystem', 'CACHE_TYPE': 'filesystem',
'CACHE_DIR': config['cache_dir'], 'CACHE_DIR': config.cache_dir,
}) })
frontend = PopnMusicFrontend(data, config, cache) frontend = PopnMusicFrontend(data, config, cache)
frontend.get_all_songs(force_db_load=True) frontend.get_all_songs(force_db_load=True)

View File

@ -1,8 +1,6 @@
from typing import Dict, Any
from flask_caching import Cache # type: ignore from flask_caching import Cache # type: ignore
from bemani.data import Data from bemani.data import Config, Data
from bemani.frontend.app import app from bemani.frontend.app import app
from bemani.frontend.reflec.reflec import ReflecBeatFrontend from bemani.frontend.reflec.reflec import ReflecBeatFrontend
@ -10,10 +8,10 @@ from bemani.frontend.reflec.reflec import ReflecBeatFrontend
class ReflecBeatCache: class ReflecBeatCache:
@classmethod @classmethod
def preload(cls, data: Data, config: Dict[str, Any]) -> None: def preload(cls, data: Data, config: Config) -> None:
cache = Cache(app, config={ cache = Cache(app, config={
'CACHE_TYPE': 'filesystem', 'CACHE_TYPE': 'filesystem',
'CACHE_DIR': config['cache_dir'], 'CACHE_DIR': config.cache_dir,
}) })
frontend = ReflecBeatFrontend(data, config, cache) frontend = ReflecBeatFrontend(data, config, cache)
frontend.get_all_songs(force_db_load=True) frontend.get_all_songs(force_db_load=True)

View File

@ -1,8 +1,6 @@
from typing import Dict, Any
from flask_caching import Cache # type: ignore from flask_caching import Cache # type: ignore
from bemani.data import Data from bemani.data import Config, Data
from bemani.frontend.app import app from bemani.frontend.app import app
from bemani.frontend.sdvx.sdvx import SoundVoltexFrontend from bemani.frontend.sdvx.sdvx import SoundVoltexFrontend
@ -10,10 +8,10 @@ from bemani.frontend.sdvx.sdvx import SoundVoltexFrontend
class SoundVoltexCache: class SoundVoltexCache:
@classmethod @classmethod
def preload(cls, data: Data, config: Dict[str, Any]) -> None: def preload(cls, data: Data, config: Config) -> None:
cache = Cache(app, config={ cache = Cache(app, config={
'CACHE_TYPE': 'filesystem', 'CACHE_TYPE': 'filesystem',
'CACHE_DIR': config['cache_dir'], 'CACHE_DIR': config.cache_dir,
}) })
frontend = SoundVoltexFrontend(data, config, cache) frontend = SoundVoltexFrontend(data, config, cache)
frontend.get_all_songs(force_db_load=True) frontend.get_all_songs(force_db_load=True)

View File

@ -1,17 +1,17 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<div class="section"> <div class="section">
To change any of these settings, edit <span class="file">server.yaml</span>. To change any of these settings, edit <span class="file">{{ config.filename }}</span>.
</div> </div>
<div class="section"> <div class="section">
<h3>Database Settings</h3> <h3>Database Settings</h3>
<dl> <dl>
<dt>Host</dt> <dt>Host</dt>
<dd>{{ config['database']['address'] }}</dd> <dd>{{ config.database.address }}</dd>
<dt>Database</dt> <dt>Database</dt>
<dd>{{ config['database']['database'] }}</dd> <dd>{{ config.database.database }}</dd>
<dt>User</dt> <dt>User</dt>
<dd>{{ config['database']['user'] }}</dd> <dd>{{ config.database.user }}</dd>
<dt>Password</dt> <dt>Password</dt>
<dd>&bull;&bull;&bull;&bull;&bull;&bull;</dd> <dd>&bull;&bull;&bull;&bull;&bull;&bull;</dd>
</dl> </dl>
@ -20,44 +20,51 @@
<h3>Backend Settings</h3> <h3>Backend Settings</h3>
<dl> <dl>
<dt>Host</dt> <dt>Host</dt>
<dd>{{ config['server']['address'] }}</dd> <dd>{{ config.server.address }}</dd>
<dt>Port</dt> <dt>Port</dt>
<dd>{{ config['server']['port'] }}</dd> <dd>{{ config.server.port }}</dd>
<dt>HTTPS</dt> <dt>HTTPS</dt>
<dd>{{ 'active' if config['server']['https'] else 'inactive' }}</dd> <dd>{{ 'active' if config.server.https else 'inactive' }}</dd>
<dt>Keepalive Address</dt> <dt>Keepalive Address</dt>
<dd>{{ config['server']['keepalive'] }}</dd> <dd>{{ config.server.keepalive }}</dd>
<dt>HTTP Get Redirect Address</dt> <dt>HTTP Get Redirect Address</dt>
<dd>{{ config['server']['redirect'] if config['server']['redirect'] else 'disabled' }}</dd> <dd>{{ config.server.redirect or 'disabled' }}</dd>
</dl>
</div>
<div class="section">
<h3>Cache Settings</h3>
<dl>
<dt>Cache Directory</dt>
<dd>{{ config.cache_dir }}</dd>
</dl> </dl>
</div> </div>
<div class="section"> <div class="section">
<h3>Frontend Settings</h3> <h3>Frontend Settings</h3>
<dl> <dl>
<dt>Web Address</dt> <dt>Web Address</dt>
<dd>{{ config['server']['uri'] if config['server']['uri'] else 'http://eagate.573.jp' }}</dd> <dd>{{ config.server.uri or 'http://eagate.573.jp' }}</dd>
<dt>Network Name</dt> <dt>Network Name</dt>
<dd>{{ config.get('name','e-AMUSEMENT Network') }}</dd> <dd>{{ config.name }}</dd>
</dl> </dl>
</div> </div>
<div class="section"> <div class="section">
<h3>Data Exchange API Settings</h3> <h3>Data Exchange API Settings</h3>
<dl> <dl>
<dt>Administrative Email</dt> <dt>Administrative Email</dt>
<dd>{{ config.get('email','nobody@nowhere.com') }}</dd> <dd>{{ config.email }}</dd>
</dl> </dl>
</div> </div>
<div class="section"> <div class="section">
<h3>Server Settings</h3> <h3>Server Settings</h3>
<dl> <dl>
<dt>PCBID Enforcement</dt> <dt>PCBID Enforcement</dt>
<dd>{{ 'active' if config['server']['enforce_pcbid'] else 'inactive' }}</dd> <dd>{{ 'active' if config.server.enforce_pcbid else 'inactive' }}</dd>
<dt>PASELI Enabled</dt> <dt>PASELI Enabled</dt>
<dd>{{ 'yes' if config['paseli']['enabled'] else 'no' }} (can be overridden by arcade settings)</dd> <dd>{{ 'yes' if config.paseli.enabled else 'no' }} (can be overridden by arcade settings)</dd>
<dt>Infinite PASELI Enabled</dt> <dt>Infinite PASELI Enabled</dt>
<dd>{{ 'yes' if config['paseli']['infinite'] else 'no' }} (can be overridden by arcade settings)</dd> <dd>{{ 'yes' if config.paseli.infinite else 'no' }} (can be overridden by arcade settings)</dd>
<dt>Event Log Preservation Duration</dt> <dt>Event Log Preservation Duration</dt>
<dd>{{ (config['event_log_duration']|string + ' seconds') if config['event_log_duration'] else 'infinite' }}</dd> <dd>{{ (config.event_log_duration|string + ' seconds') if config.event_log_duration else 'infinite' }}</dd>
</dl> </dl>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,14 +1,14 @@
from typing import Any, Dict, Optional, TYPE_CHECKING from typing import Optional, TYPE_CHECKING
if TYPE_CHECKING: if TYPE_CHECKING:
from flask.ctx import _AppCtxGlobals from flask.ctx import _AppCtxGlobals
from flask_caching import Cache # type: ignore from flask_caching import Cache # type: ignore
from bemani.data import Data, UserID from bemani.data import Config, Data, UserID
class RequestGlobals(_AppCtxGlobals): class RequestGlobals(_AppCtxGlobals):
config: Dict[str, Any] config: Config
cache: Cache cache: Cache
data: Data data: Data
sessionID: Optional[str] sessionID: Optional[str]

View File

@ -1,5 +1,6 @@
# vim: set fileencoding=utf-8 # vim: set fileencoding=utf-8
import unittest import unittest
from unittest.mock import Mock
from bemani.data.mysql.base import BaseData from bemani.data.mysql.base import BaseData
@ -7,7 +8,7 @@ from bemani.data.mysql.base import BaseData
class TestBaseData(unittest.TestCase): class TestBaseData(unittest.TestCase):
def test_basic_serialize(self) -> None: def test_basic_serialize(self) -> None:
data = BaseData({}, None) data = BaseData(Mock(), None)
testdict = { testdict = {
'test1': 1, 'test1': 1,
@ -23,7 +24,7 @@ class TestBaseData(unittest.TestCase):
self.assertEqual(data.deserialize(data.serialize(testdict)), testdict) self.assertEqual(data.deserialize(data.serialize(testdict)), testdict)
def test_basic_byte_serialize(self) -> None: def test_basic_byte_serialize(self) -> None:
data = BaseData({}, None) data = BaseData(Mock(), None)
testdict = { testdict = {
'bytes': b'\x01\x02\x03\x04\x05', 'bytes': b'\x01\x02\x03\x04\x05',
@ -34,7 +35,7 @@ class TestBaseData(unittest.TestCase):
self.assertEqual(data.deserialize(serialized), testdict) self.assertEqual(data.deserialize(serialized), testdict)
def test_deep_byte_serialize(self) -> None: def test_deep_byte_serialize(self) -> None:
data = BaseData({}, None) data = BaseData(Mock(), None)
testdict = { testdict = {
'sentinal': True, 'sentinal': True,

View File

@ -10,7 +10,7 @@ from bemani.tests.helpers import FakeCursor
class TestGameData(unittest.TestCase): class TestGameData(unittest.TestCase):
def test_put_time_sensitive_settings(self) -> None: def test_put_time_sensitive_settings(self) -> None:
game = GameData({}, None) game = GameData(Mock(), None)
# Verify that we catch incorrect input order # Verify that we catch incorrect input order
with self.assertRaises(Exception) as context: with self.assertRaises(Exception) as context:

View File

@ -27,14 +27,14 @@ class TestIIDXPendual(unittest.TestCase):
) )
def test_average_no_scores(self) -> None: def test_average_no_scores(self) -> None:
base = IIDXPendual(Mock(), {}, Mock()) base = IIDXPendual(Mock(), Mock(), Mock())
self.assertEqual( self.assertEqual(
base.delta_score([], 3), base.delta_score([], 3),
(None, None), (None, None),
) )
def test_average_identity(self) -> None: def test_average_identity(self) -> None:
base = IIDXPendual(Mock(), {}, Mock()) base = IIDXPendual(Mock(), Mock(), Mock())
self.assertEqual( self.assertEqual(
base.delta_score([ base.delta_score([
self.__make_score([10, 20, 30]), self.__make_score([10, 20, 30]),
@ -43,7 +43,7 @@ class TestIIDXPendual(unittest.TestCase):
) )
def test_average_basic(self) -> None: def test_average_basic(self) -> None:
base = IIDXPendual(Mock(), {}, Mock()) base = IIDXPendual(Mock(), Mock(), Mock())
self.assertEqual( self.assertEqual(
base.delta_score([ base.delta_score([
self.__make_score([10, 20, 30]), self.__make_score([10, 20, 30]),
@ -53,7 +53,7 @@ class TestIIDXPendual(unittest.TestCase):
) )
def test_average_complex(self) -> None: def test_average_complex(self) -> None:
base = IIDXPendual(Mock(), {}, Mock()) base = IIDXPendual(Mock(), Mock(), Mock())
self.assertEqual( self.assertEqual(
base.delta_score([ base.delta_score([
self.__make_score([10, 20, 30]), self.__make_score([10, 20, 30]),
@ -64,7 +64,7 @@ class TestIIDXPendual(unittest.TestCase):
) )
def test_average_always_zero(self) -> None: def test_average_always_zero(self) -> None:
base = IIDXPendual(Mock(), {}, Mock()) base = IIDXPendual(Mock(), Mock(), Mock())
ex_score, ghost = base.delta_score([ ex_score, ghost = base.delta_score([
self.__make_score([random.randint(0, 10) for _ in range(64)]), self.__make_score([random.randint(0, 10) for _ in range(64)]),
self.__make_score([random.randint(0, 10) for _ in range(64)]), self.__make_score([random.randint(0, 10) for _ in range(64)]),

View File

@ -11,7 +11,7 @@ from bemani.tests.helpers import FakeCursor
class TestNetworkData(unittest.TestCase): class TestNetworkData(unittest.TestCase):
def test_get_schedule_type(self) -> None: def test_get_schedule_type(self) -> None:
network = NetworkData({}, None) network = NetworkData(Mock(), None)
with freeze_time('2016-01-01 12:00'): with freeze_time('2016-01-01 12:00'):
# Check daily schedule # Check daily schedule
@ -29,7 +29,7 @@ class TestNetworkData(unittest.TestCase):
) )
def test_should_schedule(self) -> None: def test_should_schedule(self) -> None:
network = NetworkData({}, None) network = NetworkData(Mock(), None)
with freeze_time('2016-01-01'): with freeze_time('2016-01-01'):
# Check for should schedule if nothing in DB # Check for should schedule if nothing in DB

View File

@ -1,5 +1,5 @@
import yaml import yaml
from typing import Any, Dict, Set from typing import Set
from bemani.backend.iidx import IIDXFactory from bemani.backend.iidx import IIDXFactory
from bemani.backend.popn import PopnMusicFactory from bemani.backend.popn import PopnMusicFactory
@ -10,12 +10,13 @@ from bemani.backend.sdvx import SoundVoltexFactory
from bemani.backend.reflec import ReflecBeatFactory from bemani.backend.reflec import ReflecBeatFactory
from bemani.backend.museca import MusecaFactory from bemani.backend.museca import MusecaFactory
from bemani.common import GameConstants from bemani.common import GameConstants
from bemani.data import Data from bemani.data import Config, Data
def load_config(filename: str, config: Dict[str, Any]) -> None: def load_config(filename: str, config: Config) -> None:
config.update(yaml.safe_load(open(filename))) config.update(yaml.safe_load(open(filename)))
config['database']['engine'] = Data.create_engine(config) config['database']['engine'] = Data.create_engine(config)
config['filename'] = filename
supported_series: Set[GameConstants] = set() supported_series: Set[GameConstants] = set()
for series in GameConstants: for series in GameConstants:
@ -24,20 +25,20 @@ def load_config(filename: str, config: Dict[str, Any]) -> None:
config['support'] = supported_series config['support'] = supported_series
def register_games(config: Dict[str, Any]) -> None: def register_games(config: Config) -> None:
if GameConstants.POPN_MUSIC in config['support']: if GameConstants.POPN_MUSIC in config.support:
PopnMusicFactory.register_all() PopnMusicFactory.register_all()
if GameConstants.JUBEAT in config['support']: if GameConstants.JUBEAT in config.support:
JubeatFactory.register_all() JubeatFactory.register_all()
if GameConstants.IIDX in config['support']: if GameConstants.IIDX in config.support:
IIDXFactory.register_all() IIDXFactory.register_all()
if GameConstants.BISHI_BASHI in config['support']: if GameConstants.BISHI_BASHI in config.support:
BishiBashiFactory.register_all() BishiBashiFactory.register_all()
if GameConstants.DDR in config['support']: if GameConstants.DDR in config.support:
DDRFactory.register_all() DDRFactory.register_all()
if GameConstants.SDVX in config['support']: if GameConstants.SDVX in config.support:
SoundVoltexFactory.register_all() SoundVoltexFactory.register_all()
if GameConstants.REFLEC_BEAT in config['support']: if GameConstants.REFLEC_BEAT in config.support:
ReflecBeatFactory.register_all() ReflecBeatFactory.register_all()
if GameConstants.MUSECA in config['support']: if GameConstants.MUSECA in config.support:
MusecaFactory.register_all() MusecaFactory.register_all()

View File

@ -1,19 +1,19 @@
import argparse import argparse
import getpass import getpass
import sys import sys
from typing import Any, Dict, Optional from typing import Optional
from bemani.data import Data, DBCreateException from bemani.data import Config, Data, DBCreateException
from bemani.utils.config import load_config from bemani.utils.config import load_config
def create(config: Dict[str, Any]) -> None: def create(config: Config) -> None:
data = Data(config) data = Data(config)
data.create() data.create()
data.close() data.close()
def generate(config: Dict[str, Any], message: Optional[str], allow_empty: bool) -> None: def generate(config: Config, message: Optional[str], allow_empty: bool) -> None:
if message is None: if message is None:
raise Exception('Please provide a message!') raise Exception('Please provide a message!')
data = Data(config) data = Data(config)
@ -21,13 +21,13 @@ def generate(config: Dict[str, Any], message: Optional[str], allow_empty: bool)
data.close() data.close()
def upgrade(config: Dict[str, Any]) -> None: def upgrade(config: Config) -> None:
data = Data(config) data = Data(config)
data.upgrade() data.upgrade()
data.close() data.close()
def change_password(config: Dict[str, Any], username: Optional[str]) -> None: def change_password(config: Config, username: Optional[str]) -> None:
if username is None: if username is None:
raise Exception('Please provide a username!') raise Exception('Please provide a username!')
password1 = getpass.getpass('Password: ') password1 = getpass.getpass('Password: ')
@ -42,7 +42,7 @@ def change_password(config: Dict[str, Any], username: Optional[str]) -> None:
print(f'User {username} changed password.') print(f'User {username} changed password.')
def add_admin(config: Dict[str, Any], username: Optional[str]) -> None: def add_admin(config: Config, username: Optional[str]) -> None:
if username is None: if username is None:
raise Exception('Please provide a username!') raise Exception('Please provide a username!')
data = Data(config) data = Data(config)
@ -55,7 +55,7 @@ def add_admin(config: Dict[str, Any], username: Optional[str]) -> None:
print(f'User {username} gained admin rights.') print(f'User {username} gained admin rights.')
def remove_admin(config: Dict[str, Any], username: Optional[str]) -> None: def remove_admin(config: Config, username: Optional[str]) -> None:
if username is None: if username is None:
raise Exception('Please provide a username!') raise Exception('Please provide a username!')
data = Data(config) data = Data(config)
@ -96,7 +96,7 @@ def main() -> None:
parser.add_argument("-c", "--config", help="Core configuration. Defaults to server.yaml", type=str, default="server.yaml") parser.add_argument("-c", "--config", help="Core configuration. Defaults to server.yaml", type=str, default="server.yaml")
args = parser.parse_args() args = parser.parse_args()
config: Dict[str, Any] = {} config = Config()
load_config(args.config, config) load_config(args.config, config)
try: try:

View File

@ -25,21 +25,21 @@ def register_blueprints() -> None:
app.register_blueprint(arcade_pages) app.register_blueprint(arcade_pages)
app.register_blueprint(home_pages) app.register_blueprint(home_pages)
if GameConstants.IIDX in config['support']: if GameConstants.IIDX in config.support:
app.register_blueprint(iidx_pages) app.register_blueprint(iidx_pages)
if GameConstants.POPN_MUSIC in config['support']: if GameConstants.POPN_MUSIC in config.support:
app.register_blueprint(popn_pages) app.register_blueprint(popn_pages)
if GameConstants.JUBEAT in config['support']: if GameConstants.JUBEAT in config.support:
app.register_blueprint(jubeat_pages) app.register_blueprint(jubeat_pages)
if GameConstants.BISHI_BASHI in config['support']: if GameConstants.BISHI_BASHI in config.support:
app.register_blueprint(bishi_pages) app.register_blueprint(bishi_pages)
if GameConstants.DDR in config['support']: if GameConstants.DDR in config.support:
app.register_blueprint(ddr_pages) app.register_blueprint(ddr_pages)
if GameConstants.SDVX in config['support']: if GameConstants.SDVX in config.support:
app.register_blueprint(sdvx_pages) app.register_blueprint(sdvx_pages)
if GameConstants.REFLEC_BEAT in config['support']: if GameConstants.REFLEC_BEAT in config.support:
app.register_blueprint(reflec_pages) app.register_blueprint(reflec_pages)
if GameConstants.MUSECA in config['support']: if GameConstants.MUSECA in config.support:
app.register_blueprint(museca_pages) app.register_blueprint(museca_pages)
@ -51,7 +51,7 @@ def register_games() -> None:
def load_config(filename: str) -> None: def load_config(filename: str) -> None:
global config global config
base_load_config(filename, config) base_load_config(filename, config)
app.secret_key = config['secret_key'] app.secret_key = config.secret_key
def main() -> None: def main() -> None:

View File

@ -17,7 +17,7 @@ from typing import Any, Dict, List, Optional, Tuple
from bemani.common import GameConstants, VersionConstants, DBConstants, PEFile, Time from bemani.common import GameConstants, VersionConstants, DBConstants, PEFile, Time
from bemani.format import ARC, IFS, IIDXChart, IIDXMusicDB from bemani.format import ARC, IFS, IIDXChart, IIDXMusicDB
from bemani.data import Server, Song from bemani.data import Config, Server, Song
from bemani.data.interfaces import APIProviderInterface from bemani.data.interfaces import APIProviderInterface
from bemani.data.api.music import GlobalMusicData from bemani.data.api.music import GlobalMusicData
from bemani.data.api.game import GlobalGameData from bemani.data.api.game import GlobalGameData
@ -48,7 +48,7 @@ class ImportBase:
def __init__( def __init__(
self, self,
config: Dict[str, Any], config: Config,
game: GameConstants, game: GameConstants,
version: Optional[int], version: Optional[int],
no_combine: bool, no_combine: bool,
@ -59,7 +59,7 @@ class ImportBase:
self.update = update self.update = update
self.no_combine = no_combine self.no_combine = no_combine
self.__config = config self.__config = config
self.__engine = self.__config['database']['engine'] self.__engine = self.__config.database.engine
self.__sessionmanager = sessionmaker(self.__engine) self.__sessionmanager = sessionmaker(self.__engine)
self.__conn = self.__engine.connect() self.__conn = self.__engine.connect()
self.__session = self.__sessionmanager(bind=self.__conn) self.__session = self.__sessionmanager(bind=self.__conn)
@ -76,7 +76,7 @@ class ImportBase:
if not self.__batch: if not self.__batch:
raise Exception('Logic error, cannot execute outside of a batch!') raise Exception('Logic error, cannot execute outside of a batch!')
if self.__config['database'].get('read_only', False): if self.__config.database.read_only:
# See if this is an insert/update/delete # See if this is an insert/update/delete
for write_statement in [ for write_statement in [
"insert into ", "insert into ",
@ -359,7 +359,7 @@ class ImportPopn(ImportBase):
def __init__( def __init__(
self, self,
config: Dict[str, Any], config: Config,
version: str, version: str,
no_combine: bool, no_combine: bool,
update: bool, update: bool,
@ -1198,7 +1198,7 @@ class ImportJubeat(ImportBase):
def __init__( def __init__(
self, self,
config: Dict[str, Any], config: Config,
version: str, version: str,
no_combine: bool, no_combine: bool,
update: bool, update: bool,
@ -1453,7 +1453,7 @@ class ImportIIDX(ImportBase):
def __init__( def __init__(
self, self,
config: Dict[str, Any], config: Config,
version: str, version: str,
no_combine: bool, no_combine: bool,
update: bool, update: bool,
@ -2037,7 +2037,7 @@ class ImportDDR(ImportBase):
def __init__( def __init__(
self, self,
config: Dict[str, Any], config: Config,
version: str, version: str,
no_combine: bool, no_combine: bool,
update: bool, update: bool,
@ -2711,7 +2711,7 @@ class ImportSDVX(ImportBase):
def __init__( def __init__(
self, self,
config: Dict[str, Any], config: Config,
version: str, version: str,
no_combine: bool, no_combine: bool,
update: bool, update: bool,
@ -3050,7 +3050,7 @@ class ImportMuseca(ImportBase):
def __init__( def __init__(
self, self,
config: Dict[str, Any], config: Config,
version: str, version: str,
no_combine: bool, no_combine: bool,
update: bool, update: bool,
@ -3179,7 +3179,7 @@ class ImportReflecBeat(ImportBase):
def __init__( def __init__(
self, self,
config: Dict[str, Any], config: Config,
version: str, version: str,
no_combine: bool, no_combine: bool,
update: bool, update: bool,
@ -3448,7 +3448,7 @@ class ImportDanceEvolution(ImportBase):
def __init__( def __init__(
self, self,
config: Dict[str, Any], config: Config,
version: str, version: str,
no_combine: bool, no_combine: bool,
update: bool, update: bool,
@ -3652,7 +3652,7 @@ if __name__ == "__main__":
raise Exception("Cannot specify both a remote server and a local file to read from!") raise Exception("Cannot specify both a remote server and a local file to read from!")
# Load the config so we can talk to the server # Load the config so we can talk to the server
config: Dict[str, Any] = {} config = Config()
load_config(args.config, config) load_config(args.config, config)
series = None series = None

View File

@ -1,5 +1,5 @@
import argparse import argparse
from typing import Any, Dict, List from typing import Any, List
from bemani.backend.popn import PopnMusicFactory from bemani.backend.popn import PopnMusicFactory
from bemani.backend.jubeat import JubeatFactory from bemani.backend.jubeat import JubeatFactory
@ -18,38 +18,38 @@ from bemani.frontend.sdvx import SoundVoltexCache
from bemani.frontend.reflec import ReflecBeatCache from bemani.frontend.reflec import ReflecBeatCache
from bemani.frontend.museca import MusecaCache from bemani.frontend.museca import MusecaCache
from bemani.common import GameConstants, Time from bemani.common import GameConstants, Time
from bemani.data import Data from bemani.data import Config, Data
from bemani.utils.config import load_config from bemani.utils.config import load_config
def run_scheduled_work(config: Dict[str, Any]) -> None: def run_scheduled_work(config: Config) -> None:
data = Data(config) data = Data(config)
# Only run scheduled work for enabled components # Only run scheduled work for enabled components
enabled_factories: List[Any] = [] enabled_factories: List[Any] = []
enabled_caches: List[Any] = [] enabled_caches: List[Any] = []
if GameConstants.IIDX in config['support']: if GameConstants.IIDX in config.support:
enabled_factories.append(IIDXFactory) enabled_factories.append(IIDXFactory)
enabled_caches.append(IIDXCache) enabled_caches.append(IIDXCache)
if GameConstants.POPN_MUSIC in config['support']: if GameConstants.POPN_MUSIC in config.support:
enabled_factories.append(PopnMusicFactory) enabled_factories.append(PopnMusicFactory)
enabled_caches.append(PopnMusicCache) enabled_caches.append(PopnMusicCache)
if GameConstants.JUBEAT in config['support']: if GameConstants.JUBEAT in config.support:
enabled_factories.append(JubeatFactory) enabled_factories.append(JubeatFactory)
enabled_caches.append(JubeatCache) enabled_caches.append(JubeatCache)
if GameConstants.BISHI_BASHI in config['support']: if GameConstants.BISHI_BASHI in config.support:
enabled_factories.append(BishiBashiFactory) enabled_factories.append(BishiBashiFactory)
enabled_caches.append(BishiBashiCache) enabled_caches.append(BishiBashiCache)
if GameConstants.DDR in config['support']: if GameConstants.DDR in config.support:
enabled_factories.append(DDRFactory) enabled_factories.append(DDRFactory)
enabled_caches.append(DDRCache) enabled_caches.append(DDRCache)
if GameConstants.SDVX in config['support']: if GameConstants.SDVX in config.support:
enabled_factories.append(SoundVoltexFactory) enabled_factories.append(SoundVoltexFactory)
enabled_caches.append(SoundVoltexCache) enabled_caches.append(SoundVoltexCache)
if GameConstants.REFLEC_BEAT in config['support']: if GameConstants.REFLEC_BEAT in config.support:
enabled_factories.append(ReflecBeatFactory) enabled_factories.append(ReflecBeatFactory)
enabled_caches.append(ReflecBeatCache) enabled_caches.append(ReflecBeatCache)
if GameConstants.MUSECA in config['support']: if GameConstants.MUSECA in config.support:
enabled_factories.append(MusecaFactory) enabled_factories.append(MusecaFactory)
enabled_caches.append(MusecaCache) enabled_caches.append(MusecaCache)
@ -75,7 +75,7 @@ if __name__ == '__main__':
args = parser.parse_args() args = parser.parse_args()
# Set up global configuration # Set up global configuration
config: Dict[str, Any] = {} config = Config()
load_config(args.config, config) load_config(args.config, config)
# Run out of band work # Run out of band work

View File

@ -1,24 +1,22 @@
import argparse import argparse
import copy
import traceback import traceback
from typing import Any, Dict
from flask import Flask, request, redirect, Response, make_response from flask import Flask, request, redirect, Response, make_response
from bemani.protocol import EAmuseProtocol from bemani.protocol import EAmuseProtocol
from bemani.backend import Dispatch, UnrecognizedPCBIDException from bemani.backend import Dispatch, UnrecognizedPCBIDException
from bemani.data import Data from bemani.data import Config, Data
from bemani.utils.config import load_config as base_load_config, register_games as base_register_games from bemani.utils.config import load_config as base_load_config, register_games as base_register_games
app = Flask(__name__) app = Flask(__name__)
config: Dict[str, Any] = {} config = Config()
@app.route('/', defaults={'path': ''}, methods=['GET']) @app.route('/', defaults={'path': ''}, methods=['GET'])
@app.route('/<path:path>', methods=['GET']) @app.route('/<path:path>', methods=['GET'])
def receive_healthcheck(path: str) -> Response: def receive_healthcheck(path: str) -> Response:
global config global config
redirect_uri = config['server'].get('redirect') redirect_uri = config.server.redirect
if redirect_uri is None: if redirect_uri is None:
# Return a standard status OKAY message. # Return a standard status OKAY message.
return Response("Services OK.") return Response("Services OK.")
@ -50,7 +48,7 @@ def receive_request(path: str) -> Response:
# Create and format config # Create and format config
global config global config
requestconfig = copy.copy(config) requestconfig = config.clone()
requestconfig['client'] = { requestconfig['client'] = {
'address': remote_address or request.remote_addr, 'address': remote_address or request.remote_addr,
} }

View File

@ -1,26 +1,27 @@
database: database:
# IP or DNS entry for MySQL instance # IP or DNS entry for MySQL instance.
address: "localhost" address: "localhost"
# Database that will be used # Database that will be used.
database: "bemani" database: "bemani"
# User who has full credentials to the above DB # User who has full credentials to the above DB.
user: "bemani" user: "bemani"
# Password of said user # Password of said user.
password: "bemani" password: "bemani"
server: server:
# Advertised server IP or DNS entry games will connect to # Advertised server IP or DNS entry games will connect to.
address: "192.168.0.1" address: "192.168.0.1"
# Advertised keepalive address, must be globally pingable # Advertised keepalive address, must be globally pingable. Delete
# this to use the address above instead of a unique keepalive address.
keepalive: "127.0.0.1" keepalive: "127.0.0.1"
# What port games will connect to # What port on the above address games will connect to.
port: 80 port: 80
# Whether games should connect over HTTPS # Whether games should connect over HTTPS.
https: False https: False
# Advertised frontend URI. Delete this to mask the frontend address. # Advertised frontend URI. Delete this to mask the frontend address.
uri: "https://eagate.573.jp" uri: "https://eagate.573.jp"
# URI that users hitting the GET interface will be redirected to. # URI that users hitting the GET interface will be redirected to.
# Delete this to return an HTTP error instead. # Delete this to return an HTTP error instead of redirecting.
redirect: "https://eagate.573.jp" redirect: "https://eagate.573.jp"
# Whether PCBIDs must be added to the network before games will work. # Whether PCBIDs must be added to the network before games will work.
enforce_pcbid: False enforce_pcbid: False
@ -39,31 +40,31 @@ paseli:
infinite: True infinite: True
support: support:
# Bishi Bashi frontend/backend enabled # Bishi Bashi frontend/backend enabled.
bishi: True bishi: True
# DDR frontend/backend enabled # DDR frontend/backend enabled.
ddr: True ddr: True
# IIDX frontend/backend enabled # IIDX frontend/backend enabled.
iidx: True iidx: True
# Jubeat frontend/backend enabled # Jubeat frontend/backend enabled.
jubeat: True jubeat: True
# Museca frontend/backend enabled # Museca frontend/backend enabled.
museca: True museca: True
# Pop'n Music frontend/backend enabled # Pop'n Music frontend/backend enabled.
pnm: True pnm: True
# Reflec Beat frontend/backend enabled # Reflec Beat frontend/backend enabled.
reflec: True reflec: True
# SDVX frontend/backend enabled # SDVX frontend/backend enabled.
sdvx: True sdvx: True
# Key used to encrypt cookies, should be unique per instance # Key used to encrypt cookies, should be unique per network instance.
secret_key: 'this_is_a_secret_please_change_me' secret_key: 'this_is_a_secret_please_change_me'
# Name of this network # Name of this network.
name: 'e-AMUSEMENT Network' name: 'e-AMUSEMENT Network'
# Administrative contact for this network # Administrative contact for this network.
email: 'nobody@nowhere.com' email: 'nobody@nowhere.com'
# Cache DIR, should point somewhere other than /tmp for production instances # Cache DIR, should point somewhere other than /tmp for production instances.
cache_dir: '/tmp' cache_dir: '/tmp'
# Number of seconds to preserve event logs before deleting them. # Number of seconds to preserve event logs before deleting them.
# Set to zero to disable deleting logs. # Set to zero or delete to disable deleting logs.
event_log_duration: 2592000 event_log_duration: 2592000