nexus-hostinger 1.0.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.
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SDK Oficial da NEXUS HOSTINGER para Python.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .client import NexusClient
|
|
6
|
+
from .exceptions import (
|
|
7
|
+
NexusApiError,
|
|
8
|
+
NexusAuthError,
|
|
9
|
+
NexusRateLimitError,
|
|
10
|
+
NexusNotFoundError,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__version__ = "1.0.0"
|
|
14
|
+
__all__ = [
|
|
15
|
+
"NexusClient",
|
|
16
|
+
"NexusApiError",
|
|
17
|
+
"NexusAuthError",
|
|
18
|
+
"NexusRateLimitError",
|
|
19
|
+
"NexusNotFoundError",
|
|
20
|
+
]
|
nexus_hosting/client.py
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cliente oficial síncrono para a API da NEXUS HOSTINGER em Python.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Dict, Any, Optional, List
|
|
6
|
+
import requests
|
|
7
|
+
from .exceptions import (
|
|
8
|
+
NexusApiError,
|
|
9
|
+
NexusAuthError,
|
|
10
|
+
NexusRateLimitError,
|
|
11
|
+
NexusNotFoundError,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
class _AccountResource:
|
|
15
|
+
def __init__(self, client: "NexusClient"):
|
|
16
|
+
self._client = client
|
|
17
|
+
|
|
18
|
+
def get_resources(self) -> Dict[str, Any]:
|
|
19
|
+
"""Consulta cota total de vCPU, memória RAM e instâncias contratadas vs utilizadas."""
|
|
20
|
+
return self._client._request("GET", "/account/resources")
|
|
21
|
+
|
|
22
|
+
class _FilesResource:
|
|
23
|
+
def __init__(self, client: "NexusClient"):
|
|
24
|
+
self._client = client
|
|
25
|
+
|
|
26
|
+
def list(self, bot_id: str) -> List[Dict[str, Any]]:
|
|
27
|
+
"""Lista todos os arquivos e diretórios da aplicação."""
|
|
28
|
+
res = self._client._request("GET", f"/bots/{bot_id}/files")
|
|
29
|
+
return res.get("data", [])
|
|
30
|
+
|
|
31
|
+
def read(self, bot_id: str, path: str) -> Dict[str, Any]:
|
|
32
|
+
"""Lê o conteúdo em texto de um arquivo específico."""
|
|
33
|
+
res = self._client._request("GET", f"/bots/{bot_id}/files/content", params={"path": path})
|
|
34
|
+
return res.get("data", {})
|
|
35
|
+
|
|
36
|
+
def save(self, bot_id: str, path: str, content: str) -> Dict[str, Any]:
|
|
37
|
+
"""Salva ou atualiza um arquivo no contêiner da aplicação."""
|
|
38
|
+
return self._client._request("PUT", f"/bots/{bot_id}/files", json={"path": path, "content": content})
|
|
39
|
+
|
|
40
|
+
def delete(self, bot_id: str, path: str) -> Dict[str, Any]:
|
|
41
|
+
"""Exclui um arquivo da aplicação."""
|
|
42
|
+
return self._client._request("DELETE", f"/bots/{bot_id}/files", params={"path": path})
|
|
43
|
+
|
|
44
|
+
class _BotsResource:
|
|
45
|
+
def __init__(self, client: "NexusClient"):
|
|
46
|
+
self._client = client
|
|
47
|
+
self.files = _FilesResource(client)
|
|
48
|
+
|
|
49
|
+
def list(self) -> List[Dict[str, Any]]:
|
|
50
|
+
"""Lista todos os bots/servidores do workspace."""
|
|
51
|
+
res = self._client._request("GET", "/bots")
|
|
52
|
+
return res.get("data", [])
|
|
53
|
+
|
|
54
|
+
def get(self, bot_id: str) -> Dict[str, Any]:
|
|
55
|
+
"""Retorna detalhes de configuração e status de um bot."""
|
|
56
|
+
res = self._client._request("GET", f"/bots/{bot_id}")
|
|
57
|
+
return res.get("data", {})
|
|
58
|
+
|
|
59
|
+
def create(
|
|
60
|
+
self,
|
|
61
|
+
name: str,
|
|
62
|
+
runtime: str = "NODEJS_20",
|
|
63
|
+
entrypoint: Optional[str] = None,
|
|
64
|
+
memory_limit_mb: int = 256,
|
|
65
|
+
cpu_limit: float = 0.25,
|
|
66
|
+
app_type: str = "BOT",
|
|
67
|
+
subdomain: Optional[str] = None,
|
|
68
|
+
) -> Dict[str, Any]:
|
|
69
|
+
"""Provisiona um novo bot consumindo os recursos do plano."""
|
|
70
|
+
body = {
|
|
71
|
+
"name": name,
|
|
72
|
+
"runtime": runtime,
|
|
73
|
+
"entrypoint": entrypoint,
|
|
74
|
+
"memoryLimitMb": memory_limit_mb,
|
|
75
|
+
"cpuLimit": cpu_limit,
|
|
76
|
+
"appType": app_type,
|
|
77
|
+
"subdomain": subdomain,
|
|
78
|
+
}
|
|
79
|
+
return self._client._request("POST", "/bots", json=body)
|
|
80
|
+
|
|
81
|
+
def update(
|
|
82
|
+
self,
|
|
83
|
+
bot_id: str,
|
|
84
|
+
name: Optional[str] = None,
|
|
85
|
+
entrypoint: Optional[str] = None,
|
|
86
|
+
cpu_limit: Optional[float] = None,
|
|
87
|
+
memory_limit_mb: Optional[int] = None,
|
|
88
|
+
) -> Dict[str, Any]:
|
|
89
|
+
"""Atualiza configurações de um bot existente."""
|
|
90
|
+
body = {}
|
|
91
|
+
if name is not None:
|
|
92
|
+
body["name"] = name
|
|
93
|
+
if entrypoint is not None:
|
|
94
|
+
body["entrypoint"] = entrypoint
|
|
95
|
+
if cpu_limit is not None:
|
|
96
|
+
body["cpuLimit"] = cpu_limit
|
|
97
|
+
if memory_limit_mb is not None:
|
|
98
|
+
body["memoryLimitMb"] = memory_limit_mb
|
|
99
|
+
return self._client._request("PATCH", f"/bots/{bot_id}", json=body)
|
|
100
|
+
|
|
101
|
+
def delete(self, bot_id: str) -> Dict[str, Any]:
|
|
102
|
+
"""Exclui permanentemente o bot e libera os recursos no plano."""
|
|
103
|
+
return self._client._request("DELETE", f"/bots/{bot_id}")
|
|
104
|
+
|
|
105
|
+
def start(self, bot_id: str) -> Dict[str, Any]:
|
|
106
|
+
"""Inicia o contêiner do bot."""
|
|
107
|
+
return self._client._request("POST", f"/bots/{bot_id}/start")
|
|
108
|
+
|
|
109
|
+
def stop(self, bot_id: str) -> Dict[str, Any]:
|
|
110
|
+
"""Desliga o contêiner do bot."""
|
|
111
|
+
return self._client._request("POST", f"/bots/{bot_id}/stop")
|
|
112
|
+
|
|
113
|
+
def restart(self, bot_id: str) -> Dict[str, Any]:
|
|
114
|
+
"""Reinicia o contêiner do bot."""
|
|
115
|
+
return self._client._request("POST", f"/bots/{bot_id}/restart")
|
|
116
|
+
|
|
117
|
+
def stats(self, bot_id: str) -> Dict[str, Any]:
|
|
118
|
+
"""Consulta métricas de hardware (CPU, RAM, rede) em tempo real."""
|
|
119
|
+
res = self._client._request("GET", f"/bots/{bot_id}/stats")
|
|
120
|
+
return res.get("data", {})
|
|
121
|
+
|
|
122
|
+
def logs(self, bot_id: str, lines: int = 100) -> List[str]:
|
|
123
|
+
"""Retorna as últimas linhas de log do console."""
|
|
124
|
+
res = self._client._request("GET", f"/bots/{bot_id}/logs", params={"lines": lines})
|
|
125
|
+
return res.get("data", {}).get("logs", [])
|
|
126
|
+
|
|
127
|
+
def exec(self, bot_id: str, command: str) -> Dict[str, Any]:
|
|
128
|
+
"""Executa um comando shell de forma segura no contêiner isolado."""
|
|
129
|
+
res = self._client._request("POST", f"/bots/{bot_id}/exec", json={"command": command})
|
|
130
|
+
return res.get("data", {})
|
|
131
|
+
|
|
132
|
+
def get_env(self, bot_id: str) -> List[Dict[str, Any]]:
|
|
133
|
+
"""Lista variáveis de ambiente cadastradas."""
|
|
134
|
+
res = self._client._request("GET", f"/bots/{bot_id}/env")
|
|
135
|
+
return res.get("data", [])
|
|
136
|
+
|
|
137
|
+
def set_env(self, bot_id: str, variables: Dict[str, str]) -> Dict[str, Any]:
|
|
138
|
+
"""Injeta ou atualiza variáveis de ambiente em lote."""
|
|
139
|
+
return self._client._request("POST", f"/bots/{bot_id}/env", json={"variables": variables})
|
|
140
|
+
|
|
141
|
+
def delete_env(self, bot_id: str, key: str) -> Dict[str, Any]:
|
|
142
|
+
"""Remove uma variável de ambiente específica."""
|
|
143
|
+
return self._client._request("DELETE", f"/bots/{bot_id}/env/{key}")
|
|
144
|
+
|
|
145
|
+
def list_backups(self, bot_id: str) -> List[Dict[str, Any]]:
|
|
146
|
+
"""Lista backups da aplicação."""
|
|
147
|
+
res = self._client._request("GET", f"/bots/{bot_id}/backups")
|
|
148
|
+
return res.get("data", [])
|
|
149
|
+
|
|
150
|
+
def create_backup(self, bot_id: str, name: Optional[str] = None) -> Dict[str, Any]:
|
|
151
|
+
"""Cria um backup dos arquivos sob demanda."""
|
|
152
|
+
return self._client._request("POST", f"/bots/{bot_id}/backups", json={"name": name} if name else {})
|
|
153
|
+
|
|
154
|
+
class NexusClient:
|
|
155
|
+
"""Cliente oficial para integração com a API da NEXUS HOSTINGER."""
|
|
156
|
+
def __init__(
|
|
157
|
+
self,
|
|
158
|
+
api_key: str,
|
|
159
|
+
base_url: str = "https://nexushost.cloud/api/v1",
|
|
160
|
+
timeout: int = 15,
|
|
161
|
+
):
|
|
162
|
+
if not api_key:
|
|
163
|
+
raise ValueError("api_key é obrigatória para inicializar o NexusClient.")
|
|
164
|
+
self.api_key = api_key
|
|
165
|
+
self.base_url = base_url.rstrip("/")
|
|
166
|
+
self.timeout = timeout
|
|
167
|
+
self.session = requests.Session()
|
|
168
|
+
self.session.headers.update({
|
|
169
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
170
|
+
"User-Agent": "NexusHosting-PythonSDK/1.0.0",
|
|
171
|
+
"Content-Type": "application/json",
|
|
172
|
+
"Accept": "application/json",
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
self.account = _AccountResource(self)
|
|
176
|
+
self.bots = _BotsResource(self)
|
|
177
|
+
|
|
178
|
+
def _request(
|
|
179
|
+
self,
|
|
180
|
+
method: str,
|
|
181
|
+
path: str,
|
|
182
|
+
params: Optional[Dict[str, Any]] = None,
|
|
183
|
+
json: Optional[Dict[str, Any]] = None,
|
|
184
|
+
) -> Dict[str, Any]:
|
|
185
|
+
url = f"{self.base_url}{path}"
|
|
186
|
+
try:
|
|
187
|
+
res = self.session.request(
|
|
188
|
+
method=method,
|
|
189
|
+
url=url,
|
|
190
|
+
params=params,
|
|
191
|
+
json=json,
|
|
192
|
+
timeout=self.timeout,
|
|
193
|
+
)
|
|
194
|
+
except requests.RequestException as e:
|
|
195
|
+
raise NexusApiError(f"Falha de conexão com a API NEXUS: {str(e)}")
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
data = res.json()
|
|
199
|
+
except ValueError:
|
|
200
|
+
data = {"raw": res.text}
|
|
201
|
+
|
|
202
|
+
if not res.ok:
|
|
203
|
+
msg = data.get("message") or f"Erro na requisição para {url} (HTTP {res.status_code})"
|
|
204
|
+
if res.status_code in (401, 403):
|
|
205
|
+
raise NexusAuthError(msg, res.status_code, data)
|
|
206
|
+
if res.status_code == 429:
|
|
207
|
+
raise NexusRateLimitError(msg, res.status_code, data)
|
|
208
|
+
if res.status_code == 404:
|
|
209
|
+
raise NexusNotFoundError(msg, res.status_code, data)
|
|
210
|
+
raise NexusApiError(msg, res.status_code, data)
|
|
211
|
+
|
|
212
|
+
return data
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Exceções customizadas do SDK NEXUS HOSTINGER.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
class NexusApiError(Exception):
|
|
6
|
+
"""Exceção base lançada em erros de requisição ou retorno HTTP da API NEXUS."""
|
|
7
|
+
def __init__(self, message: str, status_code: int = 0, response_body: dict = None):
|
|
8
|
+
super().__init__(message)
|
|
9
|
+
self.message = message
|
|
10
|
+
self.status_code = status_code
|
|
11
|
+
self.response_body = response_body or {}
|
|
12
|
+
|
|
13
|
+
def __str__(self):
|
|
14
|
+
if self.status_code:
|
|
15
|
+
return f"[HTTP {self.status_code}] {self.message}"
|
|
16
|
+
return self.message
|
|
17
|
+
|
|
18
|
+
class NexusAuthError(NexusApiError):
|
|
19
|
+
"""Lançada quando a API Key é inválida, revogada ou expirou."""
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
class NexusRateLimitError(NexusApiError):
|
|
23
|
+
"""Lançada quando a cota de requisições por minuto do plano foi atingida."""
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
class NexusNotFoundError(NexusApiError):
|
|
27
|
+
"""Lançada quando o recurso (bot, arquivo, backup) não foi localizado."""
|
|
28
|
+
pass
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nexus-hostinger
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: SDK Oficial em Python para automação e integração com a API da NEXUS HOSTINGER
|
|
5
|
+
Author-email: NEXUS HOSTINGER <suporte@nexushost.cloud>
|
|
6
|
+
Project-URL: Homepage, https://nexushost.cloud
|
|
7
|
+
Project-URL: Documentation, https://nexushost.cloud/docs
|
|
8
|
+
Project-URL: Discord, https://discord.gg/9F99uS7UWe
|
|
9
|
+
Keywords: nexus,discord,hosting,cloud,bots,sdk
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Requires-Python: >=3.8
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: requests>=2.28.0
|
|
17
|
+
Requires-Dist: urllib3>=1.26.0
|
|
18
|
+
Provides-Extra: async
|
|
19
|
+
Requires-Dist: httpx>=0.24.0; extra == "async"
|
|
20
|
+
|
|
21
|
+
# ⚡ NEXUS HOSTINGER — Python SDK
|
|
22
|
+
|
|
23
|
+
SDK Oficial em Python para automação, monitoramento e gerenciamento de aplicações na plataforma [NEXUS HOSTINGER](https://nexushost.cloud).
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 📦 Instalação
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install nexus-hostinger
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 🚀 Como Usar
|
|
36
|
+
|
|
37
|
+
### 1. Inicializando o Cliente
|
|
38
|
+
|
|
39
|
+
Gere sua Chave de API no painel em **Desenvolvedor > Chaves de API**:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from nexus_hosting import NexusClient
|
|
43
|
+
|
|
44
|
+
nexus = NexusClient(api_key="nexus_live_sua_chave_aqui")
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
### 2. Exemplos Práticos
|
|
50
|
+
|
|
51
|
+
#### 📊 Consultar Recursos do Workspace
|
|
52
|
+
```python
|
|
53
|
+
resources = nexus.account.get_resources()
|
|
54
|
+
print(resources["data"]["resources"])
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
#### 🤖 Gerenciar Bots
|
|
58
|
+
```python
|
|
59
|
+
# Listar todos os bots
|
|
60
|
+
bots = nexus.bots.list()
|
|
61
|
+
for bot in bots:
|
|
62
|
+
print(f"[{bot['status']}] {bot['name']} (ID: {bot['id']})")
|
|
63
|
+
|
|
64
|
+
# Iniciar, desligar ou reiniciar
|
|
65
|
+
nexus.bots.restart("id-do-bot")
|
|
66
|
+
|
|
67
|
+
# Inspecionar estatísticas em tempo real
|
|
68
|
+
stats = nexus.bots.stats("id-do-bot")
|
|
69
|
+
print(f"Uso de RAM: {stats.get('memoryUsageMb', 0)}MB")
|
|
70
|
+
|
|
71
|
+
# Consultar logs do console
|
|
72
|
+
logs = nexus.bots.logs("id-do-bot", lines=50)
|
|
73
|
+
for line in logs:
|
|
74
|
+
print(line)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
#### ⚡ Execução de Comandos Shell no Contêiner
|
|
78
|
+
```python
|
|
79
|
+
res = nexus.bots.exec("id-do-bot", "pip list")
|
|
80
|
+
print(res["output"])
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
#### 📁 Manipulação de Arquivos (REST Files API)
|
|
84
|
+
```python
|
|
85
|
+
# Listar arquivos
|
|
86
|
+
files = nexus.bots.files.list("id-do-bot")
|
|
87
|
+
|
|
88
|
+
# Ler arquivo
|
|
89
|
+
config = nexus.bots.files.read("id-do-bot", "config.json")
|
|
90
|
+
print(config["content"])
|
|
91
|
+
|
|
92
|
+
# Salvar ou atualizar arquivo
|
|
93
|
+
nexus.bots.files.save("id-do-bot", "config.json", '{"prefix": "!"}')
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 🛡️ Tratamento de Erros
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from nexus_hosting import NexusClient, NexusAuthError, NexusRateLimitError, NexusApiError
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
nexus = NexusClient(api_key="chave_invalida")
|
|
105
|
+
bots = nexus.bots.list()
|
|
106
|
+
except NexusAuthError:
|
|
107
|
+
print("Chave de API inválida ou expirada!")
|
|
108
|
+
except NexusRateLimitError:
|
|
109
|
+
print("Limite de requisições por minuto atingido. Aguarde alguns instantes.")
|
|
110
|
+
except NexusApiError as e:
|
|
111
|
+
print(f"Erro na API NEXUS: {e}")
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 🌐 Links Oficiais
|
|
117
|
+
* **Painel:** https://nexushost.cloud
|
|
118
|
+
* **Documentação:** https://nexushost.cloud/docs
|
|
119
|
+
* **Comunidade Discord:** https://discord.gg/9F99uS7UWe
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
nexus_hosting/__init__.py,sha256=CwPpXo30UXbnFxM1AqTTK4M-oI_SFcSmt-6SrP9DY7Y,353
|
|
2
|
+
nexus_hosting/client.py,sha256=ityc_geXVR3kNbxNq58Jje9l9WNB5QtLQDBmGeVHLPw,8251
|
|
3
|
+
nexus_hosting/exceptions.py,sha256=H9JcrfZRYeEMTWf_4oxrQi8xDR9RtMRRAsZipGjgvKU,948
|
|
4
|
+
nexus_hostinger-1.0.0.dist-info/METADATA,sha256=flwBl9Zdshr55eunq4Pp9PhqX6fBFn2XrcYIJP4VTVM,3194
|
|
5
|
+
nexus_hostinger-1.0.0.dist-info/WHEEL,sha256=a-udL2m4V_6Yn8b-uKzWb12RjRxwwMo6ohYFM24tpaY,91
|
|
6
|
+
nexus_hostinger-1.0.0.dist-info/top_level.txt,sha256=WUzcrP-AEBbQ50XIvE2RBUlz9D9wKUJN_mhfi25WXvI,14
|
|
7
|
+
nexus_hostinger-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nexus_hosting
|