snapctl 0.31.1__py3-none-any.whl → 0.32.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of snapctl might be problematic. Click here for more details.
- snapctl/commands/byogs.py +193 -367
- snapctl/commands/byosnap.py +397 -315
- snapctl/commands/game.py +63 -57
- snapctl/commands/generate.py +93 -0
- snapctl/commands/snapend.py +361 -281
- snapctl/config/constants.py +72 -8
- snapctl/config/hashes.py +14 -0
- snapctl/main.py +106 -124
- snapctl/types/definitions.py +20 -4
- snapctl/utils/echo.py +10 -2
- snapctl/utils/helper.py +60 -3
- snapctl-0.32.1.dist-info/LICENSE +29 -0
- {snapctl-0.31.1.dist-info → snapctl-0.32.1.dist-info}/METADATA +100 -70
- snapctl-0.32.1.dist-info/RECORD +23 -0
- snapctl-0.31.1.dist-info/RECORD +0 -21
- {snapctl-0.31.1.dist-info → snapctl-0.32.1.dist-info}/WHEEL +0 -0
- {snapctl-0.31.1.dist-info → snapctl-0.32.1.dist-info}/entry_points.txt +0 -0
snapctl/config/constants.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Constants used by snapctl
|
|
3
3
|
"""
|
|
4
4
|
COMPANY_NAME = 'Snapser'
|
|
5
|
-
VERSION = '0.
|
|
5
|
+
VERSION = '0.32.1'
|
|
6
6
|
CONFIG_FILE_MAC = '~/.snapser/config'
|
|
7
7
|
CONFIG_FILE_WIN = '%homepath%\\.snapser\\config'
|
|
8
8
|
|
|
@@ -12,16 +12,80 @@ URL_KEY = 'SNAPSER_URL_KEY'
|
|
|
12
12
|
CONFIG_PATH_KEY = 'SNAPSER_CONFIG_PATH'
|
|
13
13
|
SERVER_CALL_TIMEOUT = 30
|
|
14
14
|
|
|
15
|
-
SNAPCTL_SUCCESS = 0
|
|
16
|
-
SNAPCTL_ERROR = 1
|
|
17
|
-
|
|
18
15
|
# HTTP codes
|
|
19
16
|
HTTP_UNAUTHORIZED = 401
|
|
20
17
|
HTTP_FORBIDDEN = 403
|
|
21
18
|
HTTP_NOT_FOUND = 404
|
|
22
19
|
HTTP_CONFLICT = 409
|
|
23
20
|
|
|
24
|
-
# Error codes
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
# HTTP Error codes
|
|
22
|
+
HTTP_ERROR_SERVICE_VERSION_EXISTS = 542
|
|
23
|
+
HTTP_ERROR_TAG_NOT_AVAILABLE = 544
|
|
24
|
+
HTTP_ERROR_ADD_ON_NOT_ENABLED = 547
|
|
25
|
+
HTTP_ERROR_DUPLICATE_GAME_NAME = 2
|
|
26
|
+
|
|
27
|
+
# CLI Return Codes
|
|
28
|
+
SNAPCTL_SUCCESS = 0
|
|
29
|
+
SNAPCTL_ERROR = 1
|
|
30
|
+
SNAPCTL_INPUT_ERROR = 2
|
|
31
|
+
|
|
32
|
+
# Configuration Errors
|
|
33
|
+
SNAPCTL_CONFIGURATION_INCORRECT = 10
|
|
34
|
+
SNAPCTL_CONFIGURATION_ERROR = 11
|
|
35
|
+
SNAPCTL_DEPENDENCY_MISSING = 12
|
|
36
|
+
|
|
37
|
+
# BYOGS Errors
|
|
38
|
+
SNAPCTL_BYOGS_GENERIC_ERROR = 20
|
|
39
|
+
SNAPCTL_BYOGS_DEPENDENCY_MISSING = 21
|
|
40
|
+
SNAPCTL_BYOGS_ECR_LOGIN_ERROR = 22
|
|
41
|
+
SNAPCTL_BYOGS_BUILD_ERROR = 23
|
|
42
|
+
SNAPCTL_BYOGS_TAG_ERROR = 24
|
|
43
|
+
SNAPCTL_BYOGS_PUBLISH_ERROR = 25
|
|
44
|
+
SNAPCTL_BYOGS_PUBLISH_PERMISSION_ERROR = 26
|
|
45
|
+
SNAPCTL_BYOGS_PUBLISH_DUPLICATE_TAG_ERROR = 27
|
|
46
|
+
|
|
47
|
+
# BYOSNAP Errors
|
|
48
|
+
SNAPCTL_BYOSNAP_GENERIC_ERROR = 30
|
|
49
|
+
SNAPCTL_BYOSNAP_DEPENDENCY_MISSING = 31
|
|
50
|
+
SNAPCTL_BYOSNAP_ECR_LOGIN_ERROR = 32
|
|
51
|
+
SNAPCTL_BYOSNAP_BUILD_ERROR = 33
|
|
52
|
+
SNAPCTL_BYOSNAP_TAG_ERROR = 34
|
|
53
|
+
SNAPCTL_BYOSNAP_PUBLISH_IMAGE_ERROR = 35
|
|
54
|
+
SNAPCTL_BYOSNAP_PUBLISH_IMAGE_PERMISSION_ERROR = 36
|
|
55
|
+
SNAPCTL_BYOSNAP_PUBLISH_IMAGE_DUPLICATE_TAG_ERROR = 37
|
|
56
|
+
SNAPCTL_BYOSNAP_CREATE_ERROR = 38
|
|
57
|
+
SNAPCTL_BYOSNAP_CREATE_PERMISSION_ERROR = 39
|
|
58
|
+
SNAPCTL_BYOSNAP_CREATE_DUPLICATE_NAME_ERROR = 40
|
|
59
|
+
SNAPCTL_BYOSNAP_PUBLISH_VERSION_ERROR = 41
|
|
60
|
+
SNAPCTL_BYOSNAP_PUBLISH_VERSION_PERMISSION_ERROR = 42
|
|
61
|
+
SNAPCTL_BYOSNAP_PUBLISH_VERSION_DUPLICATE_VERSION_ERROR = 43
|
|
62
|
+
SNAPCTL_BYOSNAP_PUBLISH_VERSION_DUPLICATE_TAG_ERROR = 44
|
|
63
|
+
|
|
64
|
+
# Game Errors
|
|
65
|
+
SNAPCTL_GAME_GENERIC_ERROR = 50
|
|
66
|
+
SNAPCTL_GAME_CREATE_ERROR = 51
|
|
67
|
+
SNAPCTL_GAME_CREATE_PERMISSION_ERROR = 52
|
|
68
|
+
SNAPCTL_GAME_CREATE_DUPLICATE_NAME_ERROR = 53
|
|
69
|
+
SNAPCTL_GAME_ENUMERATE_ERROR = 54
|
|
70
|
+
|
|
71
|
+
# Snapend Errors
|
|
72
|
+
SNAPCTL_SNAPEND_GENERIC_ERROR = 60
|
|
73
|
+
SNAPCTL_SNAPEND_ENUMERATE_ERROR = 61
|
|
74
|
+
SNAPCTL_SNAPEND_CLONE_ERROR = 62
|
|
75
|
+
SNAPCTL_SNAPEND_CLONE_SERVER_ERROR = 63
|
|
76
|
+
SNAPCTL_SNAPEND_CLONE_TIMEOUT_ERROR = 64
|
|
77
|
+
SNAPCTL_SNAPEND_APPLY_ERROR = 65
|
|
78
|
+
SNAPCTL_SNAPEND_APPLY_SERVER_ERROR = 66
|
|
79
|
+
SNAPCTL_SNAPEND_APPLY_TIMEOUT_ERROR = 67
|
|
80
|
+
SNAPCTL_SNAPEND_PROMOTE_ERROR = 68
|
|
81
|
+
SNAPCTL_SNAPEND_PROMOTE_SERVER_ERROR = 69
|
|
82
|
+
SNAPCTL_SNAPEND_PROMOTE_TIMEOUT_ERROR = 70
|
|
83
|
+
SNAPCTL_SNAPEND_DOWNLOAD_ERROR = 71
|
|
84
|
+
SNAPCTL_SNAPEND_UPDATE_ERROR = 72
|
|
85
|
+
SNAPCTL_SNAPEND_UPDATE_SERVER_ERROR = 73
|
|
86
|
+
SNAPCTL_SNAPEND_UPDATE_TIMEOUT_ERROR = 74
|
|
87
|
+
SNAPCTL_SNAPEND_STATE_ERROR = 75
|
|
88
|
+
|
|
89
|
+
# Generate Errors
|
|
90
|
+
SNAPCTL_GENERATE_GENERIC_ERROR = 80
|
|
91
|
+
SNAPCTL_GENERATE_BYOSNAP_PROFILE_ERROR = 81
|
snapctl/config/hashes.py
CHANGED
|
@@ -155,3 +155,17 @@ SERVICE_IDS = [
|
|
|
155
155
|
'relay', 'remote-config', 'scheduler', 'sequencer', 'social-graph', 'statistics', 'storage',
|
|
156
156
|
'trackables', 'xp'
|
|
157
157
|
]
|
|
158
|
+
|
|
159
|
+
DEFAULT_BYOSNAP_TEMPLATE = {
|
|
160
|
+
'cpu': 100,
|
|
161
|
+
'memory': 0.125,
|
|
162
|
+
'cmd': '',
|
|
163
|
+
'args': [],
|
|
164
|
+
'env_params': []
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
BYOSNAP_TEMPLATE = {
|
|
168
|
+
'dev_template': DEFAULT_BYOSNAP_TEMPLATE,
|
|
169
|
+
'stage_template': DEFAULT_BYOSNAP_TEMPLATE,
|
|
170
|
+
'prod_template': DEFAULT_BYOSNAP_TEMPLATE
|
|
171
|
+
}
|
snapctl/main.py
CHANGED
|
@@ -4,21 +4,23 @@
|
|
|
4
4
|
import configparser
|
|
5
5
|
import os
|
|
6
6
|
from sys import platform
|
|
7
|
-
from typing import Union
|
|
7
|
+
from typing import Union
|
|
8
8
|
import typer
|
|
9
9
|
import pyfiglet
|
|
10
10
|
|
|
11
11
|
from snapctl.commands.byosnap import ByoSnap
|
|
12
12
|
from snapctl.commands.byogs import ByoGs
|
|
13
13
|
from snapctl.commands.game import Game
|
|
14
|
+
from snapctl.commands.generate import Generate
|
|
14
15
|
from snapctl.commands.snapend import Snapend
|
|
15
16
|
from snapctl.config.constants import COMPANY_NAME, API_KEY, URL_KEY, CONFIG_FILE_MAC, \
|
|
16
|
-
CONFIG_FILE_WIN, DEFAULT_PROFILE, VERSION, SNAPCTL_SUCCESS,
|
|
17
|
+
CONFIG_FILE_WIN, DEFAULT_PROFILE, VERSION, SNAPCTL_SUCCESS, CONFIG_PATH_KEY, \
|
|
18
|
+
SNAPCTL_CONFIGURATION_INCORRECT
|
|
17
19
|
from snapctl.config.endpoints import END_POINTS
|
|
18
20
|
from snapctl.config.hashes import CLIENT_SDK_TYPES, SERVER_SDK_TYPES, PROTOS_TYPES, SERVICE_IDS, \
|
|
19
21
|
SNAPEND_MANIFEST_TYPES
|
|
20
|
-
from snapctl.types.definitions import ResponseType
|
|
21
22
|
from snapctl.utils.echo import error, success, info
|
|
23
|
+
from snapctl.utils.helper import validate_api_key
|
|
22
24
|
|
|
23
25
|
######### Globals #########
|
|
24
26
|
|
|
@@ -65,20 +67,22 @@ def extract_config(extract_key: str, profile: str | None = None) -> object:
|
|
|
65
67
|
config_file_path = os.path.expandvars(CONFIG_FILE_WIN)
|
|
66
68
|
else:
|
|
67
69
|
config_file_path = os.path.expanduser(CONFIG_FILE_MAC)
|
|
68
|
-
result['location'] = f'
|
|
70
|
+
result['location'] = f'{config_file_path}'
|
|
69
71
|
if os.path.isfile(config_file_path):
|
|
70
72
|
config = configparser.ConfigParser()
|
|
71
73
|
config.read(config_file_path, encoding=encoding)
|
|
72
74
|
config_profile: str = DEFAULT_PROFILE
|
|
73
75
|
if profile is not None and profile != '' and profile != DEFAULT_PROFILE:
|
|
74
|
-
result['location'] = f'{config_file_path}:profile {profile}'
|
|
76
|
+
result['location'] = f'"{config_file_path}:profile {profile}"'
|
|
75
77
|
config_profile = f'profile {profile}'
|
|
76
|
-
info(
|
|
78
|
+
info(
|
|
79
|
+
f'Trying to extract API KEY from "{config_file_path}:profile {profile}"'
|
|
80
|
+
)
|
|
77
81
|
result['value'] = config.get(
|
|
78
82
|
config_profile, extract_key, fallback=None, raw=True
|
|
79
83
|
)
|
|
80
84
|
else:
|
|
81
|
-
|
|
85
|
+
info(
|
|
82
86
|
f'Config file on platform {platform} not found at {config_file_path}')
|
|
83
87
|
return result
|
|
84
88
|
|
|
@@ -110,14 +114,9 @@ def validate_command_context(
|
|
|
110
114
|
Validator to confirm if the context has been set properly
|
|
111
115
|
"""
|
|
112
116
|
if ctx.obj['api_key'] is None or ctx.obj['base_url'] == '':
|
|
113
|
-
error(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
f"API Key Category:{ctx.obj['api_key_location']} "
|
|
117
|
-
f"Base URL:{ctx.obj['base_url']}"
|
|
118
|
-
)
|
|
119
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
120
|
-
info(f"Using API Key from {ctx.obj['api_key_location']}")
|
|
117
|
+
error("Snapctl Configuration Incorrect. Unable to extract API Key",
|
|
118
|
+
SNAPCTL_CONFIGURATION_INCORRECT)
|
|
119
|
+
raise typer.Exit(code=SNAPCTL_CONFIGURATION_INCORRECT)
|
|
121
120
|
|
|
122
121
|
######### CALLBACKS #########
|
|
123
122
|
|
|
@@ -173,16 +172,16 @@ def profile_context_callback(
|
|
|
173
172
|
# Ensure ctx object is instantiated
|
|
174
173
|
ctx.ensure_object(dict)
|
|
175
174
|
api_key_obj = extract_config(API_KEY, profile)
|
|
176
|
-
if api_key_obj['value'] is None and profile is not None and profile != '':
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
175
|
+
# if api_key_obj['value'] is None and profile is not None and profile != '':
|
|
176
|
+
# conf_file = ''
|
|
177
|
+
# if platform == 'win32':
|
|
178
|
+
# conf_file = os.path.expandvars(CONFIG_FILE_WIN)
|
|
179
|
+
# else:
|
|
180
|
+
# conf_file = os.path.expanduser(CONFIG_FILE_MAC)
|
|
181
|
+
# error(
|
|
182
|
+
# f'Invalid profile input {profile}. '
|
|
183
|
+
# f'Please check your snap config file at {conf_file}'
|
|
184
|
+
# )
|
|
186
185
|
ctx.obj['version'] = VERSION
|
|
187
186
|
ctx.obj['api_key'] = api_key_obj['value']
|
|
188
187
|
ctx.obj['api_key_location'] = api_key_obj['location']
|
|
@@ -197,7 +196,7 @@ def version_callback(value: bool = True):
|
|
|
197
196
|
"""
|
|
198
197
|
if value:
|
|
199
198
|
success(f"Snapctl version: {VERSION}")
|
|
200
|
-
raise typer.Exit(SNAPCTL_SUCCESS)
|
|
199
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
|
201
200
|
|
|
202
201
|
|
|
203
202
|
@app.callback()
|
|
@@ -226,12 +225,57 @@ def validate(
|
|
|
226
225
|
profile: Union[str, None] = typer.Option(
|
|
227
226
|
None, "--profile", help="Profile to use.", callback=profile_context_callback
|
|
228
227
|
),
|
|
229
|
-
):
|
|
228
|
+
) -> None:
|
|
230
229
|
"""
|
|
231
230
|
Validate your Snapctl setup
|
|
232
231
|
"""
|
|
233
232
|
validate_command_context(ctx)
|
|
233
|
+
validate_api_key(ctx.obj['base_url'], ctx.obj['api_key'])
|
|
234
234
|
success("Setup is valid")
|
|
235
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
@app.command()
|
|
239
|
+
def byogs(
|
|
240
|
+
ctx: typer.Context,
|
|
241
|
+
# Required fields
|
|
242
|
+
subcommand: str = typer.Argument(
|
|
243
|
+
..., help="BYOGs Subcommands: " + ", ".join(ByoGs.SUBCOMMANDS) + "."
|
|
244
|
+
),
|
|
245
|
+
# sid: str = typer.Argument(
|
|
246
|
+
# ByoGs.SID, help="Game Server Id. Should start with byogs"
|
|
247
|
+
# ),
|
|
248
|
+
# publish, publish-image and publish-version
|
|
249
|
+
tag: str = typer.Option(
|
|
250
|
+
None, "--tag",
|
|
251
|
+
help="(req: build, push, publish) Tag for your snap"
|
|
252
|
+
),
|
|
253
|
+
# publish and publish-image
|
|
254
|
+
path: Union[str, None] = typer.Option(
|
|
255
|
+
None, "--path", help="(req: build, publish) Path to your snap code"
|
|
256
|
+
),
|
|
257
|
+
docker_file: str = typer.Option(
|
|
258
|
+
"Dockerfile", help="Dockerfile name to use"
|
|
259
|
+
),
|
|
260
|
+
# overrides
|
|
261
|
+
api_key: Union[str, None] = typer.Option(
|
|
262
|
+
None, "--api-key", help="API Key override.", callback=api_key_context_callback
|
|
263
|
+
),
|
|
264
|
+
profile: Union[str, None] = typer.Option(
|
|
265
|
+
None, "--profile", help="Profile to use.", callback=profile_context_callback
|
|
266
|
+
),
|
|
267
|
+
) -> None:
|
|
268
|
+
"""
|
|
269
|
+
Bring your own game server commands
|
|
270
|
+
"""
|
|
271
|
+
validate_command_context(ctx)
|
|
272
|
+
byogs_obj: ByoGs = ByoGs(
|
|
273
|
+
subcommand, ctx.obj['base_url'], ctx.obj['api_key'],
|
|
274
|
+
tag, path, docker_file,
|
|
275
|
+
)
|
|
276
|
+
getattr(byogs_obj, subcommand.replace('-', '_'))()
|
|
277
|
+
success(f"BYOGs {subcommand} complete")
|
|
278
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
|
235
279
|
|
|
236
280
|
|
|
237
281
|
@app.command()
|
|
@@ -283,6 +327,11 @@ def byosnap(
|
|
|
283
327
|
http_port: Union[str, None] = typer.Option(
|
|
284
328
|
None, "--http-port", help="(req: publish-version) Ingress HTTP port version"
|
|
285
329
|
),
|
|
330
|
+
byosnap_profile: Union[str, None] = typer.Option(
|
|
331
|
+
None, "--byosnap-profile", help=(
|
|
332
|
+
"(req: publish-version) Path to your byosnap-profile JSON file"
|
|
333
|
+
)
|
|
334
|
+
),
|
|
286
335
|
# overrides
|
|
287
336
|
api_key: Union[str, None] = typer.Option(
|
|
288
337
|
None, "--api-key", help="API Key override.", callback=api_key_context_callback
|
|
@@ -298,68 +347,24 @@ def byosnap(
|
|
|
298
347
|
byosnap_obj: ByoSnap = ByoSnap(
|
|
299
348
|
subcommand, ctx.obj['base_url'], ctx.obj['api_key'], sid,
|
|
300
349
|
name, desc, platform_type, language, tag, path, docker_file,
|
|
301
|
-
prefix, version, http_port
|
|
350
|
+
prefix, version, http_port, byosnap_profile
|
|
302
351
|
)
|
|
303
|
-
|
|
304
|
-
if validate_input_response['error']:
|
|
305
|
-
error(validate_input_response['msg'])
|
|
306
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
307
|
-
command_method = subcommand.replace('-', '_')
|
|
308
|
-
method: Callable[..., bool] = getattr(byosnap_obj, command_method)
|
|
309
|
-
if not method():
|
|
310
|
-
error(f"BYOSnap {subcommand} failed")
|
|
311
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
352
|
+
getattr(byosnap_obj, subcommand.replace('-', '_'))()
|
|
312
353
|
success(f"BYOSnap {subcommand} complete")
|
|
354
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
|
313
355
|
|
|
314
356
|
|
|
315
357
|
@app.command()
|
|
316
|
-
def
|
|
358
|
+
def game(
|
|
317
359
|
ctx: typer.Context,
|
|
318
360
|
# Required fields
|
|
319
361
|
subcommand: str = typer.Argument(
|
|
320
|
-
..., help="
|
|
321
|
-
),
|
|
322
|
-
sid: str = typer.Argument(
|
|
323
|
-
ByoGs.SID, help="Game Server Id. Should start with byogs"
|
|
362
|
+
..., help="Game Subcommands: " + ", ".join(Game.SUBCOMMANDS) + "."
|
|
324
363
|
),
|
|
325
|
-
#
|
|
364
|
+
# name
|
|
326
365
|
name: str = typer.Option(
|
|
327
|
-
None, "--name",
|
|
328
|
-
|
|
329
|
-
desc: str = typer.Option(
|
|
330
|
-
None, "--desc", help="(req: create) Description for your snap"
|
|
331
|
-
),
|
|
332
|
-
platform_type: str = typer.Option(
|
|
333
|
-
None, "--platform",
|
|
334
|
-
help="(req: create) Platform for your snap - " + \
|
|
335
|
-
", ".join(ByoGs.PLATFORMS) + "."
|
|
336
|
-
),
|
|
337
|
-
language: str = typer.Option(
|
|
338
|
-
None, "--language",
|
|
339
|
-
help="(req: create) Language of your snap - " + \
|
|
340
|
-
", ".join(ByoGs.LANGUAGES) + "."
|
|
341
|
-
),
|
|
342
|
-
# publish, publish-image and publish-version
|
|
343
|
-
tag: str = typer.Option(
|
|
344
|
-
None, "--tag",
|
|
345
|
-
help="(req: build, push, publish, publish-image and publish-version) Tag for your snap"
|
|
346
|
-
),
|
|
347
|
-
# publish and publish-image
|
|
348
|
-
path: Union[str, None] = typer.Option(
|
|
349
|
-
None, "--path", help="(req: build, publish, publish-image, upload-docs) Path to your snap code"
|
|
350
|
-
),
|
|
351
|
-
docker_file: str = typer.Option(
|
|
352
|
-
"Dockerfile", help="Dockerfile name to use"
|
|
353
|
-
),
|
|
354
|
-
# publish-version
|
|
355
|
-
version: Union[str, None] = typer.Option(
|
|
356
|
-
None, "--version", help="(req: publish-version) Snap version"
|
|
357
|
-
),
|
|
358
|
-
http_port: Union[str, None] = typer.Option(
|
|
359
|
-
None, "--http-port", help="(req: publish-version) Ingress HTTP port version"
|
|
360
|
-
),
|
|
361
|
-
debug_port: Union[str, None] = typer.Option(
|
|
362
|
-
None, "--debug-port", help="(optional: publish-version) Debug HTTP port version"
|
|
366
|
+
None, "--name",
|
|
367
|
+
help=("(req: create) Name of your game: ")
|
|
363
368
|
),
|
|
364
369
|
# overrides
|
|
365
370
|
api_key: Union[str, None] = typer.Option(
|
|
@@ -370,37 +375,26 @@ def byogs(
|
|
|
370
375
|
),
|
|
371
376
|
) -> None:
|
|
372
377
|
"""
|
|
373
|
-
|
|
378
|
+
Game commands
|
|
374
379
|
"""
|
|
375
380
|
validate_command_context(ctx)
|
|
376
|
-
|
|
377
|
-
subcommand, ctx.obj['base_url'], ctx.obj['api_key'],
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
)
|
|
381
|
-
validate_input_response: ResponseType = byogs_obj.validate_input()
|
|
382
|
-
if validate_input_response['error']:
|
|
383
|
-
error(validate_input_response['msg'])
|
|
384
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
385
|
-
command_method = subcommand.replace('-', '_')
|
|
386
|
-
method: Callable[..., bool] = getattr(byogs_obj, command_method)
|
|
387
|
-
if not method():
|
|
388
|
-
error(f"BYOGs {subcommand} failed")
|
|
389
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
390
|
-
success(f"BYOGs {subcommand} complete")
|
|
381
|
+
game_obj: Game = Game(
|
|
382
|
+
subcommand, ctx.obj['base_url'], ctx.obj['api_key'], name)
|
|
383
|
+
getattr(game_obj, subcommand.replace('-', '_'))()
|
|
384
|
+
success(f"Game {subcommand} complete")
|
|
385
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
|
391
386
|
|
|
392
387
|
|
|
393
388
|
@app.command()
|
|
394
|
-
def
|
|
389
|
+
def generate(
|
|
395
390
|
ctx: typer.Context,
|
|
396
391
|
# Required fields
|
|
397
392
|
subcommand: str = typer.Argument(
|
|
398
|
-
..., help="
|
|
393
|
+
..., help="Generate Subcommands: " + ", ".join(Generate.SUBCOMMANDS) + "."
|
|
399
394
|
),
|
|
400
|
-
#
|
|
401
|
-
|
|
402
|
-
None, "--
|
|
403
|
-
help=("(req: create) Name of your game: ")
|
|
395
|
+
# byosnap-profile
|
|
396
|
+
out_path: Union[str, None] = typer.Option(
|
|
397
|
+
None, "--out-path", help="(req: byosnap-profile) Path to output the byosnap profile"
|
|
404
398
|
),
|
|
405
399
|
# overrides
|
|
406
400
|
api_key: Union[str, None] = typer.Option(
|
|
@@ -411,21 +405,16 @@ def game(
|
|
|
411
405
|
),
|
|
412
406
|
) -> None:
|
|
413
407
|
"""
|
|
414
|
-
|
|
408
|
+
Generate files to be used by other commands
|
|
415
409
|
"""
|
|
416
410
|
validate_command_context(ctx)
|
|
417
|
-
|
|
418
|
-
subcommand, ctx.obj['base_url'], ctx.obj['api_key'],
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
method: Callable[..., bool] = getattr(game_obj, command_method)
|
|
425
|
-
if not method():
|
|
426
|
-
error(f"Game {subcommand} failed")
|
|
427
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
428
|
-
success(f"Game {subcommand} complete")
|
|
411
|
+
generate_obj: Generate = Generate(
|
|
412
|
+
subcommand, ctx.obj['base_url'], ctx.obj['api_key'],
|
|
413
|
+
out_path,
|
|
414
|
+
)
|
|
415
|
+
getattr(generate_obj, subcommand.replace('-', '_'))()
|
|
416
|
+
success(f"Generate {subcommand} complete")
|
|
417
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
|
429
418
|
|
|
430
419
|
|
|
431
420
|
@app.command()
|
|
@@ -438,7 +427,7 @@ def snapend(
|
|
|
438
427
|
# snapend_id: str = typer.Argument(..., help="Snapend Id"),
|
|
439
428
|
snapend_id: str = typer.Option(
|
|
440
429
|
None, "--snapend-id",
|
|
441
|
-
help=("(req: update, download) Snapend Id")
|
|
430
|
+
help=("(req: state, update, download) Snapend Id")
|
|
442
431
|
),
|
|
443
432
|
# enumerate
|
|
444
433
|
game_id: str = typer.Option(
|
|
@@ -552,13 +541,6 @@ def snapend(
|
|
|
552
541
|
# Update
|
|
553
542
|
byosnaps, byogs, blocking
|
|
554
543
|
)
|
|
555
|
-
|
|
556
|
-
if validate_input_response['error']:
|
|
557
|
-
error(validate_input_response['msg'])
|
|
558
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
559
|
-
command_method = subcommand.replace('-', '_')
|
|
560
|
-
method: Callable[..., bool] = getattr(snapend_obj, command_method)
|
|
561
|
-
if not method():
|
|
562
|
-
error(f"Snapend {subcommand} failed")
|
|
563
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
544
|
+
getattr(snapend_obj, subcommand.replace('-', '_'))()
|
|
564
545
|
success(f"Snapend {subcommand} complete")
|
|
546
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
snapctl/types/definitions.py
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This file contains the definitions of the types used in the snapctl package.
|
|
3
3
|
"""
|
|
4
|
+
from typing import List, Union
|
|
4
5
|
|
|
5
6
|
|
|
6
|
-
class
|
|
7
|
+
class ErrorResponse:
|
|
7
8
|
"""
|
|
8
9
|
This class represents the response type of the Snapser API.
|
|
9
10
|
"""
|
|
10
|
-
|
|
11
|
-
msg: str
|
|
12
|
-
|
|
11
|
+
|
|
12
|
+
def __init__(self, error: bool, code: int, msg: str, data: Union[List, str]):
|
|
13
|
+
self.error = error
|
|
14
|
+
self.code = code
|
|
15
|
+
self.msg = msg
|
|
16
|
+
self.data = data
|
|
17
|
+
|
|
18
|
+
def to_dict(self):
|
|
19
|
+
'''
|
|
20
|
+
Convert the object to a dictionary
|
|
21
|
+
|
|
22
|
+
'''
|
|
23
|
+
return {
|
|
24
|
+
'error': self.error,
|
|
25
|
+
'code': self.code,
|
|
26
|
+
'msg': self.msg,
|
|
27
|
+
'data': self.data
|
|
28
|
+
}
|
snapctl/utils/echo.py
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This module contains functions to print messages to the console.
|
|
3
3
|
"""
|
|
4
|
+
import json
|
|
5
|
+
import typer
|
|
4
6
|
from rich import print
|
|
7
|
+
from snapctl.config.constants import SNAPCTL_ERROR
|
|
8
|
+
from snapctl.types.definitions import ErrorResponse
|
|
5
9
|
# Run `python -m rich.emoji` to get a list of all emojis that are supported
|
|
6
10
|
|
|
7
11
|
|
|
8
|
-
def error(msg: str) -> None:
|
|
12
|
+
def error(msg: str, code: int = SNAPCTL_ERROR, data: object = None) -> None:
|
|
9
13
|
"""
|
|
10
14
|
Prints an error message to the console.
|
|
11
15
|
"""
|
|
16
|
+
error_response = ErrorResponse(
|
|
17
|
+
error=True, code=code, msg=msg, data=data if data else ''
|
|
18
|
+
)
|
|
12
19
|
print(f"[bold red]Error[/bold red] {msg}")
|
|
20
|
+
typer.echo(json.dumps(error_response.to_dict()), err=True)
|
|
13
21
|
|
|
14
22
|
|
|
15
23
|
def info(msg: str) -> None:
|
|
@@ -23,4 +31,4 @@ def success(msg: str) -> None:
|
|
|
23
31
|
"""
|
|
24
32
|
Prints a success message to the console.
|
|
25
33
|
"""
|
|
26
|
-
print(f"[green]Success[/green] {msg}")
|
|
34
|
+
print(f"[bold green]Success[/bold green] {msg}")
|
snapctl/utils/helper.py
CHANGED
|
@@ -3,11 +3,46 @@ Helper functions for snapctl
|
|
|
3
3
|
"""
|
|
4
4
|
import requests
|
|
5
5
|
import typer
|
|
6
|
+
from requests.exceptions import RequestException
|
|
7
|
+
from rich.progress import Progress
|
|
6
8
|
from snapctl.config.constants import HTTP_NOT_FOUND, HTTP_FORBIDDEN, HTTP_UNAUTHORIZED, \
|
|
7
|
-
SERVER_CALL_TIMEOUT
|
|
9
|
+
SERVER_CALL_TIMEOUT, SNAPCTL_CONFIGURATION_ERROR, SNAPCTL_SUCCESS
|
|
8
10
|
from snapctl.utils.echo import error, success
|
|
9
11
|
|
|
10
12
|
|
|
13
|
+
def validate_api_key(base_url: str, api_key: str | None):
|
|
14
|
+
"""
|
|
15
|
+
This function validates the API Key
|
|
16
|
+
"""
|
|
17
|
+
try:
|
|
18
|
+
url = f"{base_url}/v1/snapser-api/games"
|
|
19
|
+
res = requests.get(
|
|
20
|
+
url, headers={'api-key': api_key},
|
|
21
|
+
timeout=SERVER_CALL_TIMEOUT
|
|
22
|
+
)
|
|
23
|
+
if res.ok:
|
|
24
|
+
success('API Key validated')
|
|
25
|
+
return True
|
|
26
|
+
if res.status_code == HTTP_NOT_FOUND:
|
|
27
|
+
error('Service ID is invalid.', SNAPCTL_CONFIGURATION_ERROR)
|
|
28
|
+
elif res.status_code == HTTP_UNAUTHORIZED:
|
|
29
|
+
error(
|
|
30
|
+
'API Key verification failed. Your API Key is either invalid or may have expired. ',
|
|
31
|
+
SNAPCTL_CONFIGURATION_ERROR
|
|
32
|
+
)
|
|
33
|
+
elif res.status_code == HTTP_FORBIDDEN:
|
|
34
|
+
error(
|
|
35
|
+
'Permission denied. Your role has been revoked. Please contact your administrator.',
|
|
36
|
+
SNAPCTL_CONFIGURATION_ERROR
|
|
37
|
+
)
|
|
38
|
+
else:
|
|
39
|
+
error('Failed to validate API Key. Error:',
|
|
40
|
+
SNAPCTL_CONFIGURATION_ERROR)
|
|
41
|
+
except RequestException as e:
|
|
42
|
+
error(f"Exception: Unable to update your snapend {e}")
|
|
43
|
+
raise typer.Exit(code=SNAPCTL_CONFIGURATION_ERROR)
|
|
44
|
+
|
|
45
|
+
|
|
11
46
|
def get_composite_token(base_url: str, api_key: str | None, action: str, params: object) -> str:
|
|
12
47
|
"""
|
|
13
48
|
This function exchanges the api_key for a composite token.
|
|
@@ -30,9 +65,31 @@ def get_composite_token(base_url: str, api_key: str | None, action: str, params:
|
|
|
30
65
|
)
|
|
31
66
|
elif res.status_code == HTTP_FORBIDDEN:
|
|
32
67
|
error(
|
|
33
|
-
'Permission denied. Your role has been revoked. Please contact your administrator.'
|
|
68
|
+
'Permission denied. Your role has been revoked. Please contact your administrator.'
|
|
69
|
+
)
|
|
34
70
|
else:
|
|
35
71
|
error(f'Failed to validate API Key. Error: {res.text}')
|
|
36
|
-
raise typer.Exit()
|
|
72
|
+
raise typer.Exit(code=SNAPCTL_CONFIGURATION_ERROR)
|
|
37
73
|
success('API Key validated')
|
|
38
74
|
return res.json()['token']
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def snapctl_success(message: str, progress: Progress | None = None, no_exit: bool = False):
|
|
78
|
+
"""
|
|
79
|
+
This function exits the snapctl
|
|
80
|
+
"""
|
|
81
|
+
if progress:
|
|
82
|
+
progress.stop()
|
|
83
|
+
success(message)
|
|
84
|
+
if not no_exit:
|
|
85
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def snapctl_error(message: str, code: int, progress: Progress | None = None):
|
|
89
|
+
"""
|
|
90
|
+
This function exits the snapctl
|
|
91
|
+
"""
|
|
92
|
+
if progress:
|
|
93
|
+
progress.stop()
|
|
94
|
+
error(message, code)
|
|
95
|
+
raise typer.Exit(code=code)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Snapser Inc. Proprietary License
|
|
2
|
+
|
|
3
|
+
This CLI tool, its source code, and any accompanying documentation (collectively referred to as the "Software") are the property of Snapser Inc. ("Snapser"). The Software is provided under the following license terms and conditions:
|
|
4
|
+
|
|
5
|
+
1. License Grant:
|
|
6
|
+
Snapser grants you a non-exclusive, non-transferable, revocable license to use the Software solely for your internal business purposes. You may not distribute, sublicense, rent, lease, sell, or otherwise transfer the Software or any portion thereof.
|
|
7
|
+
|
|
8
|
+
2. Restrictions:
|
|
9
|
+
You may not modify, adapt, translate, reverse engineer, decompile, disassemble, or create derivative works based on the Software. You may not remove or alter any copyright, trademark, or other proprietary rights notices contained in the Software.
|
|
10
|
+
|
|
11
|
+
3. Ownership:
|
|
12
|
+
The Software and all intellectual property rights therein are and shall remain the exclusive property of Snapser Inc. Nothing in this license agreement shall be construed to transfer ownership of the Software to you.
|
|
13
|
+
|
|
14
|
+
4. Term and Termination:
|
|
15
|
+
This license is effective until terminated by either party. Snapser may terminate this license at any time if you breach any of its terms and conditions. Upon termination, you must immediately cease all use of the Software and destroy all copies thereof.
|
|
16
|
+
|
|
17
|
+
5. Disclaimer of Warranty:
|
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, SNAPSER DISCLAIMS ALL WARRANTIES, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. SNAPSER DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED IN THE SOFTWARE WILL MEET YOUR REQUIREMENTS OR THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE.
|
|
19
|
+
|
|
20
|
+
6. Limitation of Liability:
|
|
21
|
+
IN NO EVENT SHALL SNAPSER BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION, LOSS OF INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE, EVEN IF SNAPSER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
22
|
+
|
|
23
|
+
7. Governing Law:
|
|
24
|
+
This license agreement shall be governed by and construed in accordance with the laws of the United States of America, excluding its conflicts of law principles. Any disputes arising out of or in connection with this agreement shall be subject to the exclusive jurisdiction of the courts located in the United States of America.
|
|
25
|
+
|
|
26
|
+
By using the Software, you agree to be bound by the terms and conditions of this license agreement. If you do not agree to these terms and conditions, do not use the Software.
|
|
27
|
+
|
|
28
|
+
Snapser Inc.
|
|
29
|
+
June 4, 2024
|