Coverage for server/core.py : 85%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2from __future__ import annotations
4# -- stdlib --
5from typing import Any, Dict, Tuple, Type, TypeVar
7# -- third party --
8# -- own --
9from . import parts
10from .base import Game
11from .endpoint import Client
12from game.base import Packet
13from utils.events import EventHub
14import core
15import wire
18# -- code --
19class Options(object):
20 def __init__(self, options: Dict[str, Any]):
21 self.node = options.get('node', 'localhost') # Current node name
22 self.listen = options.get('listen', '') # Listen
23 self.backend = options.get('backend', '') # Backend URI
24 self.interconnect = options.get('interconnect', '') # URI of chat server
25 self.archive_path = options.get('archive_path', '') # file:// URI of dir for storing game archives
26 self.disables = options.get('disables', []) # disabled core components, will assign a None value
27 self.testing = options.get('testing', False) # In testing?
30T = TypeVar('T', bound=wire.Message)
33class _ClientCommandMapping(dict):
34 __slots__ = ('core',)
36 def __init__(self, core: Core):
37 self.core = core
38 super().__init__()
40 def __getitem__(self, k: Type[T]) -> EventHub[Tuple[Client, T]]:
41 if k in self:
42 return dict.__getitem__(self, k)
44 hub = EventHub()
45 hub.name = f'{self.core}::client_command'
46 self[k] = hub
47 return hub
50class Events(object):
51 def __init__(self, core: Core) -> None:
52 self.core = core
54 # ev = (core: Core)
55 self.core_initialized = EventHub[Core]()
57 # Fires when user state changes,
58 # ev = (c: Client, from: str, to: str)
59 self.user_state_transition = EventHub[Tuple[Client, str, str]]()
61 # Client connected
62 self.client_connected = EventHub[Client]()
64 # Client dropped(connection lost)
65 self.client_dropped = EventHub[Client]()
67 # Client logged in when previous login still online, or still in active game
68 # ev = c: Client # old client obj with new connection `pivot_to`ed to it
69 self.client_pivot = EventHub[Client]()
71 # Client send some command
72 # ev = (c: Client, args: (...))
73 self.client_command = _ClientCommandMapping(core)
75 # Game is created
76 # ev = g: Game
77 self.game_created = EventHub[Game]()
79 # Sent client game data
80 self.game_data_send = EventHub[Tuple[Game, Client, Packet]]()
82 # Received client game data
83 self.game_data_recv = EventHub[Tuple[Game, Client, Packet]]()
85 # Fires after old game ended and new game created.
86 # Actors should copy settings from old to new
87 # ev = (old: Game, g: Game)
88 self.game_successive_create = EventHub[Tuple[Game, Game]]()
90 # Game started running
91 # ev = (g: Game)
92 self.game_started = EventHub[Game]()
94 # Client joined a game
95 # ev = (g: Game, c: Client)
96 self.game_joined = EventHub[Tuple[Game, Client]]()
98 # Client left a game
99 # ev = (g: Game, c: Client)
100 self.game_left = EventHub[Tuple[Game, Client]]()
102 # Game was ended, successfully or not.
103 # ev = (g: Game)
104 self.game_ended = EventHub[Game]()
106 # Game ended in half way.
107 # This fires before GAME_ENDED
108 # ev = (g: Game)
109 self.game_aborted = EventHub[Game]()
111 # Game crashed
112 # ev = (g: Game)
113 self.game_crashed = EventHub[Game]()
115 def __setattr__(self, name, v):
116 if hasattr(v, 'name'):
117 v.name = f'{repr(self.core)}::{name}'
118 object.__setattr__(self, name, v)
121class Core(core.Core):
122 core_type = 'S'
124 def __init__(self, **options: Dict[str, Any]) -> None:
125 super().__init__()
127 self.options = Options(options)
128 self.events = Events(self)
129 disables = self.options.disables
131 if 'serve' not in disables: 131 ↛ 134line 131 didn't jump to line 134, because the condition on line 131 was never false
132 self.serve = parts.serve.Serve(self)
134 if 'auth' not in disables: 134 ↛ 137line 134 didn't jump to line 137, because the condition on line 134 was never false
135 self.auth = parts.auth.Auth(self)
137 if 'lobby' not in disables: 137 ↛ 140line 137 didn't jump to line 140, because the condition on line 137 was never false
138 self.lobby = parts.lobby.Lobby(self)
140 if 'room' not in disables: 140 ↛ 143line 140 didn't jump to line 143, because the condition on line 140 was never false
141 self.room = parts.room.Room(self)
143 if 'game' not in disables: 143 ↛ 146line 143 didn't jump to line 146, because the condition on line 143 was never false
144 self.game = parts.game.GamePart(self)
146 if 'observe' not in disables: 146 ↛ 149line 146 didn't jump to line 149, because the condition on line 146 was never false
147 self.observe = parts.observe.Observe(self)
149 if 'invite' not in disables: 149 ↛ 152line 149 didn't jump to line 152, because the condition on line 149 was never false
150 self.invite = parts.invite.Invite(self)
152 if 'item' not in disables: 152 ↛ 155line 152 didn't jump to line 155, because the condition on line 152 was never false
153 self.item = parts.item.Item(self)
155 if 'reward' not in disables: 155 ↛ 158line 155 didn't jump to line 158, because the condition on line 155 was never false
156 self.reward = parts.reward.Reward(self)
158 if 'contest' not in disables: 158 ↛ 161line 158 didn't jump to line 161, because the condition on line 158 was never false
159 self.contest = parts.contest.Contest(self)
161 if 'admin' not in disables: 161 ↛ 164line 161 didn't jump to line 164, because the condition on line 161 was never false
162 self.admin = parts.admin.Admin(self)
164 if 'kedama' not in disables: 164 ↛ 167line 164 didn't jump to line 167, because the condition on line 164 was never false
165 self.kedama = parts.kedama.Kedama(self)
167 if 'archive' not in disables: 167 ↛ 170line 167 didn't jump to line 170, because the condition on line 167 was never false
168 self.archive = parts.archive.Archive(self)
170 if 'hooks' not in disables: 170 ↛ 173line 170 didn't jump to line 173, because the condition on line 170 was never false
171 self.hooks = parts.hooks.Hooks(self)
173 if 'connect' not in disables: 173 ↛ 174line 173 didn't jump to line 174, because the condition on line 173 was never true
174 self.connect = parts.connect.Connect(self)
176 if 'backend' not in disables: 176 ↛ 177line 176 didn't jump to line 177, because the condition on line 176 was never true
177 self.backend = parts.backend.Backend(self)
179 if 'log' not in disables: 179 ↛ 182line 179 didn't jump to line 182, because the condition on line 179 was never false
180 self.log = parts.log.Log(self)
182 if 'stats' not in disables: 182 ↛ 183line 182 didn't jump to line 183, because the condition on line 182 was never true
183 self.stats = parts.stats.Stats(self)
185 if 'view' not in disables: 185 ↛ 188line 185 didn't jump to line 188, because the condition on line 185 was never false
186 self.view = parts.view.View(self)
188 self.events.core_initialized.emit(self)