saviialib 1.3.0__py3-none-any.whl → 1.5.0__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 saviialib might be problematic. Click here for more details.
- saviialib/__init__.py +73 -3
- saviialib/general_types/api/__init__.py +0 -3
- saviialib/general_types/api/{epii_api_types.py → saviia_api_types.py} +2 -38
- saviialib/general_types/api/saviia_backup_api_types.py +24 -0
- saviialib/general_types/api/saviia_netcamera_api_types.py +11 -0
- saviialib/general_types/api/saviia_shakes_api_types.py +21 -0
- saviialib/general_types/api/saviia_thies_api_types.py +31 -0
- saviialib/general_types/error_types/api/{epii_api_error_types.py → saviia_api_error_types.py} +8 -0
- saviialib/general_types/error_types/api/saviia_netcamera_error_types.py +7 -0
- saviialib/general_types/error_types/common/common_types.py +9 -0
- saviialib/libs/directory_client/client/os_client.py +1 -1
- saviialib/libs/ffmpeg_client/__init__.py +8 -0
- saviialib/libs/ffmpeg_client/clients/ffmpeg_asyncio_client.py +101 -0
- saviialib/libs/ffmpeg_client/ffmpeg_client.py +25 -0
- saviialib/libs/ffmpeg_client/ffmpeg_client_contract.py +12 -0
- saviialib/libs/ffmpeg_client/types/ffmpeg_client_types.py +28 -0
- saviialib/libs/sftp_client/__init__.py +8 -0
- saviialib/libs/sftp_client/clients/asyncssh_sftp_client.py +83 -0
- saviialib/libs/sftp_client/sftp_client.py +26 -0
- saviialib/libs/sftp_client/sftp_client_contract.py +13 -0
- saviialib/libs/sftp_client/types/sftp_client_types.py +24 -0
- saviialib/libs/sharepoint_client/clients/sharepoint_rest_api.py +7 -3
- saviialib/libs/zero_dependency/utils/strings_utils.py +5 -0
- saviialib/services/backup/api.py +36 -0
- saviialib/services/{epii → backup}/controllers/types/__init__.py +1 -1
- saviialib/services/{epii → backup}/controllers/types/upload_backup_to_sharepoint_types.py +2 -2
- saviialib/services/{epii → backup}/controllers/upload_backup_to_sharepoint.py +5 -5
- saviialib/services/{epii → backup}/use_cases/types/__init__.py +1 -1
- saviialib/services/{epii → backup}/use_cases/types/upload_backup_to_sharepoint_types.py +1 -1
- saviialib/services/{epii → backup}/use_cases/upload_backup_to_sharepoint.py +2 -2
- saviialib/services/backup/utils/__init__.py +3 -0
- saviialib/services/{epii → backup}/utils/upload_backup_to_sharepoint_utils.py +1 -1
- saviialib/services/netcamera/api.py +30 -0
- saviialib/services/netcamera/controllers/get_media_files.py +40 -0
- saviialib/services/netcamera/controllers/types/get_media_files_types.py +16 -0
- saviialib/services/netcamera/use_cases/get_media_files.py +76 -0
- saviialib/services/netcamera/use_cases/types/get_media_files_types.py +18 -0
- saviialib/services/shakes/__init__.py +0 -0
- saviialib/services/shakes/api.py +31 -0
- saviialib/services/shakes/controllers/get_miniseed_files.py +48 -0
- saviialib/services/shakes/controllers/types/get_miniseed_files_types.py +16 -0
- saviialib/services/shakes/use_cases/get_miniseed_files.py +79 -0
- saviialib/services/shakes/use_cases/types/get_miniseed_files_types.py +18 -0
- saviialib/services/shakes/use_cases/utils/get_miniseed_files_utils.py +11 -0
- saviialib/services/thies/__init__.py +0 -0
- saviialib/services/thies/api.py +35 -0
- saviialib/services/{epii → thies}/controllers/types/update_thies_data_types.py +2 -4
- saviialib/services/{epii → thies}/controllers/update_thies_data.py +4 -4
- saviialib/services/{epii → thies}/use_cases/components/create_thies_statistics_file.py +11 -2
- saviialib/services/{epii → thies}/use_cases/types/update_thies_data_types.py +4 -1
- saviialib/services/{epii → thies}/use_cases/update_thies_data.py +19 -12
- saviialib-1.5.0.dist-info/METADATA +126 -0
- saviialib-1.5.0.dist-info/RECORD +87 -0
- {saviialib-1.3.0.dist-info → saviialib-1.5.0.dist-info}/WHEEL +1 -1
- saviialib/services/epii/api.py +0 -94
- saviialib/services/epii/utils/__init__.py +0 -3
- saviialib-1.3.0.dist-info/METADATA +0 -122
- saviialib-1.3.0.dist-info/RECORD +0 -57
- /saviialib/services/{epii → backup}/__init__.py +0 -0
- /saviialib/services/{epii → backup}/controllers/__init__.py +0 -0
- /saviialib/services/{epii → backup}/use_cases/constants/upload_backup_to_sharepoint_constants.py +0 -0
- /saviialib/services/{epii → thies}/use_cases/components/thies_bp.py +0 -0
- /saviialib/services/{epii → thies}/utils/update_thies_data_utils.py +0 -0
- {saviialib-1.3.0.dist-info → saviialib-1.5.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
|
|
3
|
+
from .controllers.upload_backup_to_sharepoint import (
|
|
4
|
+
UploadBackupToSharepointControllerInput,
|
|
5
|
+
)
|
|
6
|
+
from .controllers.upload_backup_to_sharepoint import UploadBackupToSharepointController
|
|
7
|
+
from saviialib.general_types.api.saviia_backup_api_types import SaviiaBackupConfig
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SaviiaBackupAPI:
|
|
11
|
+
"""
|
|
12
|
+
EpiiAPI is a service class that provides methods to interact with Patagonia Center system.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, config: SaviiaBackupConfig):
|
|
16
|
+
self.config = config
|
|
17
|
+
|
|
18
|
+
async def upload_backup_to_sharepoint(
|
|
19
|
+
self, local_backup_source_path: str, sharepoint_destination_path: str
|
|
20
|
+
) -> Dict[str, Any]:
|
|
21
|
+
"""Migrate a backup folder from Home assistant to Sharepoint directory.
|
|
22
|
+
Args:
|
|
23
|
+
local_backup_source_path (str): Local path to backup.
|
|
24
|
+
Returns:
|
|
25
|
+
response (dict): A dictionary containing the response from the upload operation.
|
|
26
|
+
This dictionary will typically include information about the success or
|
|
27
|
+
failure of the upload, as well as any relevant metadata.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
controller = UploadBackupToSharepointController(
|
|
31
|
+
UploadBackupToSharepointControllerInput(
|
|
32
|
+
self.config, local_backup_source_path, sharepoint_destination_path
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
response = await controller.execute()
|
|
36
|
+
return response.__dict__
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
2
|
from typing import Dict
|
|
3
3
|
|
|
4
|
-
from saviialib.general_types.api.
|
|
4
|
+
from saviialib.general_types.api.saviia_backup_api_types import SaviiaBackupConfig
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
@dataclass
|
|
8
8
|
class UploadBackupToSharepointControllerInput:
|
|
9
|
-
config:
|
|
9
|
+
config: SaviiaBackupConfig
|
|
10
10
|
local_backup_source_path: str
|
|
11
11
|
sharepoint_destination_path: str
|
|
12
12
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from http import HTTPStatus
|
|
2
|
-
from saviialib.general_types.api.
|
|
2
|
+
from saviialib.general_types.api.saviia_api_types import SharepointConfig
|
|
3
3
|
|
|
4
|
-
from saviialib.general_types.error_types.api.
|
|
4
|
+
from saviialib.general_types.error_types.api.saviia_api_error_types import (
|
|
5
5
|
BackupUploadError,
|
|
6
6
|
BackupSourcePathError,
|
|
7
7
|
BackupEmptyError,
|
|
@@ -10,14 +10,14 @@ from saviialib.general_types.error_types.common.common_types import (
|
|
|
10
10
|
EmptyDataError,
|
|
11
11
|
SharepointClientError,
|
|
12
12
|
)
|
|
13
|
-
from saviialib.services.
|
|
13
|
+
from saviialib.services.backup.controllers.types.upload_backup_to_sharepoint_types import (
|
|
14
14
|
UploadBackupToSharepointControllerInput,
|
|
15
15
|
UploadBackupToSharepointControllerOutput,
|
|
16
16
|
)
|
|
17
|
-
from saviialib.services.
|
|
17
|
+
from saviialib.services.backup.use_cases.types.upload_backup_to_sharepoint_types import (
|
|
18
18
|
UploadBackupToSharepointUseCaseInput,
|
|
19
19
|
)
|
|
20
|
-
from saviialib.services.
|
|
20
|
+
from saviialib.services.backup.use_cases.upload_backup_to_sharepoint import (
|
|
21
21
|
UploadBackupToSharepointUsecase,
|
|
22
22
|
)
|
|
23
23
|
|
|
@@ -2,7 +2,7 @@ import asyncio
|
|
|
2
2
|
from time import time
|
|
3
3
|
from saviialib.libs.zero_dependency.utils.datetime_utils import today, datetime_to_str
|
|
4
4
|
from logging import Logger
|
|
5
|
-
from saviialib.general_types.error_types.api.
|
|
5
|
+
from saviialib.general_types.error_types.api.saviia_api_error_types import (
|
|
6
6
|
BackupEmptyError,
|
|
7
7
|
BackupSourcePathError,
|
|
8
8
|
BackupUploadError,
|
|
@@ -23,7 +23,7 @@ from saviialib.libs.sharepoint_client import (
|
|
|
23
23
|
SpUploadFileArgs,
|
|
24
24
|
SpCreateFolderArgs,
|
|
25
25
|
)
|
|
26
|
-
from saviialib.services.
|
|
26
|
+
from saviialib.services.backup.utils.upload_backup_to_sharepoint_utils import (
|
|
27
27
|
calculate_percentage_uploaded,
|
|
28
28
|
count_files_in_directory,
|
|
29
29
|
extract_error_message,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import re
|
|
2
2
|
from logging import Logger
|
|
3
3
|
from typing import List, Dict, Optional
|
|
4
|
-
from saviialib.general_types.error_types.api.
|
|
4
|
+
from saviialib.general_types.error_types.api.saviia_api_error_types import (
|
|
5
5
|
BackupSourcePathError,
|
|
6
6
|
)
|
|
7
7
|
from saviialib.libs.directory_client import DirectoryClient, DirectoryClientArgs
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from .controllers.get_media_files import (
|
|
2
|
+
GetMediaFilesController,
|
|
3
|
+
GetMediaFilesControllerInput,
|
|
4
|
+
)
|
|
5
|
+
from typing import Dict, Tuple, Any
|
|
6
|
+
from saviialib.general_types.api.saviia_netcamera_api_types import SaviiaNetcameraConfig
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class NetcameraAPI:
|
|
10
|
+
"""This class provides methods for interacting with network cameras and retrieving
|
|
11
|
+
files using streaming services."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, config: SaviiaNetcameraConfig):
|
|
14
|
+
self.config = config
|
|
15
|
+
|
|
16
|
+
async def get_media_files(
|
|
17
|
+
self, cameras: Dict[str, Tuple[str, int]]
|
|
18
|
+
) -> Dict[str, Any]:
|
|
19
|
+
"""Retrieve media files from Network cameras.
|
|
20
|
+
|
|
21
|
+
:param cameras: Dictionary where the key is the identifier of the camera, and the
|
|
22
|
+
value is a tuple wich contains the service IP address and port of connection.
|
|
23
|
+
Example: {'cam_01': ('192.168.1.10', 8080), ...}
|
|
24
|
+
:type cameras: dict
|
|
25
|
+
:return response: A dictionary containg information of the extraction operation.
|
|
26
|
+
:rtype: dict
|
|
27
|
+
"""
|
|
28
|
+
controller = GetMediaFilesController(GetMediaFilesControllerInput(cameras))
|
|
29
|
+
response = await controller.execute()
|
|
30
|
+
return response.__dict__
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from .types.get_media_files_types import (
|
|
2
|
+
GetMediaFilesControllerInput,
|
|
3
|
+
GetMediaFilesControllerOutput,
|
|
4
|
+
)
|
|
5
|
+
from saviialib.services.netcamera.use_cases.get_media_files import (
|
|
6
|
+
GetMediaFilesUseCase,
|
|
7
|
+
GetMediaFilesUseCaseInput,
|
|
8
|
+
)
|
|
9
|
+
from http import HTTPStatus
|
|
10
|
+
from saviialib.general_types.error_types.api.saviia_netcamera_error_types import (
|
|
11
|
+
NetcameraConnectionError,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class GetMediaFilesController:
|
|
16
|
+
def __init__(self, input: GetMediaFilesControllerInput) -> None:
|
|
17
|
+
self.use_case = GetMediaFilesUseCase(
|
|
18
|
+
GetMediaFilesUseCaseInput(
|
|
19
|
+
cameras=input.cameras,
|
|
20
|
+
username=input.config.username,
|
|
21
|
+
password=input.config.password,
|
|
22
|
+
protocol=input.config.protocol,
|
|
23
|
+
logger=input.config.logger,
|
|
24
|
+
destination_path=input.config.destination_path,
|
|
25
|
+
)
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
async def execute(self) -> GetMediaFilesControllerOutput:
|
|
29
|
+
try:
|
|
30
|
+
_ = await self.use_case.execute()
|
|
31
|
+
return GetMediaFilesControllerOutput(
|
|
32
|
+
message="The extraction of media files was successfully!",
|
|
33
|
+
status=HTTPStatus.OK.value,
|
|
34
|
+
)
|
|
35
|
+
except NetcameraConnectionError as error:
|
|
36
|
+
return GetMediaFilesControllerOutput(
|
|
37
|
+
message="An unnexpected error ocurred while extractingphotos and videos.",
|
|
38
|
+
status=HTTPStatus.GATEWAY_TIMEOUT.value,
|
|
39
|
+
metadata={"error": error.__str__()},
|
|
40
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Dict, Tuple
|
|
3
|
+
from saviialib.general_types.api.saviia_netcamera_api_types import SaviiaNetcameraConfig
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class GetMediaFilesControllerInput:
|
|
8
|
+
config = SaviiaNetcameraConfig
|
|
9
|
+
cameras: Dict[str, Tuple[str, int]]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class GetMediaFilesControllerOutput:
|
|
14
|
+
status: int
|
|
15
|
+
message: str
|
|
16
|
+
metadata: Dict = field(default_factory=dict)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from .types.get_media_files_types import (
|
|
2
|
+
GetMediaFilesUseCaseInput,
|
|
3
|
+
GetMediaFilesUseCaseOutput,
|
|
4
|
+
)
|
|
5
|
+
from saviialib.libs.ffmpeg_client import (
|
|
6
|
+
FfmpegClient,
|
|
7
|
+
FfmpegClientInitArgs,
|
|
8
|
+
RecordVideoArgs,
|
|
9
|
+
RecordPhotoArgs,
|
|
10
|
+
)
|
|
11
|
+
from saviialib.libs.zero_dependency.utils.strings_utils import are_equal
|
|
12
|
+
from typing import Tuple, Dict
|
|
13
|
+
from saviialib.libs.directory_client.directory_client import (
|
|
14
|
+
DirectoryClient,
|
|
15
|
+
DirectoryClientArgs,
|
|
16
|
+
)
|
|
17
|
+
from saviialib.general_types.error_types.api.saviia_netcamera_error_types import (
|
|
18
|
+
NetcameraConnectionError,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class GetMediaFilesUseCase:
|
|
23
|
+
def __init__(self, input: GetMediaFilesUseCaseInput) -> None:
|
|
24
|
+
self.ffmpeg_client = FfmpegClient(
|
|
25
|
+
FfmpegClientInitArgs(
|
|
26
|
+
client_name="ffmpeg_asyncio",
|
|
27
|
+
)
|
|
28
|
+
)
|
|
29
|
+
self.dir_client = DirectoryClient(DirectoryClientArgs("os_client"))
|
|
30
|
+
self.user = input.username
|
|
31
|
+
self.pwd = input.password
|
|
32
|
+
self.cameras: Dict[str, Tuple[str, int]] = input.cameras
|
|
33
|
+
self.protocol = input.protocol
|
|
34
|
+
self.logger = input.logger
|
|
35
|
+
self.dest_path = input.destination_path
|
|
36
|
+
|
|
37
|
+
async def _retieve_with_rtsp(self):
|
|
38
|
+
for name, conn in self.cameras.items():
|
|
39
|
+
ip, port = conn
|
|
40
|
+
dest_path = self.dir_client.join_paths(self.dest_path, name)
|
|
41
|
+
try:
|
|
42
|
+
# Extraction of photo files into dest_path dir.
|
|
43
|
+
await self.ffmpeg_client.record_photo(
|
|
44
|
+
RecordPhotoArgs(
|
|
45
|
+
ip_address=ip,
|
|
46
|
+
port=str(port),
|
|
47
|
+
destination_path=dest_path,
|
|
48
|
+
rtsp_user=self.user,
|
|
49
|
+
rtsp_password=self.pwd,
|
|
50
|
+
extension="jpg",
|
|
51
|
+
frames=1,
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
# Extraction of video files into dest_path dir.
|
|
55
|
+
await self.ffmpeg_client.record_video(
|
|
56
|
+
RecordVideoArgs(
|
|
57
|
+
destination_path=dest_path,
|
|
58
|
+
ip_address=ip,
|
|
59
|
+
port=str(port),
|
|
60
|
+
rtsp_user=self.user,
|
|
61
|
+
rtsp_password=self.pwd,
|
|
62
|
+
extension="mp3",
|
|
63
|
+
duration=10,
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
except ConnectionError as error:
|
|
67
|
+
raise NetcameraConnectionError(reason=error)
|
|
68
|
+
|
|
69
|
+
async def execute(self) -> GetMediaFilesUseCaseOutput:
|
|
70
|
+
if are_equal(self.protocol, "rtsp"):
|
|
71
|
+
await self._retieve_with_rtsp()
|
|
72
|
+
else:
|
|
73
|
+
raise NotImplementedError(
|
|
74
|
+
f"The media files extraction with {self.protocol} is not implemented yet."
|
|
75
|
+
)
|
|
76
|
+
return GetMediaFilesUseCaseOutput()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from logging import Logger
|
|
3
|
+
from typing import Dict, Tuple
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class GetMediaFilesUseCaseInput:
|
|
8
|
+
cameras: Dict[str, Tuple[str, int]]
|
|
9
|
+
username: str
|
|
10
|
+
password: str
|
|
11
|
+
protocol: str
|
|
12
|
+
logger: Logger
|
|
13
|
+
destination_path: str
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class GetMediaFilesUseCaseOutput:
|
|
18
|
+
pass
|
|
File without changes
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from .controllers.get_miniseed_files import (
|
|
2
|
+
GetMiniseedFilesController,
|
|
3
|
+
GetMiniseedFilesControllerInput,
|
|
4
|
+
)
|
|
5
|
+
from saviialib.general_types.api.saviia_shakes_api_types import SaviiaShakesConfig
|
|
6
|
+
|
|
7
|
+
from typing import Dict
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ShakesAPI:
|
|
11
|
+
"""This class provides methods for interacting with Raspberry Shakes"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, config: SaviiaShakesConfig) -> None:
|
|
14
|
+
self.config = config
|
|
15
|
+
|
|
16
|
+
async def get_miniseed_files(self, raspberry_shakes: Dict[str, str]):
|
|
17
|
+
"""Download the MiniSEED files from the SFTP Server provided by each Raspberry Shake.
|
|
18
|
+
Args:
|
|
19
|
+
raspberry_shakes (dict): Dictionary where the key is the name of the Raspberry Shake,
|
|
20
|
+
and the value is the IP Address.
|
|
21
|
+
Returns:
|
|
22
|
+
response (dict): A dictionary containg the response from the download operation.
|
|
23
|
+
This response will tipically include the message, the response status, and metadata.
|
|
24
|
+
"""
|
|
25
|
+
controller = GetMiniseedFilesController(
|
|
26
|
+
GetMiniseedFilesControllerInput(
|
|
27
|
+
config=self.config, raspberry_shakes=raspberry_shakes
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
response = await controller.execute()
|
|
31
|
+
return response.__dict__
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from .types.get_miniseed_files_types import (
|
|
2
|
+
GetMiniseedFilesControllerInput,
|
|
3
|
+
GetMiniseedFilesControllerOutput,
|
|
4
|
+
)
|
|
5
|
+
from saviialib.services.shakes.use_cases.get_miniseed_files import (
|
|
6
|
+
GetMiniseedFilesUseCase,
|
|
7
|
+
GetMiniseedFilesUseCaseInput,
|
|
8
|
+
)
|
|
9
|
+
from http import HTTPStatus
|
|
10
|
+
from saviialib.general_types.error_types.api.saviia_api_error_types import (
|
|
11
|
+
ShakesNoContentError,
|
|
12
|
+
)
|
|
13
|
+
from saviialib.general_types.error_types.common.common_types import SftpClientError
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class GetMiniseedFilesController:
|
|
17
|
+
def __init__(self, input: GetMiniseedFilesControllerInput) -> None:
|
|
18
|
+
self.use_case = GetMiniseedFilesUseCase(
|
|
19
|
+
GetMiniseedFilesUseCaseInput(
|
|
20
|
+
raspberry_shakes=input.raspberry_shakes,
|
|
21
|
+
username=input.config.sftp_user,
|
|
22
|
+
password=input.config.sftp_password,
|
|
23
|
+
ssh_key_path=input.config.ssh_key_path,
|
|
24
|
+
port=input.config.sftp_port,
|
|
25
|
+
logger=input.config.logger,
|
|
26
|
+
)
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
async def execute(self) -> GetMiniseedFilesControllerOutput:
|
|
30
|
+
try:
|
|
31
|
+
res = await self.use_case.execute()
|
|
32
|
+
return GetMiniseedFilesControllerOutput(
|
|
33
|
+
message="The MiniSEED files have been downloaded succesfully!",
|
|
34
|
+
status=HTTPStatus.OK.value,
|
|
35
|
+
metadata=res.download_status,
|
|
36
|
+
)
|
|
37
|
+
except ShakesNoContentError as error:
|
|
38
|
+
return GetMiniseedFilesControllerOutput(
|
|
39
|
+
message="No files to upload.",
|
|
40
|
+
status=HTTPStatus.NO_CONTENT.value,
|
|
41
|
+
metadata={"error": error.__str__()},
|
|
42
|
+
)
|
|
43
|
+
except SftpClientError as error:
|
|
44
|
+
return GetMiniseedFilesControllerOutput(
|
|
45
|
+
message="An unexpected error ocurred during SFTP Client connection.",
|
|
46
|
+
status=HTTPStatus.REQUEST_TIMEOUT.value,
|
|
47
|
+
metadata={"error": error.__str__()},
|
|
48
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Dict
|
|
3
|
+
from saviialib.general_types.api.saviia_shakes_api_types import SaviiaShakesConfig
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class GetMiniseedFilesControllerInput:
|
|
8
|
+
raspberry_shakes: Dict[str, str]
|
|
9
|
+
config: SaviiaShakesConfig
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class GetMiniseedFilesControllerOutput:
|
|
14
|
+
status: int
|
|
15
|
+
metadata: Dict
|
|
16
|
+
message: str
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from .types.get_miniseed_files_types import (
|
|
3
|
+
GetMiniseedFilesUseCaseInput,
|
|
4
|
+
GetMiniseedFilesUseCaseOutput,
|
|
5
|
+
)
|
|
6
|
+
from typing import Dict, Any
|
|
7
|
+
from saviialib.libs.sftp_client import (
|
|
8
|
+
SFTPClient,
|
|
9
|
+
SFTPClientInitArgs,
|
|
10
|
+
ListfilesArgs,
|
|
11
|
+
DownloadfilesArgs,
|
|
12
|
+
)
|
|
13
|
+
from saviialib.libs.directory_client import DirectoryClient, DirectoryClientArgs
|
|
14
|
+
from saviialib.general_types.error_types.api.saviia_api_error_types import (
|
|
15
|
+
ShakesNoContentError,
|
|
16
|
+
)
|
|
17
|
+
from saviialib.general_types.error_types.common.common_types import SftpClientError
|
|
18
|
+
from .utils.get_miniseed_files_utils import parse_downloaded_metadata
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class GetMiniseedFilesUseCase:
|
|
22
|
+
def __init__(self, input: GetMiniseedFilesUseCaseInput) -> None:
|
|
23
|
+
self.password = input.password
|
|
24
|
+
self.username = input.username
|
|
25
|
+
self.ssh_key_path = input.ssh_key_path
|
|
26
|
+
self.port = input.port
|
|
27
|
+
self.raspberry_shakes: Dict[str, str] = input.raspberry_shakes
|
|
28
|
+
self.dir_client = DirectoryClient(DirectoryClientArgs("os_client"))
|
|
29
|
+
|
|
30
|
+
def _initialize_sftp_client(self, ip_address: str):
|
|
31
|
+
return SFTPClient(
|
|
32
|
+
SFTPClientInitArgs(
|
|
33
|
+
"asyncssh_sftp",
|
|
34
|
+
password=self.password,
|
|
35
|
+
username=self.username,
|
|
36
|
+
ssh_key_path=self.ssh_key_path,
|
|
37
|
+
host=ip_address,
|
|
38
|
+
port=self.port,
|
|
39
|
+
)
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
async def _download_mseed_file(self, rs_name: str, rs_ip: str) -> Dict[str, Any]:
|
|
43
|
+
DEST_BASE_DIR = "./rshakes-mseed-files"
|
|
44
|
+
SOURCE_PATH = self.dir_client.join_paths("opt", "data", "archive")
|
|
45
|
+
local_path = self.dir_client.join_paths(DEST_BASE_DIR, rs_name)
|
|
46
|
+
if not await self.dir_client.isdir(local_path):
|
|
47
|
+
await self.dir_client.makedirs(local_path)
|
|
48
|
+
sftp_client = self._initialize_sftp_client(rs_ip)
|
|
49
|
+
|
|
50
|
+
local_files = await self.dir_client.listdir(local_path)
|
|
51
|
+
try:
|
|
52
|
+
sftp_files = await sftp_client.list_files(ListfilesArgs(path=SOURCE_PATH))
|
|
53
|
+
pending_files = set(sftp_files) - set(local_files)
|
|
54
|
+
if not pending_files:
|
|
55
|
+
raise ShakesNoContentError
|
|
56
|
+
|
|
57
|
+
await sftp_client.download_files(
|
|
58
|
+
DownloadfilesArgs(
|
|
59
|
+
source_path=SOURCE_PATH,
|
|
60
|
+
destination_path=local_path,
|
|
61
|
+
files_to_download=list(pending_files),
|
|
62
|
+
)
|
|
63
|
+
)
|
|
64
|
+
except ConnectionError as error:
|
|
65
|
+
raise SftpClientError(reason=error)
|
|
66
|
+
return {
|
|
67
|
+
"rs_name": rs_name,
|
|
68
|
+
"destination_path": local_path,
|
|
69
|
+
"total_files": len(pending_files),
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async def execute(self):
|
|
73
|
+
requests = []
|
|
74
|
+
for rs_name, rs_ip in self.raspberry_shakes:
|
|
75
|
+
requests.append(self._download_mseed_file(rs_name, rs_ip))
|
|
76
|
+
responses = await asyncio.gather(*requests, return_exceptions=True)
|
|
77
|
+
return GetMiniseedFilesUseCaseOutput(
|
|
78
|
+
download_status=parse_downloaded_metadata(responses),
|
|
79
|
+
)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Dict
|
|
3
|
+
from logging import Logger
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class GetMiniseedFilesUseCaseInput:
|
|
8
|
+
raspberry_shakes: Dict[str, str]
|
|
9
|
+
username: str
|
|
10
|
+
password: str
|
|
11
|
+
ssh_key_path: str
|
|
12
|
+
port: int
|
|
13
|
+
logger: Logger
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class GetMiniseedFilesUseCaseOutput:
|
|
18
|
+
download_status: Dict[str, str] = field(default_factory=dict)
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from typing import Any, Dict, List
|
|
2
|
+
|
|
3
|
+
from .controllers.types.update_thies_data_types import UpdateThiesDataControllerInput
|
|
4
|
+
from .controllers.update_thies_data import UpdateThiesDataController
|
|
5
|
+
from saviialib.general_types.api.saviia_thies_api_types import (
|
|
6
|
+
SaviiaThiesConfig,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SaviiaThiesAPI:
|
|
11
|
+
def __init__(self, config: SaviiaThiesConfig) -> None:
|
|
12
|
+
self.config = config
|
|
13
|
+
|
|
14
|
+
async def update_thies_data(
|
|
15
|
+
self, sharepoint_folders_path: List[str], ftp_server_folders_path: List[str]
|
|
16
|
+
) -> Dict[str, Any]:
|
|
17
|
+
"""Updates data from a THIES Data Logger by connecting to an FTP server
|
|
18
|
+
and transferring data to specified Sharepoint folders.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
sharepoint_folders_path (list): List of Sharepoint folder paths for AVG and EXT data.
|
|
22
|
+
The AVG path must be the first element.
|
|
23
|
+
ftp_server_folders_path (list): List of FTP server folder paths for AVG and EXT data.
|
|
24
|
+
The AVG path must be the first element.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
dict: A dictionary representation of the API response.
|
|
28
|
+
"""
|
|
29
|
+
controller = UpdateThiesDataController(
|
|
30
|
+
UpdateThiesDataControllerInput(
|
|
31
|
+
self.config, sharepoint_folders_path, ftp_server_folders_path
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
response = await controller.execute()
|
|
35
|
+
return response.__dict__
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
2
|
from typing import Dict
|
|
3
|
-
from saviialib.general_types.api.
|
|
4
|
-
EpiiUpdateThiesConfig,
|
|
5
|
-
)
|
|
3
|
+
from saviialib.general_types.api.saviia_thies_api_types import SaviiaThiesConfig
|
|
6
4
|
|
|
7
5
|
|
|
8
6
|
@dataclass
|
|
9
7
|
class UpdateThiesDataControllerInput:
|
|
10
|
-
config:
|
|
8
|
+
config: SaviiaThiesConfig
|
|
11
9
|
sharepoint_folders_path: list
|
|
12
10
|
ftp_server_folders_path: list
|
|
13
11
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from http import HTTPStatus
|
|
2
2
|
|
|
3
|
-
from saviialib.general_types.error_types.api.
|
|
3
|
+
from saviialib.general_types.error_types.api.saviia_api_error_types import (
|
|
4
4
|
SharePointFetchingError,
|
|
5
5
|
ThiesConnectionError,
|
|
6
6
|
ThiesFetchingError,
|
|
@@ -12,16 +12,16 @@ from saviialib.general_types.error_types.common.common_types import (
|
|
|
12
12
|
FtpClientError,
|
|
13
13
|
SharepointClientError,
|
|
14
14
|
)
|
|
15
|
-
from saviialib.services.
|
|
15
|
+
from saviialib.services.thies.controllers.types.update_thies_data_types import (
|
|
16
16
|
UpdateThiesDataControllerInput,
|
|
17
17
|
UpdateThiesDataControllerOutput,
|
|
18
18
|
)
|
|
19
|
-
from saviialib.services.
|
|
19
|
+
from saviialib.services.backup.use_cases.types import (
|
|
20
20
|
UpdateThiesDataUseCaseInput,
|
|
21
21
|
SharepointConfig,
|
|
22
22
|
FtpClientConfig,
|
|
23
23
|
)
|
|
24
|
-
from saviialib.services.
|
|
24
|
+
from saviialib.services.thies.use_cases.update_thies_data import (
|
|
25
25
|
UpdateThiesDataUseCase,
|
|
26
26
|
)
|
|
27
27
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from .thies_bp import THIESDayData
|
|
2
|
-
from typing import List
|
|
3
2
|
from logging import Logger
|
|
4
3
|
from asyncio import to_thread
|
|
5
4
|
from saviialib.libs.directory_client import DirectoryClient
|
|
@@ -70,7 +69,7 @@ UNITS = {
|
|
|
70
69
|
|
|
71
70
|
|
|
72
71
|
async def create_thies_daily_statistics_file(
|
|
73
|
-
os_client: DirectoryClient, logger: Logger
|
|
72
|
+
os_client: DirectoryClient, logger: Logger
|
|
74
73
|
) -> None:
|
|
75
74
|
logger.debug("[thies_synchronization_lib] Creating Daily Statistics ...")
|
|
76
75
|
csv_client = FilesClient(FilesClientInitArgs(client_name="csv_client"))
|
|
@@ -127,6 +126,16 @@ async def create_thies_daily_statistics_file(
|
|
|
127
126
|
if max_col not in row:
|
|
128
127
|
max_val = 0
|
|
129
128
|
|
|
129
|
+
if (mean < min_val or mean > max_val) and col not in ["WD"]:
|
|
130
|
+
logger.warning(
|
|
131
|
+
f"[thies_synchronization_lib] Inconsistent data for {col}: "
|
|
132
|
+
f"min {min_val}, max {max_val}, mean {mean}. "
|
|
133
|
+
)
|
|
134
|
+
mean = (min_val + max_val) / 2
|
|
135
|
+
logger.warning(
|
|
136
|
+
f"[thies_synchronization_lib] Mean value corrected to {mean}."
|
|
137
|
+
)
|
|
138
|
+
|
|
130
139
|
if col in ["WD"]: # Avoid error
|
|
131
140
|
rows.append(
|
|
132
141
|
{
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
2
|
from typing import Dict, List
|
|
3
|
-
from saviialib.general_types.api.
|
|
3
|
+
from saviialib.general_types.api.saviia_api_types import (
|
|
4
|
+
FtpClientConfig,
|
|
5
|
+
SharepointConfig,
|
|
6
|
+
)
|
|
4
7
|
from logging import Logger
|
|
5
8
|
|
|
6
9
|
|