Skip to content

Commit b55f1e7

Browse files
committed
Migrated contents of 'murfey.client.__init__' to new module 'murfey.client.tui.main', since its contents are related to the initialisation of the TUI app
Removed unused key 'default_destination' from 'MurfeyInstanceEnvironment' setup, along with commented out keys
1 parent d8a7c9b commit b55f1e7

File tree

2 files changed

+344
-348
lines changed

2 files changed

+344
-348
lines changed

src/murfey/client/__init__.py

Lines changed: 0 additions & 348 deletions
Original file line numberDiff line numberDiff line change
@@ -1,348 +0,0 @@
1-
from __future__ import annotations
2-
3-
import argparse
4-
import configparser
5-
import logging
6-
import os
7-
import platform
8-
import shutil
9-
import sys
10-
import time
11-
import webbrowser
12-
from datetime import datetime
13-
from pathlib import Path
14-
from pprint import pprint
15-
from queue import Queue
16-
from typing import Literal
17-
from urllib.parse import ParseResult, urlparse
18-
19-
import requests
20-
from rich.prompt import Confirm
21-
22-
import murfey.client.update
23-
import murfey.client.watchdir
24-
import murfey.client.websocket
25-
from murfey.client.customlogging import CustomHandler, DirectableRichHandler
26-
from murfey.client.instance_environment import MurfeyInstanceEnvironment
27-
from murfey.client.tui.app import MurfeyTUI
28-
from murfey.client.tui.status_bar import StatusBar
29-
from murfey.util.api import url_path_for
30-
from murfey.util.client import authorised_requests, read_config
31-
from murfey.util.models import Visit
32-
33-
log = logging.getLogger("murfey.client")
34-
35-
requests.get, requests.post, requests.put, requests.delete = authorised_requests()
36-
37-
38-
def _get_visit_list(api_base: ParseResult, instrument_name: str):
39-
proxy_path = api_base.path.rstrip("/")
40-
get_visits_url = api_base._replace(
41-
path=f"{proxy_path}{url_path_for('session_control.router', 'get_current_visits', instrument_name=instrument_name)}"
42-
)
43-
server_reply = requests.get(get_visits_url.geturl())
44-
if server_reply.status_code != 200:
45-
raise ValueError(f"Server unreachable ({server_reply.status_code})")
46-
return [Visit.parse_obj(v) for v in server_reply.json()]
47-
48-
49-
def write_config(config: configparser.ConfigParser):
50-
mcch = os.environ.get("MURFEY_CLIENT_CONFIG_HOME")
51-
murfey_client_config_home = Path(mcch) if mcch else Path.home()
52-
with open(murfey_client_config_home / ".murfey", "w") as configfile:
53-
config.write(configfile)
54-
55-
56-
def main_loop(
57-
source_watchers: list[murfey.client.watchdir.DirWatcher],
58-
appearance_time: float,
59-
transfer_all: bool,
60-
):
61-
log.info(
62-
f"Murfey {murfey.__version__} on Python {'.'.join(map(str, sys.version_info[0:3]))} entering main loop"
63-
)
64-
if appearance_time > 0:
65-
modification_time: float | None = time.time() - appearance_time * 3600
66-
else:
67-
modification_time = None
68-
while True:
69-
for sw in source_watchers:
70-
sw.scan(modification_time=modification_time, transfer_all=transfer_all)
71-
time.sleep(15)
72-
73-
74-
def _enable_webbrowser_in_cygwin():
75-
"""Helper function to make webbrowser.open() work in CygWin"""
76-
if "cygwin" in platform.system().lower() and shutil.which("cygstart"):
77-
webbrowser.register("cygstart", None, webbrowser.GenericBrowser("cygstart"))
78-
79-
80-
def _check_for_updates(
81-
server: ParseResult, install_version: None | Literal[True] | str
82-
):
83-
if install_version is True:
84-
# User requested installation of the newest version
85-
try:
86-
murfey.client.update.check(server, force=True)
87-
print("\nYou are already running the newest version of Murfey")
88-
exit()
89-
except Exception as e:
90-
exit(f"Murfey update check failed with {e}")
91-
92-
if install_version:
93-
# User requested installation of a specific version
94-
if murfey.client.update.install_murfey(server, install_version):
95-
print(f"\nMurfey has been updated to version {install_version}")
96-
exit()
97-
else:
98-
exit("Error occurred while updating Murfey")
99-
100-
# Otherwise run a routine update check to ensure client and server are compatible
101-
try:
102-
murfey.client.update.check(server)
103-
except Exception as e:
104-
print(f"Murfey update check failed with {e}")
105-
106-
107-
def run():
108-
# Load client config and server information
109-
config = read_config()
110-
instrument_name = config["Murfey"]["instrument_name"]
111-
try:
112-
server_routing = config["ServerRouter"]
113-
except KeyError:
114-
server_routing = {}
115-
server_routing_prefix_found = False
116-
if server_routing:
117-
for path_prefix, server in server_routing.items():
118-
if str(Path.cwd()).startswith(path_prefix):
119-
known_server = server
120-
server_routing_prefix_found = True
121-
break
122-
else:
123-
known_server = None
124-
else:
125-
known_server = config["Murfey"].get("server")
126-
127-
# Set up argument parser with dynamic defaults based on client config
128-
parser = argparse.ArgumentParser(description="Start the Murfey client")
129-
parser.add_argument(
130-
"--server",
131-
metavar="HOST:PORT",
132-
type=str,
133-
help=f"Murfey server to connect to ({known_server})",
134-
default=known_server,
135-
)
136-
parser.add_argument("--visit", help="Name of visit")
137-
parser.add_argument(
138-
"--source", help="Directory to transfer files from", type=Path, default="."
139-
)
140-
parser.add_argument(
141-
"--destination",
142-
help="Directory to transfer files to (syntax: 'data/2022/cm31093-2/tmp/murfey')",
143-
)
144-
parser.add_argument(
145-
"--update",
146-
metavar="VERSION",
147-
nargs="?",
148-
default=None,
149-
const=True,
150-
help="Update Murfey to the newest or to a specific version",
151-
)
152-
parser.add_argument(
153-
"--demo",
154-
action="store_true",
155-
)
156-
parser.add_argument(
157-
"--appearance-time",
158-
type=float,
159-
default=-1,
160-
help="Only consider top level directories that have appeared more recently than this many hours ago",
161-
)
162-
parser.add_argument(
163-
"--fake-dc",
164-
action="store_true",
165-
default=False,
166-
help="Do not perform data collection related calls to API (avoids database inserts)",
167-
)
168-
parser.add_argument(
169-
"--time-based-transfer",
170-
action="store_true",
171-
help="Transfer new files",
172-
)
173-
parser.add_argument(
174-
"--no-transfer",
175-
action="store_true",
176-
help="Avoid actually transferring files",
177-
)
178-
parser.add_argument(
179-
"--debug",
180-
action="store_true",
181-
help="Turn on debugging logs",
182-
)
183-
parser.add_argument(
184-
"--local",
185-
action="store_true",
186-
default=False,
187-
help="Perform rsync transfers locally rather than remotely",
188-
)
189-
parser.add_argument(
190-
"--ignore-mdoc-metadata",
191-
action="store_true",
192-
default=False,
193-
help="Do not attempt to read metadata from all mdoc files",
194-
)
195-
parser.add_argument(
196-
"--remove-files",
197-
action="store_true",
198-
default=False,
199-
help="Remove source files immediately after their transfer",
200-
)
201-
parser.add_argument(
202-
"--name",
203-
type=str,
204-
default="",
205-
help="Name of Murfey session to be created",
206-
)
207-
parser.add_argument(
208-
"--skip-existing-processing",
209-
action="store_true",
210-
default=False,
211-
help="Do not trigger processing for any data directories currently on disk (you may have started processing for them in a previous murfey run)",
212-
)
213-
args = parser.parse_args()
214-
215-
# Logic to exit early based on parsed args
216-
if not args.server:
217-
exit("Murfey server not set. Please run with --server host:port")
218-
if not args.server.startswith(("http://", "https://")):
219-
if "://" in args.server:
220-
exit("Unknown server protocol. Only http:// and https:// are allowed")
221-
args.server = f"http://{args.server}"
222-
if args.remove_files:
223-
remove_prompt = Confirm.ask(
224-
f"Are you sure you want to remove files from {args.source or Path('.').absolute()}?"
225-
)
226-
if not remove_prompt:
227-
exit("Exiting")
228-
229-
# If a new server URL is provided, save info to config file
230-
murfey_url = urlparse(args.server, allow_fragments=False)
231-
if args.server != known_server:
232-
# New server specified. Verify that it is real
233-
print(f"Attempting to connect to new server {args.server}")
234-
try:
235-
murfey.client.update.check(murfey_url, install=False)
236-
except Exception as e:
237-
exit(f"Could not reach Murfey server at {args.server!r} - {e}")
238-
239-
# If server is reachable then update the configuration
240-
config["Murfey"]["server"] = args.server
241-
write_config(config)
242-
243-
# If user requested installation of a specific or a newer version then
244-
# make that happen, otherwise ensure client and server are compatible and
245-
# update if necessary.
246-
_check_for_updates(server=murfey_url, install_version=args.update)
247-
248-
if args.no_transfer:
249-
log.info("No files will be transferred as --no-transfer flag was specified")
250-
251-
# Check ISPyB (if set up) for ongoing visits
252-
ongoing_visits = []
253-
if args.visit:
254-
ongoing_visits = [args.visit]
255-
elif server_routing_prefix_found:
256-
for part in Path.cwd().parts:
257-
if "-" in part:
258-
ongoing_visits = [part]
259-
break
260-
if not ongoing_visits:
261-
print("Ongoing visits:")
262-
ongoing_visits = _get_visit_list(murfey_url, instrument_name)
263-
pprint(ongoing_visits)
264-
ongoing_visits = [v.name for v in ongoing_visits]
265-
266-
_enable_webbrowser_in_cygwin()
267-
268-
# Set up additional log handlers
269-
log.setLevel(logging.DEBUG)
270-
log_queue = Queue()
271-
input_queue = Queue()
272-
273-
# Rich-based console handler
274-
rich_handler = DirectableRichHandler(enable_link_path=False)
275-
rich_handler.setLevel(logging.DEBUG if args.debug else logging.INFO)
276-
277-
# Set up websocket app and handler
278-
client_id_response = requests.get(
279-
f"{murfey_url.geturl()}{url_path_for('session_control.router', 'new_client_id')}"
280-
)
281-
if client_id_response.status_code == 401:
282-
exit(
283-
"This instrument is not authorised to run the TUI app; please use the "
284-
"Murfey web UI instead"
285-
)
286-
elif client_id_response.status_code != 200:
287-
exit(
288-
"Unable to establish connection to Murfey server: \n"
289-
f"{client_id_response.json()}"
290-
)
291-
client_id: dict = client_id_response.json()
292-
ws = murfey.client.websocket.WSApp(
293-
server=args.server,
294-
id=client_id["new_id"],
295-
)
296-
ws_handler = CustomHandler(ws.send)
297-
298-
# Add additional handlers and set logging levels
299-
logging.getLogger().addHandler(rich_handler)
300-
logging.getLogger().addHandler(ws_handler)
301-
logging.getLogger("murfey").setLevel(logging.INFO)
302-
logging.getLogger("websocket").setLevel(logging.WARNING)
303-
304-
log.info("Starting Websocket connection")
305-
306-
# Load machine data for subsequent sections
307-
machine_data = requests.get(
308-
f"{murfey_url.geturl()}{url_path_for('session_control.router', 'machine_info_by_instrument', instrument_name=instrument_name)}"
309-
).json()
310-
gain_ref: Path | None = None
311-
312-
# Set up Murfey environment instance and map it to websocket app
313-
instance_environment = MurfeyInstanceEnvironment(
314-
url=murfey_url,
315-
client_id=ws.id,
316-
instrument_name=instrument_name,
317-
software_versions=machine_data.get("software_versions", {}),
318-
# sources=[Path(args.source)],
319-
# watchers=source_watchers,
320-
default_destination=args.destination or str(datetime.now().year),
321-
demo=args.demo,
322-
processing_only_mode=server_routing_prefix_found,
323-
rsync_url=(
324-
urlparse(machine_data["rsync_url"]).hostname
325-
if machine_data.get("rsync_url")
326-
else ""
327-
),
328-
)
329-
ws.environment = instance_environment
330-
331-
# Set up and run Murfey TUI app
332-
status_bar = StatusBar()
333-
rich_handler.redirect = True
334-
app = MurfeyTUI(
335-
environment=instance_environment,
336-
visits=ongoing_visits,
337-
queues={"input": input_queue, "logs": log_queue},
338-
status_bar=status_bar,
339-
dummy_dc=args.fake_dc,
340-
do_transfer=not args.no_transfer,
341-
gain_ref=gain_ref,
342-
redirected_logger=rich_handler,
343-
force_mdoc_metadata=not args.ignore_mdoc_metadata,
344-
processing_enabled=machine_data.get("processing_enabled", True),
345-
skip_existing_processing=args.skip_existing_processing,
346-
)
347-
app.run()
348-
rich_handler.redirect = False

0 commit comments

Comments
 (0)