Skip to content

Commit 15ebba5

Browse files
authored
Remove flask_uploads.py (#152)
* WIP: remove flask_uploads * Cleanup * Add option for remote sequence storage * Formatting * Remove legacy comment * Update workflow versions * Fix permission check issues * Add more permission checks
1 parent 5db3a7c commit 15ebba5

File tree

10 files changed

+117
-592
lines changed

10 files changed

+117
-592
lines changed

.github/workflows/fprime-gds-tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ jobs:
1616
python-version: ["3.8", "3.9", "3.10", "3.11"]
1717

1818
steps:
19-
- uses: actions/checkout@v3
19+
- uses: actions/checkout@v4
2020
- name: Set up Python ${{ matrix.python-version }}
21-
uses: actions/setup-python@v2
21+
uses: actions/setup-python@v4
2222
with:
2323
python-version: ${{ matrix.python-version }}
2424
- name: Install dependencies

src/fprime_gds/common/files/uplinker.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ def __init__(self, uplinker):
4747
self.queue = queue.Queue()
4848
self.__file_store = []
4949
self.__exit = threading.Event()
50-
self.__thread = threading.Thread(target=self.run, name="UplinkerThread", args=())
50+
self.__thread = threading.Thread(
51+
target=self.run, name="UplinkerThread", args=()
52+
)
5153
self.__thread.start()
5254

5355
def enqueue(self, filepath, destination):
@@ -228,9 +230,7 @@ def start(self, file_obj):
228230
# Prevent multiple uplinks at once
229231
if self.state != FileStates.IDLE:
230232
msg = f"Currently uplinking file '{self.active.source}' cannot start uplinking '{file_obj.source}'"
231-
raise FileUplinkerBusyException(
232-
msg
233-
)
233+
raise FileUplinkerBusyException(msg)
234234
self.state = FileStates.RUNNING
235235
self.active = file_obj
236236
self.active.open(TransmitFileState.READ)

src/fprime_gds/common/pipeline/files.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
88
@author mstarch
99
"""
10-
import os
10+
from pathlib import Path
1111
import fprime_gds.common.files.downlinker
1212
import fprime_gds.common.files.uplinker
1313

@@ -43,10 +43,11 @@ def setup_file_handling(
4343
)
4444
file_decoder.register(self.__downlinker)
4545
distributor.register("FW_PACKET_HAND", self.__uplinker)
46-
if not os.access(down_store, os.W_OK):
46+
try:
47+
Path(down_store).mkdir(parents=True, exist_ok=True)
48+
except PermissionError:
4749
raise PermissionError(
48-
f"{down_store} is not writable. Downlinker not be able to save files. "
49-
"Fix permissions or change storage directory with --file-storage-directory."
50+
f"{down_store} is not writable. Fix permissions or change storage directory with --file-storage-directory."
5051
)
5152

5253
@property

src/fprime_gds/common/pipeline/standard.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ def __init__(self):
4444
self.client_socket = None
4545
self.logger = None
4646
self.dictionary_path = None
47+
self.up_store = None
48+
self.down_store = None
4749

4850
self.__dictionaries = dictionaries.Dictionaries()
4951
self.__coders = encoding.EncodingDecoding()
@@ -52,19 +54,31 @@ def __init__(self):
5254
self.__transport_type = ThreadedTCPSocketClient
5355

5456
def setup(
55-
self, config, dictionary, down_store, logging_prefix=None, packet_spec=None
57+
self, config, dictionary, file_store, logging_prefix=None, packet_spec=None
5658
):
5759
"""
5860
Setup the standard pipeline for moving data from the middleware layer through the GDS layers using the standard
5961
patterns. This allows just registering the consumers, and invoking 'setup' all other of the GDS support layer.
6062
6163
:param config: config object used when constructing the pipeline.
6264
:param dictionary: dictionary path. Used to setup loading of dictionaries.
63-
:param down_store: downlink storage directory
65+
:param file_store: uplink/downlink storage directory
6466
:param logging_prefix: logging prefix. Defaults to not logging at all.
6567
:param packet_spec: location of packetized telemetry XML specification.
6668
"""
67-
assert dictionary is not None and Path(dictionary).is_file(), f"Dictionary {dictionary} does not exist"
69+
assert (
70+
dictionary is not None and Path(dictionary).is_file()
71+
), f"Dictionary {dictionary} does not exist"
72+
# File storage configuration for uplink and downlink
73+
self.up_store = Path(file_store) / "fprime-uplink"
74+
self.down_store = Path(file_store) / "fprime-downlink"
75+
try:
76+
self.down_store.mkdir(parents=True, exist_ok=True)
77+
self.up_store.mkdir(parents=True, exist_ok=True)
78+
except PermissionError:
79+
raise PermissionError(
80+
f"{file_store} is not writable. Fix permissions or change storage directory with --file-storage-directory."
81+
)
6882
self.dictionary_path = Path(dictionary)
6983
# Loads the distributor and client socket
7084
self.distributor = fprime_gds.common.distributor.distributor.Distributor(config)
@@ -76,7 +90,7 @@ def setup(
7690
)
7791
self.histories.setup_histories(self.coders)
7892
self.files.setup_file_handling(
79-
down_store,
93+
self.down_store,
8094
self.coders.file_encoder,
8195
self.coders.file_decoder,
8296
self.distributor,
@@ -152,7 +166,11 @@ def connect(
152166
outgoing_tag: this pipeline will produce data for supplied tag (FSW, GUI). Default: FSW
153167
"""
154168
# Backwards compatibility with the old method .connect(host, port)
155-
if isinstance(incoming_tag, int) and ":" not in connection_uri and outgoing_tag == RoutingTag.FSW:
169+
if (
170+
isinstance(incoming_tag, int)
171+
and ":" not in connection_uri
172+
and outgoing_tag == RoutingTag.FSW
173+
):
156174
connection_uri = f"{connection_uri}:{incoming_tag}"
157175
incoming_tag = RoutingTag.GUI
158176
self.client_socket.connect(connection_uri, incoming_tag, outgoing_tag)

src/fprime_gds/executables/cli.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -547,18 +547,31 @@ def get_arguments(self) -> Dict[Tuple[str, ...], Dict[str, Any]]:
547547

548548
return {
549549
("--file-storage-directory",): {
550-
"dest": "files_directory",
550+
"dest": "files_storage_directory",
551551
"action": "store",
552-
"default": "/tmp/" + username + "/fprime-downlink/",
552+
"default": "/tmp/" + username,
553553
"required": False,
554554
"type": str,
555-
"help": "File to store uplink and downlink files. Default: %(default)s",
556-
}
555+
"help": "Directory to store uplink and downlink files. Default: %(default)s",
556+
},
557+
("--remote-sequence-directory",): {
558+
"dest": "remote_sequence_directory",
559+
"action": "store",
560+
"default": "/seq",
561+
"required": False,
562+
"type": str,
563+
"help": "Directory to save command sequence binaries, on the remote FSW. Default: %(default)s",
564+
},
557565
}
558566

559567
def handle_arguments(self, args, **kwargs):
560568
"""Handle arguments as parsed"""
561-
os.makedirs(args.files_directory, exist_ok=True)
569+
try:
570+
Path(args.files_storage_directory).mkdir(parents=True, exist_ok=True)
571+
except PermissionError:
572+
raise PermissionError(
573+
f"{args.files_storage_directory} is not writable. Fix permissions or change storage directory with --file-storage-directory."
574+
)
562575
return args
563576

564577

@@ -584,7 +597,7 @@ def pipeline_factory(args_ns, pipeline=None) -> StandardPipeline:
584597
pipeline_arguments = {
585598
"config": ConfigManager(),
586599
"dictionary": args_ns.dictionary,
587-
"down_store": args_ns.files_directory,
600+
"file_store": args_ns.files_storage_directory,
588601
"packet_spec": args_ns.packet_spec,
589602
"logging_prefix": args_ns.logs,
590603
}

src/fprime_gds/flask/app.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import fprime_gds.flask.stats
3131
import fprime_gds.flask.updown
3232
from fprime_gds.executables.cli import ParserBase, StandardPipelineParser
33-
from fprime_gds.flask import flask_uploads
3433

3534
from . import components
3635

@@ -49,8 +48,7 @@ def construct_app():
4948
2. Setup JSON encoding for Flask and flask_restful to handle F prime types natively
5049
3. Setup standard pipeline used throughout the system
5150
4. Create Restful API for registering flask items
52-
5. Setup flask_uploads settings
53-
6. Register all restful endpoints
51+
5. Register all restful endpoints
5452
5553
:return: setup app
5654
"""
@@ -77,9 +75,6 @@ def construct_app():
7775

7876
# Restful API registration
7977
api = fprime_gds.flask.errors.setup_error_handling(app)
80-
# File upload configuration, 1 set for everything
81-
uplink_set = flask_uploads.UploadSet("uplink", flask_uploads.ALL)
82-
flask_uploads.configure_uploads(app, [uplink_set])
8378

8479
# Application routes
8580
api.add_resource(
@@ -137,7 +132,7 @@ def construct_app():
137132
api.add_resource(
138133
fprime_gds.flask.updown.FileUploads,
139134
"/upload/files",
140-
resource_class_args=[pipeline.files.uplinker, uplink_set],
135+
resource_class_args=[pipeline.files.uplinker, pipeline.up_store],
141136
)
142137
api.add_resource(
143138
fprime_gds.flask.updown.FileDownload,
@@ -150,9 +145,9 @@ def construct_app():
150145
"/sequence",
151146
resource_class_args=[
152147
args_ns.dictionary,
153-
app.config["UPLOADED_UPLINK_DEST"],
148+
pipeline.up_store,
154149
pipeline.files.uplinker,
155-
app.config["REMOTE_SEQ_DIRECTORY"],
150+
args_ns.remote_sequence_directory,
156151
],
157152
)
158153
api.add_resource(

src/fprime_gds/flask/default_settings.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,12 @@
99
#
1010
####
1111
import os
12-
import getpass
13-
14-
# Select uploads directory and create it
15-
username = getpass.getuser()
16-
uplink_dir = os.environ.get("UP_FILES_DIR", "/tmp/" + username + "/fprime-uplink/")
17-
DOWNLINK_DIR = os.environ.get("DOWN_FILES_DIR", "/tmp/" + username + "/fprime-downlink/")
1812

1913
STANDARD_PIPELINE_ARGUMENTS = os.environ.get("STANDARD_PIPELINE_ARGUMENTS").split("|")
2014

2115
SERVE_LOGS = os.environ.get("SERVE_LOGS", "YES") == "YES"
22-
UPLOADED_UPLINK_DEST = uplink_dir
23-
UPLOADS_DEFAULT_DEST = uplink_dir
24-
REMOTE_SEQ_DIRECTORY = "/seq"
25-
MAX_CONTENT_LENGTH = 32 * 1024 * 1024 # Max length of request is 32MiB
2616

17+
MAX_CONTENT_LENGTH = 32 * 1024 * 1024 # Max length of request is 32MiB
2718

28-
for directory in [UPLOADED_UPLINK_DEST, UPLOADS_DEFAULT_DEST, DOWNLINK_DIR]:
29-
os.makedirs(directory, exist_ok=True)
3019

3120
# TODO: load real config

0 commit comments

Comments
 (0)