Hide keyboard shortcuts

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 

3 

4# -- stdlib -- 

5from typing import Any, ClassVar, Dict, List, Optional, Type, TypeVar 

6from typing_extensions import TypedDict 

7 

8# -- third party -- 

9from dataclasses import dataclass 

10import dataclasses 

11 

12# -- own -- 

13from . import model 

14 

15 

16# -- code -- 

17class ServerToClient: 

18 pass 

19 

20 

21class ClientToServer: 

22 pass 

23 

24 

25class BiDirectional(ServerToClient, ClientToServer): 

26 pass 

27 

28 

29class Message: 

30 types: ClassVar[Dict[str, Type[Message]]] = {} 

31 op: str 

32 

33 def __init__(self, *args, **kwargs): 

34 raise Exception('Abstract') 

35 

36 def encode(self) -> dict: 

37 ... 

38 

39 @classmethod 

40 def decode(cls, data: dict) -> Optional[Message]: 

41 data = dict(data) 

42 op = data.pop('op', '') 

43 if op not in cls.types: 43 ↛ 44line 43 didn't jump to line 44, because the condition on line 43 was never true

44 return None 

45 

46 return cls.types[op](**data) 

47 

48 

49def message(cls: Type[Message]) -> Type[Message]: 

50 assert issubclass(cls, ServerToClient) or issubclass(cls, ClientToServer) 

51 cls.op = cls.__name__ 

52 assert cls.op not in Message.types, cls.op 

53 Message.types[cls.op] = cls 

54 

55 if cls.encode is Message.encode: 55 ↛ 68line 55 didn't jump to line 68, because the condition on line 55 was never false

56 env: Any = {} 

57 fields = [f" '{i.name}': self.{i.name}," for i in dataclasses.fields(cls)] 

58 code = ( 

59 "def encode(self) -> dict:" 

60 " return {" 

61 " 'op': self.op," 

62 " %s" 

63 " }" 

64 ) % '\n'.join(fields) 

65 exec(code, env) 

66 cls.encode = env['encode'] # type: ignore 

67 

68 return cls 

69 

70 

71T = TypeVar('T', bound=Message) 

72 

73 

74def cast(typ: Type[T], msg: Message) -> Optional[T]: 

75 if msg.op == typ.op: 

76 return msg # type: ignore 

77 

78 return None 

79 

80 

81# ---------------------------- 

82@message 

83@dataclass 

84class Info(Message, ServerToClient): 

85 msg: str 

86 

87 

88@message 

89@dataclass 

90class Error(Message, ServerToClient): 

91 msg: str 

92 

93 

94@message 

95@dataclass 

96class SystemMsg(Message, ServerToClient): 

97 msg: str 

98 

99 

100@message 

101@dataclass 

102class CurrentGames(Message, ServerToClient): 

103 games: List[model.Game] 

104 

105 

106@message 

107@dataclass 

108class CurrentUsers(Message, ServerToClient): 

109 users: List[model.User] 

110 

111 

112@message 

113@dataclass 

114class RoomUsers(Message, ServerToClient): 

115 gid: int 

116 users: List[model.User] 

117 

118 

119@message 

120@dataclass 

121class GameJoined(Message, ServerToClient): 

122 game: model.GameDetail 

123 

124 

125@message 

126@dataclass 

127class GameStarted(Message, ServerToClient): 

128 game: model.GameDetail 

129 

130 

131@message 

132@dataclass 

133class PlayerPresence(Message, ServerToClient): 

134 ''' 

135 Indicates if player is still in the game 

136 ''' 

137 gid: int 

138 presence: Dict[int, bool] 

139 

140 

141@message 

142@dataclass 

143class GameEnded(Message, ServerToClient): 

144 gid: int 

145 

146 

147@message 

148@dataclass 

149class GameParams(Message, ServerToClient): 

150 gid: int 

151 params: Dict[str, Any] 

152 

153 

154@message 

155@dataclass 

156class SetGameParam(Message, BiDirectional): 

157 gid: int 

158 key: str 

159 value: Any 

160 

161 

162@message 

163@dataclass 

164class GameData(Message, BiDirectional): 

165 gid: int 

166 tag: str 

167 data: Any 

168 

169 

170@message 

171@dataclass 

172class InviteRequest(Message, ServerToClient): 

173 uid: int 

174 name: str 

175 gid: int 

176 type: str 

177 

178 

179@message 

180@dataclass 

181class ObserveRequest(Message, ServerToClient): 

182 uid: int 

183 

184 

185@message 

186@dataclass 

187class KickRequest(Message, ServerToClient): 

188 uid: int 

189 victim: int 

190 votes: int 

191 

192 

193@message 

194@dataclass 

195class ObserveStarted(Message, ServerToClient): 

196 game: model.GameDetail 

197 observee: int 

198 

199 

200@message 

201@dataclass 

202class GameLeft(Message, ServerToClient): 

203 gid: int 

204 

205 

206@message 

207@dataclass 

208class Greeting(Message, ServerToClient): 

209 node: str 

210 version: str 

211 

212 

213@message 

214@dataclass 

215class AuthError(Message, ServerToClient): 

216 reason: str 

217 

218 

219@message 

220@dataclass 

221class AuthSuccess(Message, ServerToClient): 

222 uid: int 

223 

224 

225@message 

226@dataclass 

227class Ping(Message, ServerToClient): 

228 pass 

229 

230 

231# -------------------------------- 

232# ----- system ----- 

233@message 

234@dataclass 

235class Beat(Message, ClientToServer): 

236 pass 

237 

238 

239@message 

240@dataclass 

241class Pong(Message, ClientToServer): 

242 pass 

243 

244 

245@message 

246@dataclass 

247class Auth(Message, ClientToServer): 

248 token: str 

249 

250 

251# ----- room ----- 

252class CreateRoomFlags(TypedDict, total=False): 

253 contest: bool 

254 invite: bool 

255 chat: bool 

256 

257 

258@message 

259@dataclass 

260class CreateRoom(Message, ClientToServer): 

261 name: str 

262 mode: str 

263 flags: CreateRoomFlags 

264 

265 

266@message 

267@dataclass 

268class JoinRoom(Message, ClientToServer): 

269 gid: int 

270 slot: Optional[int] 

271 

272 

273@message 

274@dataclass 

275class LeaveRoom(Message, ClientToServer): 

276 pass 

277 

278 

279@message 

280@dataclass 

281class GetRoomUsers(Message, ClientToServer): 

282 gid: int 

283 

284 

285@message 

286@dataclass 

287class GetReady(Message, ClientToServer): 

288 pass 

289 

290 

291@message 

292@dataclass 

293class CancelReady(Message, ClientToServer): 

294 pass 

295 

296 

297@message 

298@dataclass 

299class ChangeLocation(Message, ClientToServer): 

300 loc: int 

301 

302 

303# ----- matching ----- 

304@message 

305@dataclass 

306class StartMatching(Message, BiDirectional): 

307 modes: List[str] 

308 

309 

310# ----- observe ----- 

311@message 

312@dataclass 

313class Observe(Message, ClientToServer): 

314 uid: int 

315 

316 

317@message 

318@dataclass 

319class GrantObserve(Message, ClientToServer): 

320 uid: int 

321 grant: bool 

322 

323 

324@message 

325@dataclass 

326class KickObserver(Message, ClientToServer): 

327 uid: int 

328 

329 

330@message 

331@dataclass 

332class ObserverEnter(Message, ServerToClient): 

333 observer: int 

334 observee: int 

335 

336 

337@message 

338@dataclass 

339class ObserverLeave(Message, ServerToClient): 

340 observer: int 

341 observee: int 

342 

343 

344# ----- invite ----- 

345@message 

346@dataclass 

347class Invite(Message, ClientToServer): 

348 uid: int 

349 

350 

351@message 

352@dataclass 

353class Kick(Message, ClientToServer): 

354 uid: int 

355 

356 

357# ----- item ----- 

358@message 

359@dataclass 

360class UseItem(Message, ClientToServer): 

361 sku: str 

362 

363 

364# ----- admin ----- 

365@message 

366@dataclass 

367class AdminStacktrace(Message, ClientToServer): 

368 pass 

369 

370 

371@message 

372@dataclass 

373class AdminClearZombies(Message, ClientToServer): 

374 pass 

375 

376 

377@message 

378@dataclass 

379class AdminMigrate(Message, ClientToServer): 

380 pass 

381 

382 

383@message 

384@dataclass 

385class AdminKick(Message, ClientToServer): 

386 uid: int 

387 

388 

389@message 

390@dataclass 

391class AdminKillGame(Message, ClientToServer): 

392 gid: int 

393 

394 

395@message 

396@dataclass 

397class AdminAdd(Message, ClientToServer): 

398 uid: int 

399 

400 

401@message 

402@dataclass 

403class AdminRemove(Message, ClientToServer): 

404 uid: int 

405 

406 

407@message 

408@dataclass 

409class AdminAddBigbrother(Message, ClientToServer): 

410 uid: int 

411 

412 

413@message 

414@dataclass 

415class AdminRemoveBigbrother(Message, ClientToServer): 

416 uid: int 

417 

418 

419# ----- contest ----- 

420@message 

421@dataclass 

422class SetupContest(Message, ClientToServer): 

423 name: str 

424 mode: str 

425 uids: List[int]