1
+ from typing import Dict
2
+ import asyncio
3
+ import logging
4
+ import requests
5
+ from requests .auth import HTTPBasicAuth
6
+ from ..models .pod import PodRef
7
+ from .pod import PodService
8
+ from ..config import _config
9
+
10
+ r_status = None
11
+ r_packages = None
12
+ datashield_packages = None
13
+
14
+ class RService :
15
+ def __init__ (self ):
16
+ self .pod = None
17
+
18
+ async def get_status (self ) -> Dict :
19
+ """Fetches the status of the R server."""
20
+ global r_status
21
+ logging .info (f"Current R status: { r_status } " )
22
+ if r_status is not None :
23
+ return r_status
24
+ logging .info ("Fetching R status" )
25
+ await self .connect ()
26
+ r_status = self ._fetch ("/rserver" )
27
+ return r_status
28
+
29
+ async def get_packages (self ) -> Dict :
30
+ """Fetches the list of available packages."""
31
+ global r_packages
32
+ logging .info (f"Current R packages: { r_packages } " )
33
+ if r_packages is not None :
34
+ return r_packages
35
+ await self .connect ()
36
+ r_packages = self ._fetch ("/rserver/packages" )
37
+ return r_packages
38
+
39
+ async def get_datashield_packages (self ) -> Dict :
40
+ """Fetches the list of available DataSHIELD packages."""
41
+ global datashield_packages
42
+ logging .info (f"Current DataSHIELD packages: { datashield_packages } " )
43
+ if datashield_packages is not None :
44
+ return datashield_packages
45
+ await self .connect ()
46
+ datashield_packages = self ._fetch ("/rserver/packages/_datashield" )
47
+ return datashield_packages
48
+
49
+ async def connect (self ):
50
+ """Connects to the R server."""
51
+ if self .pod is None :
52
+ self .pod = await PodService ().create_pod (wait = True )
53
+ await self ._ensure_ready (self .pod )
54
+
55
+ async def close (self ):
56
+ """Disconnects from the R server."""
57
+ if self .pod is not None :
58
+ await PodService ().delete_pod (self .pod .name )
59
+ self .pod = None
60
+
61
+ async def _ensure_ready (self , pod : PodRef ):
62
+ """Ensures the R server is ready to receive requests."""
63
+ ready = self ._check (pod )
64
+ attempts = 0
65
+ while not ready and attempts < 10 :
66
+ await asyncio .sleep (1 )
67
+ ready = self ._check (pod )
68
+ attempts += 1
69
+ logging .info (f"R Server ready: { ready } after { attempts } attempts" )
70
+ if not ready :
71
+ raise Exception ("R Server not ready" )
72
+
73
+ def _check (self , pod : PodRef ) -> bool :
74
+ """Checks if the R server is ready to receive requests."""
75
+ url = f"http://{ pod .ip } :{ pod .port } /_check"
76
+ logging .info (f"Checking { url } " )
77
+ try :
78
+ response = requests .get (url )
79
+ if response .status_code >= 200 and response .status_code < 300 :
80
+ return True
81
+ except Exception as e :
82
+ logging .error (f"Error checking R Server: { e } " )
83
+ return False
84
+
85
+ def _fetch (self , path : str ) -> Dict :
86
+ """Fetches a path from the R server."""
87
+ url = f"http://{ self .pod .ip } :{ self .pod .port } { path } "
88
+ basicAuth = HTTPBasicAuth (_config .ROCK_ADMINISTRATOR_NAME if _config .ROCK_ADMINISTRATOR_NAME != "" else "administrator" ,
89
+ _config .ROCK_ADMINISTRATOR_PASSWORD if _config .ROCK_ADMINISTRATOR_PASSWORD != "" else "password" )
90
+ logging .info (f"Fetching { url } " )
91
+ response = requests .get (url , auth = basicAuth )
92
+ response .raise_for_status ()
93
+ return response .json ()
0 commit comments