mirror of
https://github.com/status-im/status-python-sdk.git
synced 2026-08-30 21:51:14 +00:00
PyPI: Selectable Backup folder
- Backup folder can be manually selected on local machine - Related to https://github.com/status-im/status-python-sdk/issues/2
This commit is contained in:
+30
-7
@@ -1,5 +1,5 @@
|
||||
from typing import Optional, Union, Generator, Any
|
||||
import requests, datetime, re, logging, os, json, ast, shutil, eth_abi
|
||||
import requests, datetime, re, logging, os, json, ast, shutil, eth_abi, shutil
|
||||
import pandas as pd
|
||||
from PIL import Image
|
||||
from PIL.JpegImagePlugin import JpegImageFile
|
||||
@@ -29,7 +29,7 @@ class Account:
|
||||
"transfer": "a9059cbb" # keccak256("transfer(address,uint256)")[:4]
|
||||
}
|
||||
|
||||
def __init__(self, domain: str = "localhost", port: int = 8080, is_secure: bool = False):
|
||||
def __init__(self, domain: str = "localhost", port: int = 8080, is_secure: bool = False, backup_folder: Optional[str] = None):
|
||||
"""
|
||||
Work with your own Status App account
|
||||
|
||||
@@ -37,15 +37,18 @@ class Account:
|
||||
- `domain` - the domain name where Status Backend is running. If running locally it would be `localhost` and if it's running in a container it would be the image's name.
|
||||
- `port` - the port to connect to Status Backend. Verify the port in the Docker files.
|
||||
- `is_secure` - if `http` or `https` should be used
|
||||
- `backup_folder` - where backup files will be created and stored
|
||||
"""
|
||||
# Path of the account data in the Docker container for Status Backend
|
||||
self.__docker_data_folder = "./data-dir"
|
||||
# Path of the backups in the Docker container for Status Backend
|
||||
self.__docker_backup_folder = "./root/.config/Status/backups"
|
||||
self.__backup_folder = backup_folder
|
||||
# As the docker-compose.yaml folder is at the moment
|
||||
# NOTE: This might change for initial release
|
||||
self.__backup_local_folder = os.path.join(os.path.dirname(os.path.dirname(__file__)), "backups")
|
||||
os.makedirs(self.__backup_local_folder, exist_ok=True)
|
||||
self.__backup_sdk_folder = os.path.join(os.path.dirname(os.path.dirname(__file__)), "backups")
|
||||
os.makedirs(self.__backup_sdk_folder, exist_ok=True)
|
||||
|
||||
# Path of where images will be uploaded to Status Backend
|
||||
self.__docker_asset_folder = "./assets"
|
||||
# As the docker-compose.yaml folder is at the moment
|
||||
@@ -798,7 +801,7 @@ class Account:
|
||||
Create a `.bkp` (Backup) for the account. If the backup was not successful, a custom exception will be raised.
|
||||
|
||||
Output:
|
||||
- the Docker backup path (linked to a volume). The file name is unique per account.
|
||||
- the file path of the backup. The name is unique per account.
|
||||
"""
|
||||
self.info
|
||||
response = requests.post(self.__urls["http"]["create_backup"])
|
||||
@@ -808,6 +811,13 @@ class Account:
|
||||
if not file_path or (isinstance(file_path, str) and len(file_path) == 0):
|
||||
raise Exception(f"There was an error with creating a backup for {self.info['display_name']}")
|
||||
|
||||
file_name = os.path.basename(file_path)
|
||||
sdk_file_path = os.path.join(self.__backup_sdk_folder, file_name)
|
||||
file_path = sdk_file_path
|
||||
if self.__backup_folder:
|
||||
file_path = os.path.join(self.__backup_folder, file_name)
|
||||
shutil.move(sdk_file_path, file_path)
|
||||
|
||||
return file_path
|
||||
|
||||
def get_tokens(self) -> pd.DataFrame:
|
||||
@@ -1096,13 +1106,26 @@ class Account:
|
||||
Try to load every file in the Docker volume
|
||||
when an account recover is done.
|
||||
"""
|
||||
for file_name in os.listdir(self.__backup_local_folder):
|
||||
folder = self.__backup_folder if self.__backup_folder else self.__backup_sdk_folder
|
||||
for file_name in os.listdir(folder):
|
||||
if not file_name.endswith(".bkp"):
|
||||
continue
|
||||
|
||||
file_path = os.path.join(folder, file_name)
|
||||
sdk_file_path = os.path.join(self.__backup_sdk_folder, file_name)
|
||||
if sdk_file_path != file_path:
|
||||
shutil.copy(file_path, sdk_file_path)
|
||||
|
||||
params = {
|
||||
"filePath": os.path.join(self.__docker_backup_folder, file_name).replace("\\", "/")
|
||||
}
|
||||
self.logger.info(f"Trying to load {file_name}")
|
||||
self.logger.info(f"Trying to load {file_path}")
|
||||
response = requests.post(self.__urls["http"]["load_backup"], json=params)
|
||||
error: str = response.json().get("error", "")
|
||||
|
||||
if sdk_file_path != file_path:
|
||||
os.remove(sdk_file_path)
|
||||
|
||||
if len(error) == 0:
|
||||
self.__signal.get("messages.new")
|
||||
self.logger.info(f"Successfully loaded file!")
|
||||
|
||||
+49
-5
@@ -62,6 +62,50 @@ Wallet features are optional and can be omitted if not required for your use cas
|
||||
|
||||

|
||||
|
||||
## `Account(domain="localhost", port=8080, is_secure=False, backup_folder=None)`
|
||||
|
||||
Create a new `Account` instance ready to be logged in. The constructor wires the SDK to a running [Status Backend](https://github.com/status-im/status-go) at the given `domain` and `port`, prepares the local `assets/` folder (used for image uploads, such as the [profile picture](./account.md#profile_picture)) and `backups/` folder (used for [backup uploads](./account.md#backups) and recovery).
|
||||
|
||||
| Name | Type | Required | Description |
|
||||
|-----|-----|-----|-------------|
|
||||
| `domain` | `str` | No | Domain where Status Backend is reachable. Defaults to `localhost` when running through [`launch_docker_container`](./utils.md#launch_docker_container) on the same machine. **Use the container name when the SDK runs inside the same Docker network as Status Backend.** |
|
||||
| `port` | `int` | No | Port exposed by Status Backend. Defaults to `8080`. Verify the value in `docker-compose.yaml` if you have customized the setup. |
|
||||
| `is_secure` | `bool` | No | When `True`, the SDK communicates over `https`; otherwise `http` is used. Defaults to `False`. |
|
||||
| `backup_folder` | `str` | No | Absolute path on the host machine where `.bkp` files will be stored and loaded from. If not provided, the SDK's own `backups/` folder is used. See [Backups](./account.md#backups). |
|
||||
|
||||
The constructor does not log into any account on its own - call [`login`](./account.md#loginpassword-key_uidnone-display_namenone-mnemonicnone-infura_tokennonecoingecko_api_keynone) afterwards. To discover what accounts already exist in the configured data directory, use the [`available_accounts`](./account.md#available_accounts) property, which is also populated automatically during initialization.
|
||||
|
||||
Default setup (localhost, port 8080, http):
|
||||
|
||||
```python
|
||||
from bot import Account
|
||||
|
||||
account = Account()
|
||||
```
|
||||
|
||||
Use a custom backup folder:
|
||||
|
||||
```python
|
||||
from bot import Account
|
||||
|
||||
account = Account(backup_folder="C:/Users/me/status-backups")
|
||||
```
|
||||
|
||||
Connect to a Status Backend running on a different host or port:
|
||||
|
||||
```python
|
||||
from bot import Account
|
||||
|
||||
account = Account(
|
||||
domain="status-backend.internal",
|
||||
port=9090,
|
||||
is_secure=True
|
||||
)
|
||||
```
|
||||
|
||||
**Note**: Status Backend must be running before initializing `Account`. You can launch the backend container with [`launch_docker_container`](./utils.md#launch_docker_container). If the backend is not reachable on `domain:port`, calls to [`login`](./account.md#loginpassword-key_uidnone-display_namenone-mnemonicnone-infura_tokennonecoingecko_api_keynone) will fail.
|
||||
|
||||
**Note**: When `backup_folder` is set, [`backup`](./account.md#backup) moves the generated `.bkp` file out of the SDK's internal `backups/` folder into the provided path, and recovery via `mnemonic` will look in this same folder for `.bkp` files to auto-load. Make sure the folder exists and is writable.
|
||||
|
||||
## Methods
|
||||
|
||||
@@ -697,7 +741,7 @@ tx_hash = account.send_transaction(
|
||||
|
||||
**Note**: This is a wallet method, so it requires both `infura_token` and `coingecko_api_key` to be provided in [`login`](./account.md#loginpassword-key_uidnone-display_namenone-mnemonicnone-infura_tokennonecoingecko_api_keynone). If either is missing, an exception will be raised when this method is called.
|
||||
|
||||
**Note**: The sender and receiver must be on the **same chain**. Cross-chain transfers are not supported by this method — set `chain_id` to the chain where the funds currently exist.
|
||||
**Note**: The sender and receiver must be on the **same chain**. Cross-chain transfers are not supported by this method - set `chain_id` to the chain where the funds currently exist.
|
||||
|
||||
**Note**: An **exception will be raised** when:
|
||||
- the `symbol` (or contract address) does not exist on the given `chain_id`
|
||||
@@ -908,8 +952,8 @@ The property exists in `Account` because signals require an **active logged‑in
|
||||
|
||||
The property exposes two primary methods:
|
||||
|
||||
- `signal.get()` — fetch a single event. If the event is not found, you may end up in an infinite loop.
|
||||
- `signal.listen()` — stream events continuously. Example usage of this is found in [`listen_messages()`](./account.md#listen_messages)
|
||||
- `signal.get()` - fetch a single event. If the event is not found, you may end up in an infinite loop.
|
||||
- `signal.listen()` - stream events continuously. Example usage of this is found in [`listen_messages()`](./account.md#listen_messages)
|
||||
|
||||
### `logger`
|
||||
|
||||
@@ -1093,8 +1137,8 @@ print(community_members.head().to_markdown(index=False))
|
||||
#### `chats`
|
||||
|
||||
Get all chats that the account can **send messages to**. This includes:
|
||||
- [`contacts`](./account.md#contacts) — direct messages with users
|
||||
- [`communities`](./account.md#communities) — community channels where the account has **posting permission**
|
||||
- [`contacts`](./account.md#contacts) - direct messages with users
|
||||
- [`communities`](./account.md#communities) - community channels where the account has **posting permission**
|
||||
- Group chats that the account is in
|
||||
|
||||
Returns `list[dict]` where each `dict` represents a chat that can be used with [`send_message`](./account.md#send_messagechat_id-message) and [`get_messages`](./account.md#get_messageschat_id-start_timestampnone-end_timestampnone).
|
||||
|
||||
Reference in New Issue
Block a user