1
1
import asyncio
2
+ import dataclasses
2
3
import json
3
4
import logging
4
5
import logging .handlers
5
- import dataclasses
6
- from enum import Enum
6
+ import sys
7
7
from collections import OrderedDict
8
+ from enum import Enum
8
9
from itertools import count
9
- import sys
10
+ from typing import Any , Dict , List , Optional , Set , Union
10
11
11
- from typing import Any , List , Dict , Optional , Union
12
-
13
- from galaxy .api .types import Achievement , Game , LocalGame , FriendInfo , GameTime
14
-
15
- from galaxy .api .jsonrpc import Server , NotificationClient , ApplicationError
16
12
from galaxy .api .consts import Feature
17
- from galaxy .api .errors import UnknownError , ImportInProgress
18
- from galaxy .api .types import Authentication , NextStep
13
+ from galaxy .api .errors import ImportInProgress , UnknownError
14
+ from galaxy .api .jsonrpc import ApplicationError , NotificationClient , Server
15
+ from galaxy .api .types import Achievement , Authentication , FriendInfo , Game , GameTime , LocalGame , NextStep
19
16
20
17
21
18
class JSONEncoder (json .JSONEncoder ):
@@ -24,6 +21,7 @@ def default(self, o): # pylint: disable=method-hidden
24
21
# filter None values
25
22
def dict_factory (elements ):
26
23
return {k : v for k , v in elements if v is not None }
24
+
27
25
return dataclasses .asdict (o , dict_factory = dict_factory )
28
26
if isinstance (o , Enum ):
29
27
return o .value
@@ -32,12 +30,13 @@ def dict_factory(elements):
32
30
33
31
class Plugin :
34
32
"""Use and override methods of this class to create a new platform integration."""
33
+
35
34
def __init__ (self , platform , version , reader , writer , handshake_token ):
36
35
logging .info ("Creating plugin for platform %s, version %s" , platform .value , version )
37
36
self ._platform = platform
38
37
self ._version = version
39
38
40
- self ._feature_methods = OrderedDict ()
39
+ self ._features : Set [ Feature ] = set ()
41
40
self ._active = True
42
41
self ._pass_control_task = None
43
42
@@ -50,6 +49,7 @@ def __init__(self, platform, version, reader, writer, handshake_token):
50
49
51
50
def eof_handler ():
52
51
self ._shutdown ()
52
+
53
53
self ._server .register_eof (eof_handler )
54
54
55
55
self ._achievements_import_in_progress = False
@@ -85,77 +85,65 @@ def eof_handler():
85
85
self ._register_method (
86
86
"import_owned_games" ,
87
87
self .get_owned_games ,
88
- result_name = "owned_games" ,
89
- feature = Feature .ImportOwnedGames
88
+ result_name = "owned_games"
90
89
)
90
+ self ._detect_feature (Feature .ImportOwnedGames , ["get_owned_games" ])
91
+
91
92
self ._register_method (
92
93
"import_unlocked_achievements" ,
93
94
self .get_unlocked_achievements ,
94
- result_name = "unlocked_achievements" ,
95
- feature = Feature .ImportAchievements
96
- )
97
- self ._register_method (
98
- "start_achievements_import" ,
99
- self .start_achievements_import ,
100
- )
101
- self ._register_method (
102
- "import_local_games" ,
103
- self .get_local_games ,
104
- result_name = "local_games" ,
105
- feature = Feature .ImportInstalledGames
106
- )
107
- self ._register_notification ("launch_game" , self .launch_game , feature = Feature .LaunchGame )
108
- self ._register_notification ("install_game" , self .install_game , feature = Feature .InstallGame )
109
- self ._register_notification (
110
- "uninstall_game" ,
111
- self .uninstall_game ,
112
- feature = Feature .UninstallGame
113
- )
114
- self ._register_notification (
115
- "shutdown_platform_client" ,
116
- self .shutdown_platform_client ,
117
- feature = Feature .ShutdownPlatformClient
118
- )
119
- self ._register_method (
120
- "import_friends" ,
121
- self .get_friends ,
122
- result_name = "friend_info_list" ,
123
- feature = Feature .ImportFriends
124
- )
125
- self ._register_method (
126
- "import_game_times" ,
127
- self .get_game_times ,
128
- result_name = "game_times" ,
129
- feature = Feature .ImportGameTime
130
- )
131
- self ._register_method (
132
- "start_game_times_import" ,
133
- self .start_game_times_import ,
95
+ result_name = "unlocked_achievements"
134
96
)
97
+ self ._detect_feature (Feature .ImportAchievements , ["get_unlocked_achievements" ])
135
98
136
- @property
137
- def features (self ):
138
- features = []
139
- if self .__class__ != Plugin :
140
- for feature , handlers in self ._feature_methods .items ():
141
- if self ._implements (handlers ):
142
- features .append (feature )
99
+ self ._register_method ("start_achievements_import" , self .start_achievements_import )
100
+ self ._detect_feature (Feature .ImportAchievements , ["import_games_achievements" ])
101
+
102
+ self ._register_method ("import_local_games" , self .get_local_games , result_name = "local_games" )
103
+ self ._detect_feature (Feature .ImportInstalledGames , ["get_local_games" ])
104
+
105
+ self ._register_notification ("launch_game" , self .launch_game )
106
+ self ._detect_feature (Feature .LaunchGame , ["launch_game" ])
107
+
108
+ self ._register_notification ("install_game" , self .install_game )
109
+ self ._detect_feature (Feature .InstallGame , ["install_game" ])
110
+
111
+ self ._register_notification ("uninstall_game" , self .uninstall_game )
112
+ self ._detect_feature (Feature .UninstallGame , ["uninstall_game" ])
113
+
114
+ self ._register_notification ("shutdown_platform_client" , self .shutdown_platform_client )
115
+ self ._detect_feature (Feature .ShutdownPlatformClient , ["shutdown_platform_client" ])
116
+
117
+ self ._register_method ("import_friends" , self .get_friends , result_name = "friend_info_list" )
118
+ self ._detect_feature (Feature .ImportFriends , ["get_friends" ])
143
119
144
- return features
120
+ self ._register_method ("import_game_times" , self .get_game_times , result_name = "game_times" )
121
+ self ._detect_feature (Feature .ImportGameTime , ["get_game_times" ])
122
+
123
+ self ._register_method ("start_game_times_import" , self .start_game_times_import )
124
+ self ._detect_feature (Feature .ImportGameTime , ["import_game_times" ])
125
+
126
+ @property
127
+ def features (self ) -> List [Feature ]:
128
+ return list (self ._features )
145
129
146
130
@property
147
131
def persistent_cache (self ) -> Dict :
148
132
"""The cache is only available after the :meth:`~.handshake_complete()` is called.
149
133
"""
150
134
return self ._persistent_cache
151
135
152
- def _implements (self , handlers ) :
153
- for handler in handlers :
154
- if handler . __name__ not in self .__class__ .__dict__ :
136
+ def _implements (self , methods : List [ str ]) -> bool :
137
+ for method in methods :
138
+ if method not in self .__class__ .__dict__ :
155
139
return False
156
140
return True
157
141
158
- def _register_method (self , name , handler , result_name = None , internal = False , sensitive_params = False , feature = None ):
142
+ def _detect_feature (self , feature : Feature , methods : List [str ]):
143
+ if self ._implements (methods ):
144
+ self ._features .add (feature )
145
+
146
+ def _register_method (self , name , handler , result_name = None , internal = False , sensitive_params = False ):
159
147
if internal :
160
148
def method (* args , ** kwargs ):
161
149
result = handler (* args , ** kwargs )
@@ -164,6 +152,7 @@ def method(*args, **kwargs):
164
152
result_name : result
165
153
}
166
154
return result
155
+
167
156
self ._server .register_method (name , method , True , sensitive_params )
168
157
else :
169
158
async def method (* args , ** kwargs ):
@@ -173,17 +162,12 @@ async def method(*args, **kwargs):
173
162
result_name : result
174
163
}
175
164
return result
176
- self ._server .register_method (name , method , False , sensitive_params )
177
165
178
- if feature is not None :
179
- self ._feature_methods .setdefault (feature , []).append (handler )
166
+ self ._server .register_method (name , method , False , sensitive_params )
180
167
181
- def _register_notification (self , name , handler , internal = False , sensitive_params = False , feature = None ):
168
+ def _register_notification (self , name , handler , internal = False , sensitive_params = False ):
182
169
self ._server .register_notification (name , handler , internal , sensitive_params )
183
170
184
- if feature is not None :
185
- self ._feature_methods .setdefault (feature , []).append (handler )
186
-
187
171
async def run (self ):
188
172
"""Plugin's main coroutine."""
189
173
await self ._server .run ()
@@ -192,6 +176,7 @@ async def run(self):
192
176
193
177
def create_task (self , coro , description ):
194
178
"""Wrapper around asyncio.create_task - takes care of canceling tasks on shutdown"""
179
+
195
180
async def task_wrapper (task_id ):
196
181
try :
197
182
return await coro
@@ -524,7 +509,7 @@ async def authenticate(self, stored_credentials=None):
524
509
raise NotImplementedError ()
525
510
526
511
async def pass_login_credentials (self , step : str , credentials : Dict [str , str ], cookies : List [Dict [str , str ]]) \
527
- -> Union [NextStep , Authentication ]:
512
+ -> Union [NextStep , Authentication ]:
528
513
"""This method is called if we return galaxy.api.types.NextStep from authenticate or from pass_login_credentials.
529
514
This method's parameters provide the data extracted from the web page navigation that previous NextStep finished on.
530
515
This method should either return galaxy.api.types.Authentication if the authentication is finished
@@ -607,6 +592,7 @@ async def import_games_achievements(self, game_ids: List[str]) -> None:
607
592
608
593
:param game_ids: ids of the games for which to import unlocked achievements
609
594
"""
595
+
610
596
async def import_game_achievements (game_id ):
611
597
try :
612
598
achievements = await self .get_unlocked_achievements (game_id )
0 commit comments